diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index fc865be015e..f7bf457f72c 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -1109,11 +1109,11 @@ void InterpreterMacroAssembler::verify_method_data_pointer() { lhz(R11_scratch1, in_bytes(DataLayout::bci_offset()), R28_mdx); ld(R12_scratch2, in_bytes(Method::const_offset()), R19_method); addi(R11_scratch1, R11_scratch1, in_bytes(ConstMethod::codes_offset())); - add(R11_scratch1, R12_scratch2, R12_scratch2); + add(R11_scratch1, R11_scratch1, R12_scratch2); cmpd(CR0, R11_scratch1, R14_bcp); beq(CR0, verify_continue); - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp ), R19_method, R14_bcp, R28_mdx); + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), R19_method, R14_bcp, R28_mdx); bind(verify_continue); #endif diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 5649ead2ea8..809285afddb 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -4535,7 +4535,7 @@ void MacroAssembler::push_cont_fastpath() { Label done; ld_ptr(R0, JavaThread::cont_fastpath_offset(), R16_thread); cmpld(CR0, R1_SP, R0); - ble(CR0, done); + ble(CR0, done); // if (SP <= _cont_fastpath) goto done; st_ptr(R1_SP, JavaThread::cont_fastpath_offset(), R16_thread); bind(done); } @@ -4546,7 +4546,7 @@ void MacroAssembler::pop_cont_fastpath() { Label done; ld_ptr(R0, JavaThread::cont_fastpath_offset(), R16_thread); cmpld(CR0, R1_SP, R0); - ble(CR0, done); + blt(CR0, done); // if (SP < _cont_fastpath) goto done; li(R0, 0); st_ptr(R0, JavaThread::cont_fastpath_offset(), R16_thread); bind(done); diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 22f19c4f5ea..36f0864da0b 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -167,11 +167,6 @@ void VM_Version::common_initialize() { (unaligned_scalar.value() == MISALIGNED_SCALAR_FAST)); } - if (FLAG_IS_DEFAULT(AlignVector)) { - FLAG_SET_DEFAULT(AlignVector, - unaligned_vector.value() != MISALIGNED_VECTOR_FAST); - } - #ifdef __riscv_ztso // Hotspot is compiled with TSO support, it will only run on hardware which // supports Ztso @@ -242,6 +237,11 @@ void VM_Version::c2_initialize() { } } + if (FLAG_IS_DEFAULT(AlignVector)) { + FLAG_SET_DEFAULT(AlignVector, + unaligned_vector.value() != MISALIGNED_VECTOR_FAST); + } + // NOTE: Make sure codes dependent on UseRVV are put after MaxVectorSize initialize, // as there are extra checks inside it which could disable UseRVV // in some situations. diff --git a/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp b/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp index 0951bda0d17..77a149addb5 100644 --- a/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp +++ b/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Intel Corporation. All rights reserved. + * Copyright (c) 2024, 2026, Intel Corporation. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1330,10 +1330,12 @@ static void big_case_loop_helper(bool sizeKnown, int size, Label &noMatch, Label // Clarification: The BYTE_K compare above compares haystack[(n-32):(n-1)]. We need to // compare haystack[(k-1):(k-1+31)]. Subtracting either index gives shift value of // (k + 31 - n): x = (k-1+31)-(n-1) = k-1+31-n+1 = k+31-n. + // When isU is set, similarly, shift is from haystack[(n-32):(n-1)] to [(k-2):(k-2+31)] + if (sizeKnown) { - __ movl(temp2, 31 + size); + __ movl(temp2, (isU ? 30 : 31) + size); } else { - __ movl(temp2, 31); + __ movl(temp2, isU ? 30 : 31); __ addl(temp2, needleLen); } __ subl(temp2, hsLength); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index be7deb884ce..7f7bb2c4c7f 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -6086,7 +6086,7 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, vpbroadcastd(xtmp, xtmp, Assembler::AVX_512bit); subptr(count, 16 << shift); - jccb(Assembler::less, L_check_fill_32_bytes); + jcc(Assembler::less, L_check_fill_32_bytes); align(16); BIND(L_fill_64_bytes_loop_avx3); diff --git a/src/hotspot/cpu/x86/register_x86.cpp b/src/hotspot/cpu/x86/register_x86.cpp index e6083429344..188af9264a8 100644 --- a/src/hotspot/cpu/x86/register_x86.cpp +++ b/src/hotspot/cpu/x86/register_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,14 +32,10 @@ const KRegister::KRegisterImpl all_KRegisterImpls [KRegister::number_ const char * Register::RegisterImpl::name() const { static const char *const names[number_of_registers] = { -#ifdef _LP64 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" -#else - "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" -#endif // _LP64 }; return is_valid() ? names[encoding()] : "noreg"; } @@ -54,11 +50,9 @@ const char* FloatRegister::FloatRegisterImpl::name() const { const char* XMMRegister::XMMRegisterImpl::name() const { static const char *const names[number_of_registers] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" -#ifdef _LP64 ,"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" ,"xmm16", "xmm17", "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23" ,"xmm24", "xmm25", "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31" -#endif // _LP64 }; return is_valid() ? names[encoding()] : "xnoreg"; } diff --git a/src/hotspot/cpu/x86/register_x86.hpp b/src/hotspot/cpu/x86/register_x86.hpp index 0a8ecb7be26..5e0326b9aad 100644 --- a/src/hotspot/cpu/x86/register_x86.hpp +++ b/src/hotspot/cpu/x86/register_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ class VMRegImpl; typedef VMRegImpl* VMReg; -// The implementation of integer registers for the x86/x64 architectures. +// The implementation of integer registers for the x64 architectures. class Register { private: int _encoding; @@ -44,11 +44,9 @@ private: public: inline friend constexpr Register as_Register(int encoding); - enum { - number_of_registers = LP64_ONLY( 32 ) NOT_LP64( 8 ), - number_of_byte_registers = LP64_ONLY( 32 ) NOT_LP64( 4 ), - max_slots_per_register = LP64_ONLY( 2 ) NOT_LP64( 1 ) - }; + static const int number_of_registers = 32; + static const int number_of_byte_registers = 32; + static const int max_slots_per_register = 2; class RegisterImpl: public AbstractRegisterImpl { friend class Register; @@ -79,11 +77,9 @@ public: // Actually available GP registers for use, depending on actual CPU capabilities and flags. static int available_gp_registers() { -#ifdef _LP64 if (!UseAPX) { return number_of_registers / 2; } -#endif // _LP64 return number_of_registers; } }; @@ -116,9 +112,8 @@ constexpr Register rsp = as_Register(4); constexpr Register rbp = as_Register(5); constexpr Register rsi = as_Register(6); constexpr Register rdi = as_Register(7); -#ifdef _LP64 -constexpr Register r8 = as_Register( 8); -constexpr Register r9 = as_Register( 9); +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); @@ -141,7 +136,6 @@ constexpr Register r28 = as_Register(28); constexpr Register r29 = as_Register(29); constexpr Register r30 = as_Register(30); constexpr Register r31 = as_Register(31); -#endif // _LP64 // The implementation of x87 floating point registers for the ia32 architecture. @@ -154,10 +148,8 @@ private: public: inline friend constexpr FloatRegister as_FloatRegister(int encoding); - enum { - number_of_registers = 8, - max_slots_per_register = 2 - }; + static const int number_of_registers = 8; + static const int max_slots_per_register = 2; class FloatRegisterImpl: public AbstractRegisterImpl { friend class FloatRegister; @@ -217,10 +209,8 @@ private: public: inline friend constexpr XMMRegister as_XMMRegister(int encoding); - enum { - number_of_registers = LP64_ONLY( 32 ) NOT_LP64( 8 ), - max_slots_per_register = LP64_ONLY( 16 ) NOT_LP64( 16 ) // 512-bit - }; + static const int number_of_registers = 32; + static const int max_slots_per_register = 16; // 512-bit class XMMRegisterImpl: public AbstractRegisterImpl { friend class XMMRegister; @@ -250,11 +240,9 @@ public: // Actually available XMM registers for use, depending on actual CPU capabilities and flags. static int available_xmm_registers() { -#ifdef _LP64 if (UseAVX < 3) { return number_of_registers / 2; } -#endif // _LP64 return number_of_registers; } }; @@ -287,7 +275,6 @@ constexpr XMMRegister xmm4 = as_XMMRegister( 4); constexpr XMMRegister xmm5 = as_XMMRegister( 5); constexpr XMMRegister xmm6 = as_XMMRegister( 6); constexpr XMMRegister xmm7 = as_XMMRegister( 7); -#ifdef _LP64 constexpr XMMRegister xmm8 = as_XMMRegister( 8); constexpr XMMRegister xmm9 = as_XMMRegister( 9); constexpr XMMRegister xmm10 = as_XMMRegister(10); @@ -312,7 +299,6 @@ constexpr XMMRegister xmm28 = as_XMMRegister(28); constexpr XMMRegister xmm29 = as_XMMRegister(29); constexpr XMMRegister xmm30 = as_XMMRegister(30); constexpr XMMRegister xmm31 = as_XMMRegister(31); -#endif // _LP64 // The implementation of AVX-512 opmask registers. @@ -394,25 +380,17 @@ constexpr KRegister k7 = as_KRegister(7); // Define a class that exports it. class ConcreteRegisterImpl : public AbstractRegisterImpl { public: - enum { - max_gpr = Register::number_of_registers * Register::max_slots_per_register, - max_fpr = max_gpr + FloatRegister::number_of_registers * FloatRegister::max_slots_per_register, - max_xmm = max_fpr + XMMRegister::number_of_registers * XMMRegister::max_slots_per_register, - max_kpr = max_xmm + KRegister::number_of_registers * KRegister::max_slots_per_register, + static const int max_gpr = Register::number_of_registers * Register::max_slots_per_register; + static const int max_fpr = max_gpr + FloatRegister::number_of_registers * FloatRegister::max_slots_per_register; + static const int max_xmm = max_fpr + XMMRegister::number_of_registers * XMMRegister::max_slots_per_register; + static const int max_kpr = max_xmm + KRegister::number_of_registers * KRegister::max_slots_per_register; // A big enough number for C2: all the registers plus flags // This number must be large enough to cover REG_COUNT (defined by c2) registers. // There is no requirement that any ordering here matches any ordering c2 gives // it's optoregs. - - // x86_32.ad defines additional dummy FILL0-FILL7 registers, in order to tally - // REG_COUNT (computed by ADLC based on the number of reg_defs seen in .ad files) - // with ConcreteRegisterImpl::number_of_registers additional count of 8 is being - // added for 32 bit jvm. - number_of_registers = max_kpr + // gpr/fpr/xmm/kpr - NOT_LP64( 8 + ) // FILL0-FILL7 in x86_32.ad - 1 // eflags - }; + static const int number_of_registers = max_kpr + // gpr/fpr/xmm/kpr + 1; // eflags }; template <> diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp index 3e5593322d5..7d5dee6a5df 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +64,39 @@ static address kyberAvx512ConstsAddr(int offset) { const Register scratch = r10; +ATTRIBUTE_ALIGNED(64) static const uint8_t kyberAvx512_12To16Dup[] = { +// 0 - 63 + 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11, 12, 13, 13, 14, 15, 16, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23, 24, 25, 25, 26, 27, 28, 28, 29, 30, + 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, 40, 41, 42, 43, 43, 44, + 45, 46, 46, 47 + }; + +static address kyberAvx512_12To16DupAddr() { + return (address) kyberAvx512_12To16Dup; +} + +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512_12To16Shift[] = { +// 0 - 31 + 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, + 4, 0, 4, 0, 4, 0, 4 + }; + +static address kyberAvx512_12To16ShiftAddr() { + return (address) kyberAvx512_12To16Shift; +} + +ATTRIBUTE_ALIGNED(64) static const uint64_t kyberAvx512_12To16And[] = { +// 0 - 7 + 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, + 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF, + 0x0FFF0FFF0FFF0FFF, 0x0FFF0FFF0FFF0FFF + }; + +static address kyberAvx512_12To16AndAddr() { + return (address) kyberAvx512_12To16And; +} + ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512NttPerms[] = { // 0 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, @@ -822,10 +855,65 @@ address generate_kyber12To16_avx512(StubGenerator *stubgen, const Register perms = r11; - Label Loop; + Label Loop, VBMILoop; __ addptr(condensed, condensedOffs); + if (VM_Version::supports_avx512_vbmi()) { + // mask load for the first 48 bytes of each vector + __ mov64(rax, 0x0000FFFFFFFFFFFF); + __ kmovql(k1, rax); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16DupAddr())); + __ evmovdqub(xmm20, Address(perms), Assembler::AVX_512bit); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16ShiftAddr())); + __ evmovdquw(xmm21, Address(perms), Assembler::AVX_512bit); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16AndAddr())); + __ evmovdquq(xmm22, Address(perms), Assembler::AVX_512bit); + + __ align(OptoLoopAlignment); + __ BIND(VBMILoop); + + __ evmovdqub(xmm0, k1, Address(condensed, 0), false, + Assembler::AVX_512bit); + __ evmovdqub(xmm1, k1, Address(condensed, 48), false, + Assembler::AVX_512bit); + __ evmovdqub(xmm2, k1, Address(condensed, 96), false, + Assembler::AVX_512bit); + __ evmovdqub(xmm3, k1, Address(condensed, 144), false, + Assembler::AVX_512bit); + + __ evpermb(xmm4, k0, xmm20, xmm0, false, Assembler::AVX_512bit); + __ evpermb(xmm5, k0, xmm20, xmm1, false, Assembler::AVX_512bit); + __ evpermb(xmm6, k0, xmm20, xmm2, false, Assembler::AVX_512bit); + __ evpermb(xmm7, k0, xmm20, xmm3, false, Assembler::AVX_512bit); + + __ evpsrlvw(xmm4, xmm4, xmm21, Assembler::AVX_512bit); + __ evpsrlvw(xmm5, xmm5, xmm21, Assembler::AVX_512bit); + __ evpsrlvw(xmm6, xmm6, xmm21, Assembler::AVX_512bit); + __ evpsrlvw(xmm7, xmm7, xmm21, Assembler::AVX_512bit); + + __ evpandq(xmm0, xmm22, xmm4, Assembler::AVX_512bit); + __ evpandq(xmm1, xmm22, xmm5, Assembler::AVX_512bit); + __ evpandq(xmm2, xmm22, xmm6, Assembler::AVX_512bit); + __ evpandq(xmm3, xmm22, xmm7, Assembler::AVX_512bit); + + store4regs(parsed, 0, xmm0_3, _masm); + + __ addptr(condensed, 192); + __ addptr(parsed, 256); + __ subl(parsedLength, 128); + __ jcc(Assembler::greater, VBMILoop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; + } + __ lea(perms, ExternalAddress(kyberAvx512_12To16PermsAddr())); load4regs(xmm24_27, perms, 0, _masm); diff --git a/src/hotspot/cpu/x86/vmreg_x86.cpp b/src/hotspot/cpu/x86/vmreg_x86.cpp index 44aee56ef15..45269e69fcb 100644 --- a/src/hotspot/cpu/x86/vmreg_x86.cpp +++ b/src/hotspot/cpu/x86/vmreg_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +32,7 @@ void VMRegImpl::set_regName() { int i; for (i = 0; i < ConcreteRegisterImpl::max_gpr ; ) { regName[i++] = reg->name(); -#ifdef AMD64 regName[i++] = reg->name(); -#endif // AMD64 reg = reg->successor(); } diff --git a/src/hotspot/cpu/x86/vmreg_x86.hpp b/src/hotspot/cpu/x86/vmreg_x86.hpp index 6f7c7fafb32..032ce654f2f 100644 --- a/src/hotspot/cpu/x86/vmreg_x86.hpp +++ b/src/hotspot/cpu/x86/vmreg_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * 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,14 +52,8 @@ inline bool is_KRegister() { } inline Register as_Register() { - - assert( is_Register(), "must be"); - // Yuk -#ifdef AMD64 + assert(is_Register(), "must be"); return ::as_Register(value() >> 1); -#else - return ::as_Register(value()); -#endif // AMD64 } inline FloatRegister as_FloatRegister() { @@ -82,9 +76,6 @@ inline KRegister as_KRegister() { inline bool is_concrete() { assert(is_reg(), "must be"); -#ifndef AMD64 - if (is_Register()) return true; -#endif // AMD64 // Do not use is_XMMRegister() here as it depends on the UseAVX setting. if (value() >= ConcreteRegisterImpl::max_fpr && value() < ConcreteRegisterImpl::max_xmm) { int base = value() - ConcreteRegisterImpl::max_fpr; diff --git a/src/hotspot/cpu/x86/vmreg_x86.inline.hpp b/src/hotspot/cpu/x86/vmreg_x86.inline.hpp index 1aeedc094fd..76d70900fe4 100644 --- a/src/hotspot/cpu/x86/vmreg_x86.inline.hpp +++ b/src/hotspot/cpu/x86/vmreg_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #define CPU_X86_VMREG_X86_INLINE_HPP inline VMReg Register::RegisterImpl::as_VMReg() const { - return VMRegImpl::as_VMReg(encoding() LP64_ONLY( << 1 )); + return VMRegImpl::as_VMReg(encoding() << 1); } inline VMReg FloatRegister::FloatRegisterImpl::as_VMReg() const { diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index f88729cdc66..d7c1911a914 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -258,10 +258,18 @@ bool os::free_memory(physical_memory_size_type& value) { return Aix::available_memory(value); } +bool os::Machine::free_memory(physical_memory_size_type& value) { + return Aix::available_memory(value); +} + bool os::available_memory(physical_memory_size_type& value) { return Aix::available_memory(value); } +bool os::Machine::available_memory(physical_memory_size_type& value) { + return Aix::available_memory(value); +} + bool os::Aix::available_memory(physical_memory_size_type& value) { os::Aix::meminfo_t mi; if (os::Aix::get_meminfo(&mi)) { @@ -273,6 +281,10 @@ bool os::Aix::available_memory(physical_memory_size_type& value) { } bool os::total_swap_space(physical_memory_size_type& value) { + return Machine::total_swap_space(value); +} + +bool os::Machine::total_swap_space(physical_memory_size_type& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { return false; @@ -282,6 +294,10 @@ bool os::total_swap_space(physical_memory_size_type& value) { } bool os::free_swap_space(physical_memory_size_type& value) { + return Machine::free_swap_space(value); +} + +bool os::Machine::free_swap_space(physical_memory_size_type& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { return false; @@ -294,6 +310,10 @@ physical_memory_size_type os::physical_memory() { return Aix::physical_memory(); } +physical_memory_size_type os::Machine::physical_memory() { + return Aix::physical_memory(); +} + size_t os::rss() { return (size_t)0; } // Cpu architecture string @@ -2264,6 +2284,10 @@ int os::active_processor_count() { return ActiveProcessorCount; } + return Machine::active_processor_count(); +} + +int os::Machine::active_processor_count() { int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN); assert(online_cpus > 0 && online_cpus <= processor_count(), "sanity check"); return online_cpus; diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 61de48bb7fa..667810bd6ca 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,10 +137,18 @@ bool os::available_memory(physical_memory_size_type& value) { return Bsd::available_memory(value); } +bool os::Machine::available_memory(physical_memory_size_type& value) { + return Bsd::available_memory(value); +} + bool os::free_memory(physical_memory_size_type& value) { return Bsd::available_memory(value); } +bool os::Machine::free_memory(physical_memory_size_type& value) { + return Bsd::available_memory(value); +} + // Available here means free. Note that this number is of no much use. As an estimate // for future memory pressure it is far too conservative, since MacOS will use a lot // of unused memory for caches, and return it willingly in case of needs. @@ -181,6 +189,10 @@ void os::Bsd::print_uptime_info(outputStream* st) { } bool os::total_swap_space(physical_memory_size_type& value) { + return Machine::total_swap_space(value); +} + +bool os::Machine::total_swap_space(physical_memory_size_type& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); @@ -195,6 +207,10 @@ bool os::total_swap_space(physical_memory_size_type& value) { } bool os::free_swap_space(physical_memory_size_type& value) { + return Machine::free_swap_space(value); +} + +bool os::Machine::free_swap_space(physical_memory_size_type& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); @@ -212,6 +228,10 @@ physical_memory_size_type os::physical_memory() { return Bsd::physical_memory(); } +physical_memory_size_type os::Machine::physical_memory() { + return Bsd::physical_memory(); +} + size_t os::rss() { size_t rss = 0; #ifdef __APPLE__ @@ -2189,6 +2209,10 @@ int os::active_processor_count() { return ActiveProcessorCount; } + return Machine::active_processor_count(); +} + +int os::Machine::active_processor_count() { return _processor_count; } diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index f9c6f794ebd..e49d070890e 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -631,22 +631,20 @@ void CgroupSubsystemFactory::cleanup(CgroupInfo* cg_infos) { * return: * true if there were no errors. false otherwise. */ -bool CgroupSubsystem::active_processor_count(int& value) { - int cpu_count; - int result = -1; - +bool CgroupSubsystem::active_processor_count(double& value) { // We use a cache with a timeout to avoid performing expensive // computations in the event this function is called frequently. // [See 8227006]. - CachingCgroupController* contrl = cpu_controller(); - CachedMetric* cpu_limit = contrl->metrics_cache(); + CachingCgroupController* contrl = cpu_controller(); + CachedMetric* cpu_limit = contrl->metrics_cache(); if (!cpu_limit->should_check_metric()) { - value = (int)cpu_limit->value(); - log_trace(os, container)("CgroupSubsystem::active_processor_count (cached): %d", value); + value = cpu_limit->value(); + log_trace(os, container)("CgroupSubsystem::active_processor_count (cached): %.2f", value); return true; } - cpu_count = os::Linux::active_processor_count(); + int cpu_count = os::Linux::active_processor_count(); + double result = -1; if (!CgroupUtil::processor_count(contrl->controller(), cpu_count, result)) { return false; } @@ -671,8 +669,8 @@ bool CgroupSubsystem::active_processor_count(int& value) { */ bool CgroupSubsystem::memory_limit_in_bytes(physical_memory_size_type upper_bound, physical_memory_size_type& value) { - CachingCgroupController* contrl = memory_controller(); - CachedMetric* memory_limit = contrl->metrics_cache(); + CachingCgroupController* contrl = memory_controller(); + CachedMetric* memory_limit = contrl->metrics_cache(); if (!memory_limit->should_check_metric()) { value = memory_limit->value(); return true; diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 522b64f8816..8aafbf49c63 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -181,9 +181,10 @@ class CgroupController: public CHeapObj { static bool limit_from_str(char* limit_str, physical_memory_size_type& value); }; +template class CachedMetric : public CHeapObj{ private: - volatile physical_memory_size_type _metric; + volatile MetricType _metric; volatile jlong _next_check_counter; public: CachedMetric() { @@ -193,8 +194,8 @@ class CachedMetric : public CHeapObj{ bool should_check_metric() { return os::elapsed_counter() > _next_check_counter; } - physical_memory_size_type value() { return _metric; } - void set_value(physical_memory_size_type value, jlong timeout) { + MetricType value() { return _metric; } + void set_value(MetricType value, jlong timeout) { _metric = value; // Metric is unlikely to change, but we want to remain // responsive to configuration changes. A very short grace time @@ -205,19 +206,19 @@ class CachedMetric : public CHeapObj{ } }; -template +template class CachingCgroupController : public CHeapObj { private: T* _controller; - CachedMetric* _metrics_cache; + CachedMetric* _metrics_cache; public: CachingCgroupController(T* cont) { _controller = cont; - _metrics_cache = new CachedMetric(); + _metrics_cache = new CachedMetric(); } - CachedMetric* metrics_cache() { return _metrics_cache; } + CachedMetric* metrics_cache() { return _metrics_cache; } T* controller() { return _controller; } }; @@ -277,7 +278,7 @@ class CgroupMemoryController: public CHeapObj { class CgroupSubsystem: public CHeapObj { public: bool memory_limit_in_bytes(physical_memory_size_type upper_bound, physical_memory_size_type& value); - bool active_processor_count(int& value); + bool active_processor_count(double& value); virtual bool pids_max(uint64_t& value) = 0; virtual bool pids_current(uint64_t& value) = 0; @@ -286,8 +287,8 @@ class CgroupSubsystem: public CHeapObj { virtual char * cpu_cpuset_cpus() = 0; virtual char * cpu_cpuset_memory_nodes() = 0; virtual const char * container_type() = 0; - virtual CachingCgroupController* memory_controller() = 0; - virtual CachingCgroupController* cpu_controller() = 0; + virtual CachingCgroupController* memory_controller() = 0; + virtual CachingCgroupController* cpu_controller() = 0; virtual CgroupCpuacctController* cpuacct_controller() = 0; bool cpu_quota(int& value); diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index 7aa07d53148..570b335940b 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, 2025, Red Hat, Inc. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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 +26,8 @@ #include "cgroupUtil_linux.hpp" #include "os_linux.hpp" -bool CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int upper_bound, int& value) { +bool CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int upper_bound, double& value) { assert(upper_bound > 0, "upper bound of cpus must be positive"); - int limit_count = upper_bound; int quota = -1; int period = -1; if (!cpu_ctrl->cpu_quota(quota)) { @@ -37,20 +37,15 @@ bool CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int upper_bound, return false; } int quota_count = 0; - int result = upper_bound; + double result = upper_bound; - if (quota > -1 && period > 0) { - quota_count = ceilf((float)quota / (float)period); - log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); + if (quota > 0 && period > 0) { // Use quotas + double cpu_quota = static_cast(quota) / period; + log_trace(os, container)("CPU Quota based on quota/period: %.2f", cpu_quota); + result = MIN2(result, cpu_quota); } - // Use quotas - if (quota_count != 0) { - limit_count = quota_count; - } - - result = MIN2(upper_bound, limit_count); - log_trace(os, container)("OSContainer::active_processor_count: %d", result); + log_trace(os, container)("OSContainer::active_processor_count: %.2f", result); value = result; return true; } @@ -73,11 +68,11 @@ physical_memory_size_type CgroupUtil::get_updated_mem_limit(CgroupMemoryControll // Get an updated cpu limit. The return value is strictly less than or equal to the // passed in 'lowest' value. -int CgroupUtil::get_updated_cpu_limit(CgroupCpuController* cpu, +double CgroupUtil::get_updated_cpu_limit(CgroupCpuController* cpu, int lowest, int upper_bound) { assert(lowest > 0 && lowest <= upper_bound, "invariant"); - int cpu_limit_val = -1; + double cpu_limit_val = -1; if (CgroupUtil::processor_count(cpu, upper_bound, cpu_limit_val) && cpu_limit_val != upper_bound) { assert(cpu_limit_val <= upper_bound, "invariant"); if (lowest > cpu_limit_val) { @@ -172,7 +167,7 @@ void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { assert(cg_path[0] == '/', "cgroup path must start with '/'"); int host_cpus = os::Linux::active_processor_count(); int lowest_limit = host_cpus; - int cpus = get_updated_cpu_limit(cpu, lowest_limit, host_cpus); + double cpus = get_updated_cpu_limit(cpu, lowest_limit, host_cpus); int orig_limit = lowest_limit != host_cpus ? lowest_limit : host_cpus; char* limit_cg_path = nullptr; while ((last_slash = strrchr(cg_path, '/')) != cg_path) { diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp index d72bbd1cf1e..1fd2a7d872b 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.hpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, Red Hat, Inc. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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 +32,7 @@ class CgroupUtil: AllStatic { public: - static bool processor_count(CgroupCpuController* cpu, int upper_bound, int& value); + static bool processor_count(CgroupCpuController* cpu, int upper_bound, double& value); // Given a memory controller, adjust its path to a point in the hierarchy // that represents the closest memory limit. static void adjust_controller(CgroupMemoryController* m); @@ -42,9 +43,7 @@ class CgroupUtil: AllStatic { static physical_memory_size_type get_updated_mem_limit(CgroupMemoryController* m, physical_memory_size_type lowest, physical_memory_size_type upper_bound); - static int get_updated_cpu_limit(CgroupCpuController* c, - int lowest, - int upper_bound); + static double get_updated_cpu_limit(CgroupCpuController* c, int lowest, int upper_bound); }; #endif // CGROUP_UTIL_LINUX_HPP diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 2df604083d2..c8f5a290c99 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -328,8 +328,8 @@ CgroupV1Subsystem::CgroupV1Subsystem(CgroupV1Controller* cpuset, _pids(pids) { CgroupUtil::adjust_controller(memory); CgroupUtil::adjust_controller(cpu); - _memory = new CachingCgroupController(memory); - _cpu = new CachingCgroupController(cpu); + _memory = new CachingCgroupController(memory); + _cpu = new CachingCgroupController(cpu); } bool CgroupV1Subsystem::is_containerized() { diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index f556bc57f26..af8d0efd378 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -214,15 +214,15 @@ class CgroupV1Subsystem: public CgroupSubsystem { const char * container_type() override { return "cgroupv1"; } - CachingCgroupController* memory_controller() override { return _memory; } - CachingCgroupController* cpu_controller() override { return _cpu; } + CachingCgroupController* memory_controller() override { return _memory; } + CachingCgroupController* cpu_controller() override { return _cpu; } CgroupCpuacctController* cpuacct_controller() override { return _cpuacct; } private: /* controllers */ - CachingCgroupController* _memory = nullptr; + CachingCgroupController* _memory = nullptr; CgroupV1Controller* _cpuset = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _cpu = nullptr; CgroupV1CpuacctController* _cpuacct = nullptr; CgroupV1Controller* _pids = nullptr; diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index c61d30e9236..30e1affc646 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2025, Red Hat Inc. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -156,8 +156,8 @@ CgroupV2Subsystem::CgroupV2Subsystem(CgroupV2MemoryController * memory, _unified(unified) { CgroupUtil::adjust_controller(memory); CgroupUtil::adjust_controller(cpu); - _memory = new CachingCgroupController(memory); - _cpu = new CachingCgroupController(cpu); + _memory = new CachingCgroupController(memory); + _cpu = new CachingCgroupController(cpu); _cpuacct = cpuacct; } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 39a4fabe9f6..998145c0ff9 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2024, Red Hat Inc. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +152,8 @@ class CgroupV2Subsystem: public CgroupSubsystem { /* One unified controller */ CgroupV2Controller _unified; /* Caching wrappers for cpu/memory metrics */ - CachingCgroupController* _memory = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _memory = nullptr; + CachingCgroupController* _cpu = nullptr; CgroupCpuacctController* _cpuacct = nullptr; @@ -175,8 +175,8 @@ class CgroupV2Subsystem: public CgroupSubsystem { const char * container_type() override { return "cgroupv2"; } - CachingCgroupController* memory_controller() override { return _memory; } - CachingCgroupController* cpu_controller() override { return _cpu; } + CachingCgroupController* memory_controller() override { return _memory; } + CachingCgroupController* cpu_controller() override { return _cpu; } CgroupCpuacctController* cpuacct_controller() override { return _cpuacct; }; }; diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index 25ffd0b8078..28159ae4801 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -66,9 +66,6 @@ #endif // open(2) flags -#ifndef O_CLOEXEC -#define O_CLOEXEC 02000000 -#endif #ifndef O_TMPFILE #define O_TMPFILE (020000000 | O_DIRECTORY) #endif diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index 15a6403d07f..fe1dbc17239 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ void OSContainer::init() { // 2.) On a physical Linux system with a limit enforced by other means (like systemd slice) physical_memory_size_type mem_limit_val = value_unlimited; (void)memory_limit_in_bytes(mem_limit_val); // discard error and use default - int host_cpus = os::Linux::active_processor_count(); - int cpus = host_cpus; + double host_cpus = os::Linux::active_processor_count(); + double cpus = host_cpus; (void)active_processor_count(cpus); // discard error and use default any_mem_cpu_limit_present = mem_limit_val != value_unlimited || host_cpus != cpus; if (any_mem_cpu_limit_present) { @@ -127,8 +127,7 @@ bool OSContainer::available_memory_in_bytes(physical_memory_size_type& value) { return false; } -bool OSContainer::available_swap_in_bytes(physical_memory_size_type host_free_swap, - physical_memory_size_type& value) { +bool OSContainer::available_swap_in_bytes(physical_memory_size_type& value) { physical_memory_size_type mem_limit = 0; physical_memory_size_type mem_swap_limit = 0; if (memory_limit_in_bytes(mem_limit) && @@ -179,8 +178,7 @@ bool OSContainer::available_swap_in_bytes(physical_memory_size_type host_free_sw assert(num < 25, "buffer too small"); mem_limit_buf[num] = '\0'; log_trace(os,container)("OSContainer::available_swap_in_bytes: container_swap_limit=%s" - " container_mem_limit=%s, host_free_swap: " PHYS_MEM_TYPE_FORMAT, - mem_swap_buf, mem_limit_buf, host_free_swap); + " container_mem_limit=%s", mem_swap_buf, mem_limit_buf); } return false; } @@ -252,7 +250,7 @@ char * OSContainer::cpu_cpuset_memory_nodes() { return cgroup_subsystem->cpu_cpuset_memory_nodes(); } -bool OSContainer::active_processor_count(int& value) { +bool OSContainer::active_processor_count(double& value) { assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); return cgroup_subsystem->active_processor_count(value); } @@ -291,11 +289,13 @@ 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 = "%.2f"; }; 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*, double, const char*); template void OSContainer::print_container_metric(outputStream*, const char*, const char*, const char*); template diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp index 11c3e086feb..96b59b98db8 100644 --- a/src/hotspot/os/linux/osContainer_linux.hpp +++ b/src/hotspot/os/linux/osContainer_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ class OSContainer: AllStatic { static const char * container_type(); static bool available_memory_in_bytes(physical_memory_size_type& value); - static bool available_swap_in_bytes(physical_memory_size_type host_free_swap, - physical_memory_size_type& value); + static bool available_swap_in_bytes(physical_memory_size_type& value); static bool memory_limit_in_bytes(physical_memory_size_type& value); static bool memory_and_swap_limit_in_bytes(physical_memory_size_type& value); static bool memory_and_swap_usage_in_bytes(physical_memory_size_type& value); @@ -84,7 +83,7 @@ class OSContainer: AllStatic { static bool rss_usage_in_bytes(physical_memory_size_type& value); static bool cache_usage_in_bytes(physical_memory_size_type& value); - static bool active_processor_count(int& value); + static bool active_processor_count(double& value); static char * cpu_cpuset_cpus(); static char * cpu_cpuset_memory_nodes(); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 88e5e9b582a..48529c6ce17 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -211,15 +211,58 @@ static bool suppress_primordial_thread_resolution = false; // utility functions +bool os::is_containerized() { + return OSContainer::is_containerized(); +} + +bool os::Container::memory_limit(physical_memory_size_type& value) { + physical_memory_size_type result = 0; + if (OSContainer::memory_limit_in_bytes(result) && result != value_unlimited) { + value = result; + return true; + } + return false; +} + +bool os::Container::memory_soft_limit(physical_memory_size_type& value) { + physical_memory_size_type result = 0; + if (OSContainer::memory_soft_limit_in_bytes(result) && result != 0 && result != value_unlimited) { + value = result; + return true; + } + return false; +} + +bool os::Container::memory_throttle_limit(physical_memory_size_type& value) { + physical_memory_size_type result = 0; + if (OSContainer::memory_throttle_limit_in_bytes(result) && result != value_unlimited) { + value = result; + return true; + } + return false; +} + +bool os::Container::used_memory(physical_memory_size_type& value) { + return OSContainer::memory_usage_in_bytes(value); +} + bool os::available_memory(physical_memory_size_type& value) { - if (OSContainer::is_containerized() && OSContainer::available_memory_in_bytes(value)) { + if (is_containerized() && Container::available_memory(value)) { log_trace(os)("available container memory: " PHYS_MEM_TYPE_FORMAT, value); return true; } + return Machine::available_memory(value); +} + +bool os::Machine::available_memory(physical_memory_size_type& value) { return Linux::available_memory(value); } +bool os::Container::available_memory(physical_memory_size_type& value) { + return OSContainer::available_memory_in_bytes(value); +} + bool os::Linux::available_memory(physical_memory_size_type& value) { physical_memory_size_type avail_mem = 0; @@ -251,11 +294,15 @@ bool os::Linux::available_memory(physical_memory_size_type& value) { } bool os::free_memory(physical_memory_size_type& value) { - if (OSContainer::is_containerized() && OSContainer::available_memory_in_bytes(value)) { + if (is_containerized() && Container::available_memory(value)) { log_trace(os)("free container memory: " PHYS_MEM_TYPE_FORMAT, value); return true; } + return Machine::free_memory(value); +} + +bool os::Machine::free_memory(physical_memory_size_type& value) { return Linux::free_memory(value); } @@ -274,21 +321,30 @@ bool os::Linux::free_memory(physical_memory_size_type& value) { } bool os::total_swap_space(physical_memory_size_type& value) { - if (OSContainer::is_containerized()) { - physical_memory_size_type mem_swap_limit = value_unlimited; - physical_memory_size_type memory_limit = value_unlimited; - if (OSContainer::memory_and_swap_limit_in_bytes(mem_swap_limit) && - OSContainer::memory_limit_in_bytes(memory_limit)) { - if (memory_limit != value_unlimited && mem_swap_limit != value_unlimited && - mem_swap_limit >= memory_limit /* ensure swap is >= 0 */) { - value = mem_swap_limit - memory_limit; - return true; - } - } - } // fallback to the host swap space if the container returned unlimited + if (is_containerized() && Container::total_swap_space(value)) { + return true; + } // fallback to the host swap space if the container value fails + return Machine::total_swap_space(value); +} + +bool os::Machine::total_swap_space(physical_memory_size_type& value) { return Linux::host_swap(value); } +bool os::Container::total_swap_space(physical_memory_size_type& value) { + physical_memory_size_type mem_swap_limit = value_unlimited; + physical_memory_size_type memory_limit = value_unlimited; + if (OSContainer::memory_and_swap_limit_in_bytes(mem_swap_limit) && + OSContainer::memory_limit_in_bytes(memory_limit)) { + if (memory_limit != value_unlimited && mem_swap_limit != value_unlimited && + mem_swap_limit >= memory_limit /* ensure swap is >= 0 */) { + value = mem_swap_limit - memory_limit; + return true; + } + } + return false; +} + static bool host_free_swap_f(physical_memory_size_type& value) { struct sysinfo si; int ret = sysinfo(&si); @@ -309,32 +365,45 @@ bool os::free_swap_space(physical_memory_size_type& value) { return false; } physical_memory_size_type host_free_swap_val = MIN2(total_swap_space, host_free_swap); - if (OSContainer::is_containerized()) { - if (OSContainer::available_swap_in_bytes(host_free_swap_val, value)) { + if (is_containerized()) { + if (Container::free_swap_space(value)) { return true; } // Fall through to use host value log_trace(os,container)("os::free_swap_space: containerized value unavailable" " returning host value: " PHYS_MEM_TYPE_FORMAT, host_free_swap_val); } + value = host_free_swap_val; return true; } +bool os::Machine::free_swap_space(physical_memory_size_type& value) { + return host_free_swap_f(value); +} + +bool os::Container::free_swap_space(physical_memory_size_type& value) { + return OSContainer::available_swap_in_bytes(value); +} + physical_memory_size_type os::physical_memory() { - if (OSContainer::is_containerized()) { + if (is_containerized()) { physical_memory_size_type mem_limit = value_unlimited; - if (OSContainer::memory_limit_in_bytes(mem_limit) && mem_limit != value_unlimited) { + if (Container::memory_limit(mem_limit) && mem_limit != value_unlimited) { log_trace(os)("total container memory: " PHYS_MEM_TYPE_FORMAT, mem_limit); return mem_limit; } } - physical_memory_size_type phys_mem = Linux::physical_memory(); + physical_memory_size_type phys_mem = Machine::physical_memory(); log_trace(os)("total system memory: " PHYS_MEM_TYPE_FORMAT, phys_mem); return phys_mem; } +physical_memory_size_type os::Machine::physical_memory() { + return Linux::physical_memory(); +} + // Returns the resident set size (RSS) of the process. // Falls back to using VmRSS from /proc/self/status if /proc/self/smaps_rollup is unavailable. // Note: On kernels with memory cgroups or shared memory, VmRSS may underreport RSS. @@ -2439,20 +2508,21 @@ bool os::Linux::print_container_info(outputStream* st) { 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); + double cpus = -1; + bool supported = OSContainer::active_processor_count(cpus); if (supported) { - assert(i > 0, "must be"); + assert(cpus > 0, "must be"); if (ActiveProcessorCount > 0) { OSContainer::print_container_metric(st, "active_processor_count", ActiveProcessorCount, "(from -XX:ActiveProcessorCount)"); } else { - OSContainer::print_container_metric(st, "active_processor_count", i); + OSContainer::print_container_metric(st, "active_processor_count", cpus); } } else { OSContainer::print_container_metric(st, "active_processor_count", "not supported"); } + int i = -1; supported = OSContainer::cpu_quota(i); if (supported && i > 0) { OSContainer::print_container_metric(st, "cpu_quota", i); @@ -4737,15 +4807,26 @@ int os::active_processor_count() { return ActiveProcessorCount; } - int active_cpus = -1; - if (OSContainer::is_containerized() && OSContainer::active_processor_count(active_cpus)) { - log_trace(os)("active_processor_count: determined by OSContainer: %d", - active_cpus); - } else { - active_cpus = os::Linux::active_processor_count(); + if (is_containerized()) { + double cpu_quota; + if (Container::processor_count(cpu_quota)) { + int active_cpus = ceilf(cpu_quota); // Round fractional CPU quota up. + assert(active_cpus <= Machine::active_processor_count(), "must be"); + log_trace(os)("active_processor_count: determined by OSContainer: %d", + active_cpus); + return active_cpus; + } } - return active_cpus; + return Machine::active_processor_count(); +} + +int os::Machine::active_processor_count() { + return os::Linux::active_processor_count(); +} + +bool os::Container::processor_count(double& value) { + return OSContainer::active_processor_count(value); } static bool should_warn_invalid_processor_id() { @@ -4878,31 +4959,8 @@ int os::open(const char *path, int oflag, int mode) { // All file descriptors that are opened in the Java process and not // specifically destined for a subprocess should have the close-on-exec // flag set. If we don't set it, then careless 3rd party native code - // might fork and exec without closing all appropriate file descriptors, - // and this in turn might: - // - // - cause end-of-file to fail to be detected on some file - // descriptors, resulting in mysterious hangs, or - // - // - might cause an fopen in the subprocess to fail on a system - // suffering from bug 1085341. - // - // (Yes, the default setting of the close-on-exec flag is a Unix - // design flaw) - // - // See: - // 1085341: 32-bit stdio routines should support file descriptors >255 - // 4843136: (process) pipe file descriptor from Runtime.exec not being closed - // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9 - // - // Modern Linux kernels (after 2.6.23 2007) support O_CLOEXEC with open(). - // O_CLOEXEC is preferable to using FD_CLOEXEC on an open file descriptor - // because it saves a system call and removes a small window where the flag - // is unset. On ancient Linux kernels the O_CLOEXEC flag will be ignored - // and we fall back to using FD_CLOEXEC (see below). -#ifdef O_CLOEXEC + // might fork and exec without closing all appropriate file descriptors. oflag |= O_CLOEXEC; -#endif int fd = ::open(path, oflag, mode); if (fd == -1) return -1; @@ -4925,21 +4983,6 @@ int os::open(const char *path, int oflag, int mode) { } } -#ifdef FD_CLOEXEC - // Validate that the use of the O_CLOEXEC flag on open above worked. - // With recent kernels, we will perform this check exactly once. - static sig_atomic_t O_CLOEXEC_is_known_to_work = 0; - if (!O_CLOEXEC_is_known_to_work) { - int flags = ::fcntl(fd, F_GETFD); - if (flags != -1) { - if ((flags & FD_CLOEXEC) != 0) - O_CLOEXEC_is_known_to_work = 1; - else - ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC); - } - } -#endif - return fd; } diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 85babea5603..203e13a46ac 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -951,6 +951,32 @@ struct enum_sigcode_desc_t { const char* s_desc; }; +#if defined(LINUX) +// Additional kernel si_code definitions that are only exported by +// more recent glibc distributions, so we have to hard-code the values. +#ifndef BUS_MCEERR_AR // glibc 2.17 +#define BUS_MCEERR_AR 4 +#define BUS_MCEERR_AO 5 +#endif + +#ifndef SEGV_PKUERR // glibc 2.27 +#define SEGV_PKUERR 4 +#endif + +#ifndef SYS_SECCOMP // glibc 2.28 +#define SYS_SECCOMP 1 +#endif + +#ifndef TRAP_BRANCH // glibc 2.30 +#define TRAP_BRANCH 3 +#endif + +#ifndef TRAP_HWBKPT // not glibc version specific - gdb related +#define TRAP_HWBKPT 4 +#endif + +#endif // LINUX + static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t* out) { const struct { @@ -976,6 +1002,7 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t { SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for mapped object." }, #if defined(LINUX) { SIGSEGV, SEGV_BNDERR, "SEGV_BNDERR", "Failed address bound checks." }, + { SIGSEGV, SEGV_PKUERR, "SEGV_PKUERR", "Protection key checking failure." }, #endif #if defined(AIX) // no explanation found what keyerr would be @@ -984,8 +1011,18 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t { SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment." }, { SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Nonexistent physical address." }, { SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object-specific hardware error." }, +#if defined(LINUX) + { SIGBUS, BUS_MCEERR_AR,"BUS_MCEERR_AR","Hardware memory error consumed on a machine check: action required." }, + { SIGBUS, BUS_MCEERR_AO,"BUS_MCEERR_AO","Hardware memory error detected in process but not consumed: action optional." }, + + { SIGSYS, SYS_SECCOMP, "SYS_SECCOMP", "Secure computing (seccomp) filter failure." }, +#endif { SIGTRAP, TRAP_BRKPT, "TRAP_BRKPT", "Process breakpoint." }, { SIGTRAP, TRAP_TRACE, "TRAP_TRACE", "Process trace trap." }, +#if defined(LINUX) + { SIGTRAP, TRAP_BRANCH, "TRAP_BRANCH", "Process taken branch trap." }, + { SIGTRAP, TRAP_HWBKPT, "TRAP_HWBKPT", "Hardware breakpoint/watchpoint." }, +#endif { SIGCHLD, CLD_EXITED, "CLD_EXITED", "Child has exited." }, { SIGCHLD, CLD_KILLED, "CLD_KILLED", "Child has terminated abnormally and did not create a core file." }, { SIGCHLD, CLD_DUMPED, "CLD_DUMPED", "Child has terminated abnormally and created a core file." }, @@ -993,6 +1030,7 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t { SIGCHLD, CLD_STOPPED, "CLD_STOPPED", "Child has stopped." }, { SIGCHLD, CLD_CONTINUED,"CLD_CONTINUED","Stopped child has continued." }, #ifdef SIGPOLL + { SIGPOLL, POLL_IN, "POLL_IN", "Data input available." }, { SIGPOLL, POLL_OUT, "POLL_OUT", "Output buffers available." }, { SIGPOLL, POLL_MSG, "POLL_MSG", "Input message available." }, { SIGPOLL, POLL_ERR, "POLL_ERR", "I/O error." }, diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index efbd1fe7c68..b0b7ae18106 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -839,10 +839,18 @@ bool os::available_memory(physical_memory_size_type& value) { return win32::available_memory(value); } +bool os::Machine::available_memory(physical_memory_size_type& value) { + return win32::available_memory(value); +} + bool os::free_memory(physical_memory_size_type& value) { return win32::available_memory(value); } +bool os::Machine::free_memory(physical_memory_size_type& value) { + return win32::available_memory(value); +} + bool os::win32::available_memory(physical_memory_size_type& value) { // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect // value if total memory is larger than 4GB @@ -858,7 +866,11 @@ bool os::win32::available_memory(physical_memory_size_type& value) { } } -bool os::total_swap_space(physical_memory_size_type& value) { +bool os::total_swap_space(physical_memory_size_type& value) { + return Machine::total_swap_space(value); +} + +bool os::Machine::total_swap_space(physical_memory_size_type& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); @@ -872,6 +884,10 @@ bool os::total_swap_space(physical_memory_size_type& value) { } bool os::free_swap_space(physical_memory_size_type& value) { + return Machine::free_swap_space(value); +} + +bool os::Machine::free_swap_space(physical_memory_size_type& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); @@ -888,6 +904,10 @@ physical_memory_size_type os::physical_memory() { return win32::physical_memory(); } +physical_memory_size_type os::Machine::physical_memory() { + return win32::physical_memory(); +} + size_t os::rss() { size_t rss = 0; PROCESS_MEMORY_COUNTERS_EX pmex; @@ -911,6 +931,10 @@ int os::active_processor_count() { return ActiveProcessorCount; } + return Machine::active_processor_count(); +} + +int os::Machine::active_processor_count() { bool schedules_all_processor_groups = win32::is_windows_11_or_greater() || win32::is_windows_server_2022_or_greater(); if (UseAllWindowsProcessorGroups && !schedules_all_processor_groups && !win32::processor_group_warning_displayed()) { win32::set_processor_group_warning_displayed(true); diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index c775014cfac..20dfad0d980 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -614,6 +614,10 @@ struct StringTableDeleteCheck : StackObj { }; void StringTable::clean_dead_entries(JavaThread* jt) { + // BulkDeleteTask::prepare() may take ConcurrentHashTableResize_lock (nosafepoint-2). + // When NativeHeapTrimmer is enabled, SuspendMark may take NativeHeapTrimmer::_lock (nosafepoint). + // Take SuspendMark first to keep lock order and avoid deadlock. + NativeHeapTrimmer::SuspendMark sm("stringtable"); StringTableHash::BulkDeleteTask bdt(_local_table); if (!bdt.prepare(jt)) { return; @@ -621,7 +625,6 @@ void StringTable::clean_dead_entries(JavaThread* jt) { StringTableDeleteCheck stdc; StringTableDoDelete stdd; - NativeHeapTrimmer::SuspendMark sm("stringtable"); { TraceTime timer("Clean", TRACETIME_LOG(Debug, stringtable, perf)); while(bdt.do_task(jt, stdc, stdd)) { diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index ec639a2b4d3..c49aa10fa0d 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -763,6 +763,10 @@ struct SymbolTableDeleteCheck : StackObj { }; void SymbolTable::clean_dead_entries(JavaThread* jt) { + // BulkDeleteTask::prepare() may take ConcurrentHashTableResize_lock (nosafepoint-2). + // When NativeHeapTrimmer is enabled, SuspendMark may take NativeHeapTrimmer::_lock (nosafepoint). + // Take SuspendMark first to keep lock order and avoid deadlock. + NativeHeapTrimmer::SuspendMark sm("symboltable"); SymbolTableHash::BulkDeleteTask bdt(_local_table); if (!bdt.prepare(jt)) { return; @@ -770,7 +774,6 @@ void SymbolTable::clean_dead_entries(JavaThread* jt) { SymbolTableDeleteCheck stdc; SymbolTableDoDelete stdd; - NativeHeapTrimmer::SuspendMark sm("symboltable"); { TraceTime timer("Clean", TRACETIME_LOG(Debug, symboltable, perf)); while (bdt.do_task(jt, stdc, stdd)) { diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 0314c5227d2..f51c068f1e7 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1371,6 +1371,7 @@ void AOTCodeAddressTable::init_extrs() { SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom_narrow); #endif #if INCLUDE_ZGC + SET_ADDRESS(_extrs, ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr()); SET_ADDRESS(_extrs, ZBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded_addr()); #if defined(AMD64) SET_ADDRESS(_extrs, &ZPointerLoadShift); diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp index 24182c22a23..59ab69b2427 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp @@ -62,8 +62,6 @@ jint EpsilonHeap::initialize() { // Enable monitoring _monitoring_support = new EpsilonMonitoringSupport(this); - _last_counter_update = 0; - _last_heap_print = 0; // Install barrier set BarrierSet::set_barrier_set(new EpsilonBarrierSet()); @@ -156,17 +154,17 @@ HeapWord* EpsilonHeap::allocate_work(size_t size) { // At this point, some diagnostic subsystems might not yet be initialized. // We pretend the printout happened either way. This keeps allocation path // from obsessively checking the subsystems' status on every allocation. - size_t last_counter = AtomicAccess::load(&_last_counter_update); + size_t last_counter = _last_counter_update.load_relaxed(); if ((used - last_counter >= _step_counter_update) && - AtomicAccess::cmpxchg(&_last_counter_update, last_counter, used) == last_counter) { + _last_counter_update.compare_set(last_counter, used)) { if (_monitoring_support->is_ready()) { _monitoring_support->update_counters(); } } - size_t last_heap = AtomicAccess::load(&_last_heap_print); + size_t last_heap = _last_heap_print.load_relaxed(); if ((used - last_heap >= _step_heap_print) && - AtomicAccess::cmpxchg(&_last_heap_print, last_heap, used) == last_heap) { + _last_heap_print.compare_set(last_heap, used)) { print_heap_info(used); if (Metaspace::initialized()) { print_metaspace_info(); diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp index 9693c63b15c..8d7aa7960fd 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp @@ -31,6 +31,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/space.hpp" #include "memory/virtualspace.hpp" +#include "runtime/atomic.hpp" #include "services/memoryManager.hpp" class EpsilonHeap : public CollectedHeap { @@ -45,8 +46,8 @@ private: size_t _step_counter_update; size_t _step_heap_print; int64_t _decay_time_ns; - volatile size_t _last_counter_update; - volatile size_t _last_heap_print; + Atomic _last_counter_update; + Atomic _last_heap_print; void print_tracing_info() const override; void stop() override {}; diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp index 38be736df74..213fc18b8ff 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp @@ -96,7 +96,6 @@ public: EpsilonMonitoringSupport::EpsilonMonitoringSupport(EpsilonHeap* heap) { _heap_counters = new EpsilonGenerationCounters(heap); _space_counters = new EpsilonSpaceCounters("Heap", 0, heap->max_capacity(), 0, _heap_counters); - _ready = false; } void EpsilonMonitoringSupport::update_counters() { @@ -114,9 +113,9 @@ void EpsilonMonitoringSupport::update_counters() { } bool EpsilonMonitoringSupport::is_ready() { - return AtomicAccess::load_acquire(&_ready); + return _ready.load_acquire(); } void EpsilonMonitoringSupport::mark_ready() { - return AtomicAccess::release_store(&_ready, true); + _ready.release_store(true); } diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp index 76cdac6df1b..9dc52c2a659 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_EPSILON_EPSILONMONITORINGSUPPORT_HPP #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" class EpsilonGenerationCounters; class EpsilonSpaceCounters; @@ -35,7 +36,7 @@ class EpsilonMonitoringSupport : public CHeapObj { private: EpsilonGenerationCounters* _heap_counters; EpsilonSpaceCounters* _space_counters; - volatile bool _ready; + Atomic _ready; public: EpsilonMonitoringSupport(EpsilonHeap* heap); diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 80cf5fea76a..3441e6bc608 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1024,10 +1024,6 @@ size_t G1CardSet::num_containers() { return cl._count; } -G1CardSetCoarsenStats G1CardSet::coarsen_stats() { - return _coarsen_stats; -} - void G1CardSet::print_coarsen_stats(outputStream* out) { _last_coarsen_stats.subtract_from(_coarsen_stats); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 2ad5a26d5e6..b6c3c0b0907 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -103,7 +103,6 @@ #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/cpuTimeCounters.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" @@ -687,8 +686,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) { // before the allocation is that we avoid having to keep track of the newly // allocated memory while we do a GC. // Only try that if we can actually perform a GC. - if (is_init_completed() && policy()->need_to_start_conc_mark("concurrent humongous allocation", - word_size)) { + if (is_init_completed() && + policy()->need_to_start_conc_mark("concurrent humongous allocation", word_size)) { try_collect(word_size, GCCause::_g1_humongous_allocation, collection_counters(this)); } diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp index ffcb5a0022f..37553e2aa56 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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 +29,6 @@ #include "gc/g1/g1EvacFailureRegions.inline.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "memory/allocation.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/bitMap.inline.hpp" G1EvacFailureRegions::G1EvacFailureRegions() : @@ -43,7 +43,7 @@ G1EvacFailureRegions::~G1EvacFailureRegions() { } void G1EvacFailureRegions::pre_collection(uint max_regions) { - AtomicAccess::store(&_num_regions_evac_failed, 0u); + _num_regions_evac_failed.store_relaxed(0u); _regions_evac_failed.resize(max_regions); _regions_pinned.resize(max_regions); _regions_alloc_failed.resize(max_regions); @@ -69,6 +69,6 @@ void G1EvacFailureRegions::par_iterate(G1HeapRegionClosure* closure, G1CollectedHeap::heap()->par_iterate_regions_array(closure, hrclaimer, _evac_failed_regions, - AtomicAccess::load(&_num_regions_evac_failed), + num_regions_evac_failed(), worker_id); } diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp index 9d29957b782..f752a3f8ab7 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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 +26,7 @@ #ifndef SHARE_GC_G1_G1EVACFAILUREREGIONS_HPP #define SHARE_GC_G1_G1EVACFAILUREREGIONS_HPP +#include "runtime/atomic.hpp" #include "utilities/bitMap.hpp" class G1AbstractSubTask; @@ -53,14 +55,14 @@ class G1EvacFailureRegions { // Evacuation failed regions (indexes) in the current collection. uint* _evac_failed_regions; // Number of regions evacuation failed in the current collection. - volatile uint _num_regions_evac_failed; + Atomic _num_regions_evac_failed; public: G1EvacFailureRegions(); ~G1EvacFailureRegions(); uint get_region_idx(uint idx) const { - assert(idx < _num_regions_evac_failed, "precondition"); + assert(idx < _num_regions_evac_failed.load_relaxed(), "precondition"); return _evac_failed_regions[idx]; } diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp index 6eec9b63e6b..fb456475b56 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +30,9 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" -#include "runtime/atomicAccess.hpp" uint G1EvacFailureRegions::num_regions_evac_failed() const { - return AtomicAccess::load(&_num_regions_evac_failed); + return _num_regions_evac_failed.load_relaxed(); } bool G1EvacFailureRegions::has_regions_evac_failed() const { @@ -57,7 +57,7 @@ bool G1EvacFailureRegions::record(uint worker_id, uint region_idx, bool cause_pi bool success = _regions_evac_failed.par_set_bit(region_idx, memory_order_relaxed); if (success) { - size_t offset = AtomicAccess::fetch_then_add(&_num_regions_evac_failed, 1u); + size_t offset = _num_regions_evac_failed.fetch_then_add(1u); _evac_failed_regions[offset] = region_idx; G1CollectedHeap* g1h = G1CollectedHeap::heap(); diff --git a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp index 83c846e84d4..c02b028112b 100644 --- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ #include "gc/shared/weakProcessor.inline.hpp" #include "logging/log.hpp" #include "memory/iterator.inline.hpp" -#include "runtime/atomicAccess.hpp" class G1AdjustLiveClosure : public StackObj { G1AdjustClosure* _adjust_closure; diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp index 6cbfe2674e8..398ef046bf5 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp @@ -108,7 +108,7 @@ void G1FullGCMarker::follow_array_chunk(objArrayOop array, int index) { push_objarray(array, end_index); } - array->oop_iterate_range(mark_closure(), beg_index, end_index); + array->oop_iterate_elements_range(mark_closure(), beg_index, end_index); } inline void G1FullGCMarker::follow_object(oop obj) { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index fae73a2c6bf..13c7a6a8d3e 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "memory/allocation.hpp" #include "memory/padded.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index 0f78e0d6271..950098c706e 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "gc/g1/g1CodeRootSet.hpp" #include "gc/g1/g1CollectionSetCandidates.hpp" #include "gc/g1/g1FromCardCache.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "utilities/bitMap.hpp" @@ -123,9 +122,6 @@ public: static void initialize(MemRegion reserved); - // Coarsening statistics since VM start. - static G1CardSetCoarsenStats coarsen_stats() { return G1CardSet::coarsen_stats(); } - inline uintptr_t to_card(OopOrNarrowOopStar from) const; private: diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index fbd529cb1d3..f621b1318c1 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "gc/g1/g1CardSet.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/bitMap.inline.hpp" void G1HeapRegionRemSet::set_state_untracked() { diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.cpp b/src/hotspot/share/gc/g1/g1MonotonicArena.cpp index a9c6462680f..3f97870a67f 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArena.cpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "gc/g1/g1MonotonicArena.inline.hpp" #include "memory/allocation.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/vmOperations.hpp" #include "utilities/globalCounter.inline.hpp" @@ -61,13 +60,13 @@ void G1MonotonicArena::SegmentFreeList::bulk_add(Segment& first, size_t num, size_t mem_size) { _list.prepend(first, last); - AtomicAccess::add(&_num_segments, num, memory_order_relaxed); - AtomicAccess::add(&_mem_size, mem_size, memory_order_relaxed); + _num_segments.add_then_fetch(num, memory_order_relaxed); + _mem_size.add_then_fetch(mem_size, memory_order_relaxed); } void G1MonotonicArena::SegmentFreeList::print_on(outputStream* out, const char* prefix) { out->print_cr("%s: segments %zu size %zu", - prefix, AtomicAccess::load(&_num_segments), AtomicAccess::load(&_mem_size)); + prefix, _num_segments.load_relaxed(), _mem_size.load_relaxed()); } G1MonotonicArena::Segment* G1MonotonicArena::SegmentFreeList::get_all(size_t& num_segments, @@ -75,12 +74,12 @@ G1MonotonicArena::Segment* G1MonotonicArena::SegmentFreeList::get_all(size_t& nu GlobalCounter::CriticalSection cs(Thread::current()); Segment* result = _list.pop_all(); - num_segments = AtomicAccess::load(&_num_segments); - mem_size = AtomicAccess::load(&_mem_size); + num_segments = _num_segments.load_relaxed(); + mem_size = _mem_size.load_relaxed(); if (result != nullptr) { - AtomicAccess::sub(&_num_segments, num_segments, memory_order_relaxed); - AtomicAccess::sub(&_mem_size, mem_size, memory_order_relaxed); + _num_segments.sub_then_fetch(num_segments, memory_order_relaxed); + _mem_size.sub_then_fetch(mem_size, memory_order_relaxed); } return result; } @@ -96,8 +95,8 @@ void G1MonotonicArena::SegmentFreeList::free_all() { Segment::delete_segment(cur); } - AtomicAccess::sub(&_num_segments, num_freed, memory_order_relaxed); - AtomicAccess::sub(&_mem_size, mem_size_freed, memory_order_relaxed); + _num_segments.sub_then_fetch(num_freed, memory_order_relaxed); + _mem_size.sub_then_fetch(mem_size_freed, memory_order_relaxed); } G1MonotonicArena::Segment* G1MonotonicArena::new_segment(Segment* const prev) { @@ -115,7 +114,7 @@ G1MonotonicArena::Segment* G1MonotonicArena::new_segment(Segment* const prev) { } // Install it as current allocation segment. - Segment* old = AtomicAccess::cmpxchg(&_first, prev, next); + Segment* old = _first.compare_exchange(prev, next); if (old != prev) { // Somebody else installed the segment, use that one. Segment::delete_segment(next); @@ -126,9 +125,9 @@ G1MonotonicArena::Segment* G1MonotonicArena::new_segment(Segment* const prev) { _last = next; } // Successfully installed the segment into the list. - AtomicAccess::inc(&_num_segments, memory_order_relaxed); - AtomicAccess::add(&_mem_size, next->mem_size(), memory_order_relaxed); - AtomicAccess::add(&_num_total_slots, next->num_slots(), memory_order_relaxed); + _num_segments.add_then_fetch(1u, memory_order_relaxed); + _mem_size.add_then_fetch(next->mem_size(), memory_order_relaxed); + _num_total_slots.add_then_fetch(next->num_slots(), memory_order_relaxed); return next; } } @@ -155,7 +154,7 @@ uint G1MonotonicArena::slot_size() const { } void G1MonotonicArena::drop_all() { - Segment* cur = AtomicAccess::load_acquire(&_first); + Segment* cur = _first.load_acquire(); if (cur != nullptr) { assert(_last != nullptr, "If there is at least one segment, there must be a last one."); @@ -175,25 +174,25 @@ void G1MonotonicArena::drop_all() { cur = next; } #endif - assert(num_segments == _num_segments, "Segment count inconsistent %u %u", num_segments, _num_segments); - assert(mem_size == _mem_size, "Memory size inconsistent"); + assert(num_segments == _num_segments.load_relaxed(), "Segment count inconsistent %u %u", num_segments, _num_segments.load_relaxed()); + assert(mem_size == _mem_size.load_relaxed(), "Memory size inconsistent"); assert(last == _last, "Inconsistent last segment"); - _segment_free_list->bulk_add(*first, *_last, _num_segments, _mem_size); + _segment_free_list->bulk_add(*first, *_last, _num_segments.load_relaxed(), _mem_size.load_relaxed()); } - _first = nullptr; + _first.store_relaxed(nullptr); _last = nullptr; - _num_segments = 0; - _mem_size = 0; - _num_total_slots = 0; - _num_allocated_slots = 0; + _num_segments.store_relaxed(0); + _mem_size.store_relaxed(0); + _num_total_slots.store_relaxed(0); + _num_allocated_slots.store_relaxed(0); } void* G1MonotonicArena::allocate() { assert(slot_size() > 0, "instance size not set."); - Segment* cur = AtomicAccess::load_acquire(&_first); + Segment* cur = _first.load_acquire(); if (cur == nullptr) { cur = new_segment(cur); } @@ -201,7 +200,7 @@ void* G1MonotonicArena::allocate() { while (true) { void* slot = cur->allocate_slot(); if (slot != nullptr) { - AtomicAccess::inc(&_num_allocated_slots, memory_order_relaxed); + _num_allocated_slots.add_then_fetch(1u, memory_order_relaxed); guarantee(is_aligned(slot, _alloc_options->slot_alignment()), "result " PTR_FORMAT " not aligned at %u", p2i(slot), _alloc_options->slot_alignment()); return slot; @@ -213,7 +212,7 @@ void* G1MonotonicArena::allocate() { } uint G1MonotonicArena::num_segments() const { - return AtomicAccess::load(&_num_segments); + return _num_segments.load_relaxed(); } #ifdef ASSERT @@ -238,7 +237,7 @@ uint G1MonotonicArena::calculate_length() const { template void G1MonotonicArena::iterate_segments(SegmentClosure& closure) const { - Segment* cur = AtomicAccess::load_acquire(&_first); + Segment* cur = _first.load_acquire(); assert((cur != nullptr) == (_last != nullptr), "If there is at least one segment, there must be a last one"); diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.hpp b/src/hotspot/share/gc/g1/g1MonotonicArena.hpp index 211820c5254..d8e658b5a64 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArena.hpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,6 +28,7 @@ #include "gc/shared/freeListAllocator.hpp" #include "nmt/memTag.hpp" +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/lockFreeStack.hpp" @@ -65,27 +66,27 @@ private: // AllocOptions provides parameters for Segment sizing and expansion. const AllocOptions* _alloc_options; - Segment* volatile _first; // The (start of the) list of all segments. - Segment* _last; // The last segment of the list of all segments. - volatile uint _num_segments; // Number of assigned segments to this allocator. - volatile size_t _mem_size; // Memory used by all segments. + Atomic _first; // The (start of the) list of all segments. + Segment* _last; // The last segment of the list of all segments. + Atomic _num_segments; // Number of assigned segments to this allocator. + Atomic _mem_size; // Memory used by all segments. SegmentFreeList* _segment_free_list; // The global free segment list to preferentially // get new segments from. - volatile uint _num_total_slots; // Number of slots available in all segments (allocated + not yet used). - volatile uint _num_allocated_slots; // Number of total slots allocated ever (including free and pending). + Atomic _num_total_slots; // Number of slots available in all segments (allocated + not yet used). + Atomic _num_allocated_slots; // Number of total slots allocated ever (including free and pending). inline Segment* new_segment(Segment* const prev); DEBUG_ONLY(uint calculate_length() const;) public: - const Segment* first_segment() const { return AtomicAccess::load(&_first); } + const Segment* first_segment() const { return _first.load_relaxed(); } - uint num_total_slots() const { return AtomicAccess::load(&_num_total_slots); } + uint num_total_slots() const { return _num_total_slots.load_relaxed(); } uint num_allocated_slots() const { - uint allocated = AtomicAccess::load(&_num_allocated_slots); + uint allocated = _num_allocated_slots.load_relaxed(); assert(calculate_length() == allocated, "Must be"); return allocated; } @@ -116,11 +117,11 @@ static constexpr uint SegmentPayloadMaxAlignment = 8; class alignas(SegmentPayloadMaxAlignment) G1MonotonicArena::Segment { const uint _slot_size; const uint _num_slots; - Segment* volatile _next; + Atomic _next; // Index into the next free slot to allocate into. Full if equal (or larger) // to _num_slots (can be larger because we atomically increment this value and // check only afterwards if the allocation has been successful). - uint volatile _next_allocate; + Atomic _next_allocate; const MemTag _mem_tag; static size_t header_size() { return align_up(sizeof(Segment), SegmentPayloadMaxAlignment); } @@ -139,21 +140,21 @@ class alignas(SegmentPayloadMaxAlignment) G1MonotonicArena::Segment { Segment(uint slot_size, uint num_slots, Segment* next, MemTag mem_tag); ~Segment() = default; public: - Segment* volatile* next_addr() { return &_next; } + Atomic* next_addr() { return &_next; } void* allocate_slot(); uint num_slots() const { return _num_slots; } - Segment* next() const { return _next; } + Segment* next() const { return _next.load_relaxed(); } void set_next(Segment* next) { assert(next != this, " loop condition"); - _next = next; + _next.store_relaxed(next); } void reset(Segment* next) { - _next_allocate = 0; + _next_allocate.store_relaxed(0); assert(next != this, " loop condition"); set_next(next); memset(payload(0), 0, payload_size()); @@ -166,7 +167,7 @@ public: uint length() const { // _next_allocate might grow larger than _num_slots in multi-thread environments // due to races. - return MIN2(_next_allocate, _num_slots); + return MIN2(_next_allocate.load_relaxed(), _num_slots); } static size_t size_in_bytes(uint slot_size, uint num_slots) { @@ -176,7 +177,7 @@ public: static Segment* create_segment(uint slot_size, uint num_slots, Segment* next, MemTag mem_tag); static void delete_segment(Segment* segment); - bool is_full() const { return _next_allocate >= _num_slots; } + bool is_full() const { return _next_allocate.load_relaxed() >= _num_slots; } }; static_assert(alignof(G1MonotonicArena::Segment) >= SegmentPayloadMaxAlignment, "assert alignment of Segment (and indirectly its payload)"); @@ -186,15 +187,15 @@ static_assert(alignof(G1MonotonicArena::Segment) >= SegmentPayloadMaxAlignment, // performed by multiple threads concurrently. // Counts and memory usage are current on a best-effort basis if accessed concurrently. class G1MonotonicArena::SegmentFreeList { - static Segment* volatile* next_ptr(Segment& segment) { + static Atomic* next_ptr(Segment& segment) { return segment.next_addr(); } using SegmentStack = LockFreeStack; SegmentStack _list; - volatile size_t _num_segments; - volatile size_t _mem_size; + Atomic _num_segments; + Atomic _mem_size; public: SegmentFreeList() : _list(), _num_segments(0), _mem_size(0) { } @@ -210,8 +211,8 @@ public: void print_on(outputStream* out, const char* prefix = ""); - size_t num_segments() const { return AtomicAccess::load(&_num_segments); } - size_t mem_size() const { return AtomicAccess::load(&_mem_size); } + size_t num_segments() const { return _num_segments.load_relaxed(); } + size_t mem_size() const { return _mem_size.load_relaxed(); } }; // Configuration for G1MonotonicArena, e.g slot size, slot number of next Segment. diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp b/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp index dd9ccae1849..cf1b35ccead 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,14 +28,13 @@ #include "gc/g1/g1MonotonicArena.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/globalCounter.inline.hpp" inline void* G1MonotonicArena::Segment::allocate_slot() { - if (_next_allocate >= _num_slots) { + if (_next_allocate.load_relaxed() >= _num_slots) { return nullptr; } - uint result = AtomicAccess::fetch_then_add(&_next_allocate, 1u, memory_order_relaxed); + uint result = _next_allocate.fetch_then_add(1u, memory_order_relaxed); if (result >= _num_slots) { return nullptr; } @@ -48,8 +47,8 @@ inline G1MonotonicArena::Segment* G1MonotonicArena::SegmentFreeList::get() { Segment* result = _list.pop(); if (result != nullptr) { - AtomicAccess::dec(&_num_segments, memory_order_relaxed); - AtomicAccess::sub(&_mem_size, result->mem_size(), memory_order_relaxed); + _num_segments.sub_then_fetch(1u, memory_order_relaxed); + _mem_size.sub_then_fetch(result->mem_size(), memory_order_relaxed); } return result; } diff --git a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp index d7e0c6e394f..529ef62b44d 100644 --- a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp +++ b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "nmt/memTracker.hpp" #include "oops/markWord.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/bitMap.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 80e5fd44fcd..75a8ef1a336 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +42,6 @@ #include "memory/allocation.inline.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/prefetch.inline.hpp" #include "utilities/globalDefinitions.hpp" @@ -238,9 +237,9 @@ void G1ParScanThreadState::do_partial_array(PartialArrayState* state, bool stole G1HeapRegionAttr dest_attr = _g1h->region_attr(to_array); G1SkipCardMarkSetter x(&_scanner, dest_attr.is_new_survivor()); // Process claimed task. - to_array->oop_iterate_range(&_scanner, - checked_cast(claim._start), - checked_cast(claim._end)); + to_array->oop_iterate_elements_range(&_scanner, + checked_cast(claim._start), + checked_cast(claim._end)); } MAYBE_INLINE_EVACUATION @@ -260,7 +259,7 @@ void G1ParScanThreadState::start_partial_objarray(oop from_obj, // Process the initial chunk. No need to process the type in the // klass, as it will already be handled by processing the built-in // module. - to_array->oop_iterate_range(&_scanner, 0, checked_cast(initial_chunk_size)); + to_array->oop_iterate_elements_range(&_scanner, 0, checked_cast(initial_chunk_size)); } MAYBE_INLINE_EVACUATION diff --git a/src/hotspot/share/gc/serial/serialFullGC.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp index 546084e38dd..0c8ca51fc99 100644 --- a/src/hotspot/share/gc/serial/serialFullGC.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -412,7 +412,7 @@ void SerialFullGC::follow_array_chunk(objArrayOop array, int index) { const int stride = MIN2(len - beg_index, (int) ObjArrayMarkingStride); const int end_index = beg_index + stride; - array->oop_iterate_range(&mark_and_push_closure, beg_index, end_index); + array->oop_iterate_elements_range(&mark_and_push_closure, beg_index, end_index); if (end_index < len) { SerialFullGC::push_objarray(array, end_index); // Push the continuation. diff --git a/src/hotspot/share/gc/shared/workerUtils.cpp b/src/hotspot/share/gc/shared/workerUtils.cpp index 422d513a5cd..1826b9d7df8 100644 --- a/src/hotspot/share/gc/shared/workerUtils.cpp +++ b/src/hotspot/share/gc/shared/workerUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ * */ +#include "cppstdlib/new.hpp" #include "gc/shared/workerUtils.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" // *** WorkerThreadsBarrierSync @@ -80,21 +81,21 @@ void WorkerThreadsBarrierSync::abort() { SubTasksDone::SubTasksDone(uint n) : _tasks(nullptr), _n_tasks(n) { - _tasks = NEW_C_HEAP_ARRAY(bool, n, mtInternal); + _tasks = NEW_C_HEAP_ARRAY(Atomic, n, mtInternal); for (uint i = 0; i < _n_tasks; i++) { - _tasks[i] = false; + ::new (&_tasks[i]) Atomic(false); } } #ifdef ASSERT void SubTasksDone::all_tasks_claimed_impl(uint skipped[], size_t skipped_size) { - if (AtomicAccess::cmpxchg(&_verification_done, false, true)) { + if (!_verification_done.compare_set(false, true)) { // another thread has done the verification return; } // all non-skipped tasks are claimed for (uint i = 0; i < _n_tasks; ++i) { - if (!_tasks[i]) { + if (!_tasks[i].load_relaxed()) { auto is_skipped = false; for (size_t j = 0; j < skipped_size; ++j) { if (i == skipped[j]) { @@ -109,27 +110,27 @@ void SubTasksDone::all_tasks_claimed_impl(uint skipped[], size_t skipped_size) { for (size_t i = 0; i < skipped_size; ++i) { auto task_index = skipped[i]; assert(task_index < _n_tasks, "Array in range."); - assert(!_tasks[task_index], "%d is both claimed and skipped.", task_index); + assert(!_tasks[task_index].load_relaxed(), "%d is both claimed and skipped.", task_index); } } #endif bool SubTasksDone::try_claim_task(uint t) { assert(t < _n_tasks, "bad task id."); - return !_tasks[t] && !AtomicAccess::cmpxchg(&_tasks[t], false, true); + return !_tasks[t].load_relaxed() && _tasks[t].compare_set(false, true); } SubTasksDone::~SubTasksDone() { - assert(_verification_done, "all_tasks_claimed must have been called."); - FREE_C_HEAP_ARRAY(bool, _tasks); + assert(_verification_done.load_relaxed(), "all_tasks_claimed must have been called."); + FREE_C_HEAP_ARRAY(Atomic, _tasks); } // *** SequentialSubTasksDone bool SequentialSubTasksDone::try_claim_task(uint& t) { - t = _num_claimed; + t = _num_claimed.load_relaxed(); if (t < _num_tasks) { - t = AtomicAccess::add(&_num_claimed, 1u) - 1; + t = _num_claimed.fetch_then_add(1u); } return t < _num_tasks; } diff --git a/src/hotspot/share/gc/shared/workerUtils.hpp b/src/hotspot/share/gc/shared/workerUtils.hpp index 5f771a57837..7bf9d7d7656 100644 --- a/src/hotspot/share/gc/shared/workerUtils.hpp +++ b/src/hotspot/share/gc/shared/workerUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "cppstdlib/type_traits.hpp" #include "memory/allocation.hpp" #include "metaprogramming/enableIf.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutex.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -79,11 +80,11 @@ public: // enumeration type. class SubTasksDone: public CHeapObj { - volatile bool* _tasks; + Atomic* _tasks; uint _n_tasks; // make sure verification logic is run exactly once to avoid duplicate assertion failures - DEBUG_ONLY(volatile bool _verification_done = false;) + DEBUG_ONLY(Atomic _verification_done;) void all_tasks_claimed_impl(uint skipped[], size_t skipped_size) NOT_DEBUG_RETURN; NONCOPYABLE(SubTasksDone); @@ -127,7 +128,7 @@ public: class SequentialSubTasksDone : public CHeapObj { uint _num_tasks; // Total number of tasks available. - volatile uint _num_claimed; // Number of tasks claimed. + Atomic _num_claimed; // Number of tasks claimed. NONCOPYABLE(SequentialSubTasksDone); @@ -135,7 +136,8 @@ public: SequentialSubTasksDone(uint num_tasks) : _num_tasks(num_tasks), _num_claimed(0) { } ~SequentialSubTasksDone() { // Claiming may try to claim more tasks than there are. - assert(_num_claimed >= _num_tasks, "Claimed %u tasks of %u", _num_claimed, _num_tasks); + assert(_num_claimed.load_relaxed() >= _num_tasks, + "Claimed %u tasks of %u", _num_claimed.load_relaxed(), _num_tasks); } // Attempt to claim the next unclaimed task in the sequence, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index c03e66e28da..a8c97801824 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -338,7 +338,7 @@ void ShenandoahRegionPartitions::make_all_regions_unavailable() { _empty_region_counts[partition_id] = 0; _used[partition_id] = 0; _humongous_waste[partition_id] = 0; - _available[partition_id] = FreeSetUnderConstruction; + _available[partition_id] = 0; } } @@ -2495,6 +2495,10 @@ void ShenandoahFreeSet::move_regions_from_collector_to_mutator(size_t max_xfer_r void ShenandoahFreeSet::prepare_to_rebuild(size_t &young_trashed_regions, size_t &old_trashed_regions, size_t &first_old_region, size_t &last_old_region, size_t &old_region_count) { shenandoah_assert_heaplocked(); + assert(rebuild_lock() != nullptr, "sanity"); + rebuild_lock()->lock(false); + // This resets all state information, removing all regions from all sets. + clear(); log_debug(gc, free)("Rebuilding FreeSet"); // This places regions that have alloc_capacity into the old_collector set if they identify as is_old() or the @@ -2524,6 +2528,9 @@ void ShenandoahFreeSet::finish_rebuild(size_t young_trashed_regions, size_t old_ _total_young_regions = _heap->num_regions() - old_region_count; _total_global_regions = _heap->num_regions(); establish_old_collector_alloc_bias(); + + // Release the rebuild lock now. What remains in this function is read-only + rebuild_lock()->unlock(); _partitions.assert_bounds(true); log_status(); } @@ -3058,7 +3065,7 @@ void ShenandoahFreeSet::log_status() { size_t max_humongous = max_contig * ShenandoahHeapRegion::region_size_bytes(); // capacity() is capacity of mutator // used() is used of mutator - size_t free = capacity() - used(); + size_t free = capacity_holding_lock() - used_holding_lock(); // Since certain regions that belonged to the Mutator free partition at the time of most recent rebuild may have been // 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(). diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 95f9fbe6856..364637740f2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -28,9 +28,13 @@ #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" +#include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" #include "logging/logStream.hpp" +typedef ShenandoahLock ShenandoahRebuildLock; +typedef ShenandoahLocker ShenandoahRebuildLocker; + // Each ShenandoahHeapRegion is associated with a ShenandoahFreeSetPartitionId. enum class ShenandoahFreeSetPartitionId : uint8_t { Mutator, // Region is in the Mutator free set: available memory is available to mutators. @@ -139,8 +143,6 @@ public: ShenandoahRegionPartitions(size_t max_regions, ShenandoahFreeSet* free_set); ~ShenandoahRegionPartitions() {} - static const size_t FreeSetUnderConstruction = SIZE_MAX; - inline idx_t max() const { return _max; } // At initialization, reset OldCollector tallies @@ -352,6 +354,16 @@ public: return _available[int(which_partition)]; } + // Return available_in assuming caller does not hold the heap lock but does hold the rebuild_lock. + // The returned value may be "slightly stale" because we do not assure that every fetch of this value + // sees the most recent update of this value. Requiring the caller to hold the rebuild_lock assures + // that we don't see "bogus" values that are "worse than stale". During rebuild of the freeset, the + // value of _available is not reliable. + inline size_t available_in_locked_for_rebuild(ShenandoahFreeSetPartitionId which_partition) const { + assert (which_partition < NumPartitions, "selected free set must be valid"); + return _available[int(which_partition)]; + } + // Returns bytes of humongous waste inline size_t humongous_waste(ShenandoahFreeSetPartitionId which_partition) const { assert (which_partition < NumPartitions, "selected free set must be valid"); @@ -359,23 +371,6 @@ public: return _humongous_waste[int(which_partition)]; } - // Return available_in assuming caller does not hold the heap lock. In production builds, available is - // returned without acquiring the lock. In debug builds, the global heap lock is acquired in order to - // enforce a consistency assert. - inline size_t available_in_not_locked(ShenandoahFreeSetPartitionId which_partition) const { - assert (which_partition < NumPartitions, "selected free set must be valid"); - shenandoah_assert_not_heaplocked(); -#ifdef ASSERT - ShenandoahHeapLocker locker(ShenandoahHeap::heap()->lock()); - assert((_available[int(which_partition)] == FreeSetUnderConstruction) || - (_available[int(which_partition)] == _capacity[int(which_partition)] - _used[int(which_partition)]), - "Expect available (%zu) equals capacity (%zu) - used (%zu) for partition %s", - _available[int(which_partition)], _capacity[int(which_partition)], _used[int(which_partition)], - partition_membership_name(idx_t(which_partition))); -#endif - return _available[int(which_partition)]; - } - inline void set_capacity_of(ShenandoahFreeSetPartitionId which_partition, size_t value); inline void set_used_by(ShenandoahFreeSetPartitionId which_partition, size_t value) { @@ -440,6 +435,15 @@ private: ShenandoahHeap* const _heap; ShenandoahRegionPartitions _partitions; + // This locks the rebuild process (in combination with the global heap lock). Whenever we rebuild the free set, + // we first acquire the global heap lock and then we acquire this _rebuild_lock in a nested context. Threads that + // need to check available, acquire only the _rebuild_lock to make sure that they are not obtaining the value of + // available for a partially reconstructed free-set. + // + // Note that there is rank ordering of nested locks to prevent deadlock. All threads that need to acquire both + // locks will acquire them in the same order: first the global heap lock and then the rebuild lock. + ShenandoahRebuildLock _rebuild_lock; + size_t _total_humongous_waste; HeapWord* allocate_aligned_plab(size_t size, ShenandoahAllocRequest& req, ShenandoahHeapRegion* r); @@ -635,10 +639,12 @@ private: void log_status(); public: - static const size_t FreeSetUnderConstruction = ShenandoahRegionPartitions::FreeSetUnderConstruction; - ShenandoahFreeSet(ShenandoahHeap* heap, size_t max_regions); + ShenandoahRebuildLock* rebuild_lock() { + return &_rebuild_lock; + } + inline size_t max_regions() const { return _partitions.max(); } ShenandoahFreeSetPartitionId membership(size_t index) const { return _partitions.membership(index); } inline void shrink_interval_if_range_modifies_either_boundary(ShenandoahFreeSetPartitionId partition, @@ -776,9 +782,29 @@ public: // adjusts available with respect to lock holders. However, sequential calls to these three functions may produce // inconsistent data: available may not equal capacity - used because the intermediate states of any "atomic" // locked action can be seen by these unlocked functions. - inline size_t capacity() const { return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); } - inline size_t used() const { return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); } - inline size_t available() const { return _partitions.available_in_not_locked(ShenandoahFreeSetPartitionId::Mutator); } + inline size_t capacity_holding_lock() const { + shenandoah_assert_heaplocked(); + return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t capacity_not_holding_lock() { + shenandoah_assert_not_heaplocked(); + ShenandoahRebuildLocker locker(rebuild_lock()); + return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t used_holding_lock() const { + shenandoah_assert_heaplocked(); + return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t used_not_holding_lock() { + shenandoah_assert_not_heaplocked(); + ShenandoahRebuildLocker locker(rebuild_lock()); + return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); + } + inline size_t available() { + shenandoah_assert_not_heaplocked(); + ShenandoahRebuildLocker locker(rebuild_lock()); + return _partitions.available_in_locked_for_rebuild(ShenandoahFreeSetPartitionId::Mutator); + } inline size_t total_humongous_waste() const { return _total_humongous_waste; } inline size_t humongous_waste_in_mutator() const { return _partitions.humongous_waste(ShenandoahFreeSetPartitionId::Mutator); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 027d7e02268..fa3a7a42209 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -1113,18 +1113,17 @@ void ShenandoahFullGC::phase5_epilog() { ShenandoahPostCompactClosure post_compact; heap->heap_region_iterate(&post_compact); heap->collection_set()->clear(); - size_t young_cset_regions, old_cset_regions; - size_t first_old, last_old, num_old; - heap->free_set()->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old, last_old, num_old); - - // We also do not expand old generation size following Full GC because we have scrambled age populations and - // no longer have objects separated by age into distinct regions. - if (heap->mode()->is_generational()) { - ShenandoahGenerationalFullGC::compute_balances(); + size_t young_cset_regions, old_cset_regions, first_old, last_old, num_old; + ShenandoahFreeSet* free_set = heap->free_set(); + { + free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old, last_old, num_old); + // We also do not expand old generation size following Full GC because we have scrambled age populations and + // no longer have objects separated by age into distinct regions. + if (heap->mode()->is_generational()) { + ShenandoahGenerationalFullGC::compute_balances(); + } + free_set->finish_rebuild(young_cset_regions, old_cset_regions, num_old); } - - heap->free_set()->finish_rebuild(young_cset_regions, old_cset_regions, num_old); - // Set mark incomplete because the marking bitmaps have been reset except pinned regions. _generation->set_mark_incomplete(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index d74ee872cd1..a5d8cca458d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -815,10 +815,9 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_rebuild_freeset); ShenandoahHeapLocker locker(heap->lock()); - size_t young_cset_regions, old_cset_regions; // We are preparing for evacuation. At this time, we ignore cset region tallies. - size_t first_old, last_old, num_old; + size_t young_cset_regions, old_cset_regions, first_old, last_old, num_old; _free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old, last_old, num_old); if (heap->mode()->is_generational()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index f887cc9064e..fa78e02e6af 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -104,17 +104,6 @@ void ShenandoahGenerationalHeap::initialize_heuristics() { // Initialize global generation and heuristics even in generational mode. ShenandoahHeap::initialize_heuristics(); - // Max capacity is the maximum _allowed_ capacity. That is, the maximum allowed capacity - // for old would be total heap - minimum capacity of young. This means the sum of the maximum - // allowed for old and young could exceed the total heap size. It remains the case that the - // _actual_ capacity of young + old = total. - size_t region_count = num_regions(); - size_t max_young_regions = MAX2((region_count * ShenandoahMaxYoungPercentage) / 100, (size_t) 1U); - size_t initial_capacity_young = max_young_regions * ShenandoahHeapRegion::region_size_bytes(); - size_t max_capacity_young = initial_capacity_young; - size_t initial_capacity_old = max_capacity() - max_capacity_young; - size_t max_capacity_old = max_capacity() - initial_capacity_young; - _young_generation = new ShenandoahYoungGeneration(max_workers()); _old_generation = new ShenandoahOldGeneration(max_workers()); _young_generation->initialize_heuristics(mode()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 3bf53f800a2..683e2959a92 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -426,8 +426,6 @@ jint ShenandoahHeap::initialize() { _affiliations[i] = ShenandoahAffiliation::FREE; } _free_set = new ShenandoahFreeSet(this, _num_regions); - - post_initialize_heuristics(); // We are initializing free set. We ignore cset region tallies. size_t young_cset_regions, old_cset_regions, first_old, last_old, num_old; @@ -1658,7 +1656,7 @@ void ShenandoahHeap::verify(VerifyOption vo) { } } size_t ShenandoahHeap::tlab_capacity() const { - return _free_set->capacity(); + return _free_set->capacity_not_holding_lock(); } class ObjectIterateScanRootClosure : public BasicOopIterateClosure { @@ -2138,7 +2136,7 @@ GCTracer* ShenandoahHeap::tracer() { } size_t ShenandoahHeap::tlab_used() const { - return _free_set->used(); + return _free_set->used_not_holding_lock(); } bool ShenandoahHeap::try_cancel_gc(GCCause::Cause cause) { @@ -2528,8 +2526,7 @@ void ShenandoahHeap::rebuild_free_set(bool concurrent) { ShenandoahPhaseTimings::final_update_refs_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_update_refs_rebuild_freeset); ShenandoahHeapLocker locker(lock()); - size_t young_cset_regions, old_cset_regions; - size_t first_old_region, last_old_region, old_region_count; + size_t young_cset_regions, old_cset_regions, first_old_region, last_old_region, old_region_count; _free_set->prepare_to_rebuild(young_cset_regions, old_cset_regions, first_old_region, last_old_region, old_region_count); // If there are no old regions, first_old_region will be greater than last_old_region assert((first_old_region > last_old_region) || @@ -2548,13 +2545,14 @@ void ShenandoahHeap::rebuild_free_set(bool concurrent) { // The computation of bytes_of_allocation_runway_before_gc_trigger is quite conservative so consider all of this // available for transfer to old. Note that transfer of humongous regions does not impact available. ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); - size_t allocation_runway = gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_cset_regions); + size_t allocation_runway = + gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_cset_regions); gen_heap->compute_old_generation_balance(allocation_runway, old_cset_regions); // Total old_available may have been expanded to hold anticipated promotions. We trigger if the fragmented available // memory represents more than 16 regions worth of data. Note that fragmentation may increase when we promote regular - // regions in place when many of these regular regions have an abundant amount of available memory within them. Fragmentation - // will decrease as promote-by-copy consumes the available memory within these partially consumed regions. + // regions in place when many of these regular regions have an abundant amount of available memory within them. + // Fragmentation will decrease as promote-by-copy consumes the available memory within these partially consumed regions. // // We consider old-gen to have excessive fragmentation if more than 12.5% of old-gen is free memory that resides // within partially consumed regions of memory. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 0a95ee9f149..849459157b5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -167,7 +167,7 @@ inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, if (len <= (int) ObjArrayMarkingStride*2) { // A few slices only, process directly - array->oop_iterate_range(cl, 0, len); + array->oop_iterate_elements_range(cl, 0, len); } else { int bits = log2i_graceful(len); // Compensate for non-power-of-two arrays, cover the array in excess: @@ -216,7 +216,7 @@ inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, // Process the irregular tail, if present int from = last_idx; if (from < len) { - array->oop_iterate_range(cl, from, len); + array->oop_iterate_elements_range(cl, from, len); } } } @@ -248,7 +248,7 @@ inline void ShenandoahMark::do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, assert (0 < to && to <= len, "to is sane: %d/%d", to, len); #endif - array->oop_iterate_range(cl, from, to); + array->oop_iterate_elements_range(cl, from, to); } template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp index d774a8dba42..81c62ebbda9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp @@ -30,7 +30,7 @@ ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot(ShenandoahFreeSet* free_set) : _free_set(free_set) - , _used_before(free_set->used()) + , _used_before(free_set->used_not_holding_lock()) , _if_before(free_set->internal_fragmentation()) , _ef_before(free_set->external_fragmentation()) { } @@ -38,7 +38,6 @@ ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot(ShenandoahFreeSet* free_set bool ShenandoahMetricsSnapshot::is_good_progress() const { // Under the critical threshold? const size_t free_actual = _free_set->available(); - assert(free_actual != ShenandoahFreeSet::FreeSetUnderConstruction, "Avoid this race"); // ShenandoahCriticalFreeThreshold is expressed as a percentage. We multiply this percentage by 1/100th // of the soft max capacity to determine whether the available memory within the mutator partition of the @@ -52,7 +51,7 @@ bool ShenandoahMetricsSnapshot::is_good_progress() const { } // Freed up enough? - const size_t used_after = _free_set->used(); + const size_t used_after = _free_set->used_not_holding_lock(); const size_t progress_actual = (_used_before > used_after) ? _used_before - used_after : 0; const size_t progress_expected = ShenandoahHeapRegion::region_size_bytes(); const bool prog_used = progress_actual >= progress_expected; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index c7cf013d034..c795eda3d96 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -412,9 +412,12 @@ void ShenandoahOldGeneration::prepare_regions_and_collection_set(bool concurrent ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_rebuild_freeset); + ShenandoahFreeSet* free_set = heap->free_set(); ShenandoahHeapLocker locker(heap->lock()); - size_t young_trash_regions, old_trash_regions; - size_t first_old, last_old, num_old; + + // This is completion of old-gen marking. We rebuild in order to reclaim immediate garbage and to + // prepare for subsequent mixed evacuations. + size_t young_trash_regions, old_trash_regions, first_old, last_old, num_old; heap->free_set()->prepare_to_rebuild(young_trash_regions, old_trash_regions, first_old, last_old, num_old); // At the end of old-gen, we may find that we have reclaimed immediate garbage, allowing a longer allocation runway. // We may also find that we have accumulated canddiate regions for mixed evacuation. If so, we will want to expand diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 15520c47bbc..254483d1923 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -430,18 +430,6 @@ "by thread type (worker or mutator) and evacuation type (young, " \ "old, or promotion.") \ \ - product(uintx, ShenandoahMinYoungPercentage, 20, EXPERIMENTAL, \ - "The minimum percentage of the heap to use for the young " \ - "generation. Heuristics will not adjust the young generation " \ - "to be less than this.") \ - range(0, 100) \ - \ - product(uintx, ShenandoahMaxYoungPercentage, 100, EXPERIMENTAL, \ - "The maximum percentage of the heap to use for the young " \ - "generation. Heuristics will not adjust the young generation " \ - "to be more than this.") \ - range(0, 100) \ - \ product(uintx, ShenandoahCriticalFreeThreshold, 1, EXPERIMENTAL, \ "How much of the heap needs to be free after recovery cycles, " \ "either Degenerated or Full GC to be claimed successful. If this "\ diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp index d6289178ea8..73ced211058 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.cpp +++ b/src/hotspot/share/gc/z/zHeapIterator.cpp @@ -456,7 +456,7 @@ void ZHeapIterator::follow_array_chunk(const ZHeapIteratorContext& context, cons // Follow array chunk ZHeapIteratorOopClosure cl(this, context, obj); - ZIterator::oop_iterate_range(obj, &cl, start, end); + ZIterator::oop_iterate_elements_range(obj, &cl, start, end); } template diff --git a/src/hotspot/share/gc/z/zIterator.hpp b/src/hotspot/share/gc/z/zIterator.hpp index 3a1de049dd0..e048002e52e 100644 --- a/src/hotspot/share/gc/z/zIterator.hpp +++ b/src/hotspot/share/gc/z/zIterator.hpp @@ -41,7 +41,7 @@ public: static void oop_iterate(oop obj, OopClosureT* cl); template - static void oop_iterate_range(objArrayOop obj, OopClosureT* cl, int start, int end); + static void oop_iterate_elements_range(objArrayOop obj, OopClosureT* cl, int start, int end); // This function skips invisible roots template diff --git a/src/hotspot/share/gc/z/zIterator.inline.hpp b/src/hotspot/share/gc/z/zIterator.inline.hpp index fb20a424288..cbfe1a79aaf 100644 --- a/src/hotspot/share/gc/z/zIterator.inline.hpp +++ b/src/hotspot/share/gc/z/zIterator.inline.hpp @@ -66,9 +66,9 @@ void ZIterator::oop_iterate(oop obj, OopClosureT* cl) { } template -void ZIterator::oop_iterate_range(objArrayOop obj, OopClosureT* cl, int start, int end) { +void ZIterator::oop_iterate_elements_range(objArrayOop obj, OopClosureT* cl, int start, int end) { assert(!is_invisible_object_array(obj), "not safe"); - obj->oop_iterate_range(cl, start, end); + obj->oop_iterate_elements_range(cl, start, end); } template diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index b09a89594ad..d9892f80b6f 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" +#include "jfr/recorder/service/jfrRecorderService.hpp" #include "jfr/support/jfrClassDefineEvent.hpp" #include "jfr/support/jfrKlassExtension.hpp" #include "jfr/support/jfrResolution.hpp" @@ -43,6 +44,7 @@ #include "runtime/java.hpp" #include "runtime/javaThread.hpp" + bool Jfr::is_enabled() { return JfrRecorder::is_enabled(); } @@ -153,9 +155,9 @@ void Jfr::on_resolution(const Method* caller, const Method* target, TRAPS) { } #endif -void Jfr::on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown, bool halt) { +void Jfr::on_vm_shutdown(bool exception_handler /* false */, bool halt /* false */, bool oom /* false */) { if (!halt && JfrRecorder::is_recording()) { - JfrEmergencyDump::on_vm_shutdown(emit_old_object_samples, emit_event_shutdown); + JfrEmergencyDump::on_vm_shutdown(exception_handler, oom); } } @@ -173,6 +175,12 @@ bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* de return JfrOptionSet::parse_start_flight_recording_option(option, delimiter); } +void Jfr::on_report_java_out_of_memory() { + if (CrashOnOutOfMemoryError && JfrRecorder::is_recording()) { + JfrRecorderService::emit_leakprofiler_events_on_oom(); + } +} + #if INCLUDE_CDS void Jfr::on_restoration(const Klass* k, JavaThread* jt) { assert(k != nullptr, "invariant"); diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index db567cc9a29..ac6a232dda1 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ class Jfr : AllStatic { static void on_resolution(const Method* caller, const Method* target, TRAPS); static void on_java_thread_start(JavaThread* starter, JavaThread* startee); static void on_set_current_thread(JavaThread* jt, oop thread); - static void on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown, bool halt = false); + static void on_vm_shutdown(bool exception_handler = false, bool halt = false, bool oom = false); static void on_vm_error_report(outputStream* st); static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter); static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter); @@ -79,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_report_java_out_of_memory(); CDS_ONLY(static void on_restoration(const Klass* k, JavaThread* jt);) }; diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 6a1146587bc..885484020bd 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" -#ifdef LINUX -#include "os_linux.hpp" -#include "osContainer_linux.hpp" -#endif #define NO_TRANSITION(result_type, header) extern "C" { result_type JNICALL header { #define NO_TRANSITION_END } } @@ -364,8 +360,7 @@ JVM_ENTRY_NO_ENV(void, jfr_set_force_instrumentation(JNIEnv* env, jclass jvm, jb JVM_END NO_TRANSITION(void, jfr_emit_old_object_samples(JNIEnv* env, jclass jvm, jlong cutoff_ticks, jboolean emit_all, jboolean skip_bfs)) - JfrRecorderService service; - service.emit_leakprofiler_events(cutoff_ticks, emit_all == JNI_TRUE, skip_bfs == JNI_TRUE); + JfrRecorderService::emit_leakprofiler_events(cutoff_ticks, emit_all == JNI_TRUE, skip_bfs == JNI_TRUE); NO_TRANSITION_END JVM_ENTRY_NO_ENV(void, jfr_exclude_thread(JNIEnv* env, jclass jvm, jobject t)) @@ -401,35 +396,18 @@ JVM_ENTRY_NO_ENV(jboolean, jfr_is_class_instrumented(JNIEnv* env, jclass jvm, jc JVM_END JVM_ENTRY_NO_ENV(jboolean, jfr_is_containerized(JNIEnv* env, jclass jvm)) -#ifdef LINUX - return OSContainer::is_containerized(); -#else - return false; -#endif + return os::is_containerized(); JVM_END JVM_ENTRY_NO_ENV(jlong, jfr_host_total_memory(JNIEnv* env, jclass jvm)) -#ifdef LINUX - // We want the host memory, not the container limit. - // os::physical_memory() would return the container limit. - return static_cast(os::Linux::physical_memory()); -#else - return static_cast(os::physical_memory()); -#endif + return static_cast(os::Machine::physical_memory()); JVM_END JVM_ENTRY_NO_ENV(jlong, jfr_host_total_swap_memory(JNIEnv* env, jclass jvm)) -#ifdef LINUX - // We want the host swap memory, not the container value. - physical_memory_size_type host_swap = 0; - (void)os::Linux::host_swap(host_swap); // Discard return value and treat as no swap - return static_cast(host_swap); -#else physical_memory_size_type total_swap_space = 0; // Return value ignored - defaulting to 0 on failure. - (void)os::total_swap_space(total_swap_space); + (void)os::Machine::total_swap_space(total_swap_space); return static_cast(total_swap_space); -#endif JVM_END JVM_ENTRY_NO_ENV(void, jfr_emit_data_loss(JNIEnv* env, jclass jvm, jlong bytes)) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp index 7e7747ba396..0a8b3975139 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -232,41 +232,50 @@ void JfrSamplerThread::task_stacktrace(JfrSampleRequestType type, JavaThread** l JavaThread* start = nullptr; elapsedTimer sample_time; sample_time.start(); - ThreadsListHandle tlh; - // Resolve a sample session relative start position index into the thread list array. - // In cases where the last sampled thread is null or not-null but stale, find_index() returns -1. - _cur_index = tlh.list()->find_index_of_JavaThread(*last_thread); - JavaThread* current = _cur_index != -1 ? *last_thread : nullptr; + { + /* + * Take the Threads_lock for three purposes: + * + * 1) Avoid sampling right through a safepoint, + * which could result in touching oops in case of virtual threads. + * 2) Prevent JFR from issuing an epoch rotation while the sampler thread + * is actively processing a thread in state native, as both threads are outside the safepoint protocol. + * 3) Some operating systems (BSD / Mac) require a process lock when sending a signal with pthread_kill. + * Holding the Threads_lock prevents a JavaThread from calling os::create_thread(), which also takes the process lock. + * In a sense, we provide a coarse signal mask, so we can always send the resume signal. + */ + MutexLocker tlock(Threads_lock); + ThreadsListHandle tlh; + // Resolve a sample session relative start position index into the thread list array. + // In cases where the last sampled thread is null or not-null but stale, find_index() returns -1. + _cur_index = tlh.list()->find_index_of_JavaThread(*last_thread); + JavaThread* current = _cur_index != -1 ? *last_thread : nullptr; - while (num_samples < sample_limit) { - current = next_thread(tlh.list(), start, current); - if (current == nullptr) { - break; - } - if (is_excluded(current)) { - continue; - } - if (start == nullptr) { - start = current; // remember the thread where we started to attempt sampling - } - bool success; - if (JAVA_SAMPLE == type) { - success = sample_java_thread(current); - } else { - assert(type == NATIVE_SAMPLE, "invariant"); - success = sample_native_thread(current); - } - if (success) { - num_samples++; - } - if (SafepointSynchronize::is_at_safepoint()) { - // For _thread_in_native, we cannot get the Threads_lock. - // For _thread_in_Java, well, there are none. - break; + while (num_samples < sample_limit) { + current = next_thread(tlh.list(), start, current); + if (current == nullptr) { + break; + } + if (is_excluded(current)) { + continue; + } + if (start == nullptr) { + start = current; // remember the thread where we started to attempt sampling + } + bool success; + if (JAVA_SAMPLE == type) { + success = sample_java_thread(current); + } else { + assert(type == NATIVE_SAMPLE, "invariant"); + success = sample_native_thread(current); + } + if (success) { + num_samples++; + } } + + *last_thread = current; // remember the thread we last attempted to sample } - - *last_thread = current; // remember the thread we last attempted to sample sample_time.stop(); log_trace(jfr)("JFR thread sampling done in %3.7f secs with %d java %d native samples", sample_time.seconds(), type == JAVA_SAMPLE ? num_samples : 0, type == NATIVE_SAMPLE ? num_samples : 0); @@ -297,6 +306,7 @@ class OSThreadSampler : public SuspendedThreadTask { // Sampling a thread in state _thread_in_Java // involves a platform-specific thread suspend and CPU context retrieval. bool JfrSamplerThread::sample_java_thread(JavaThread* jt) { + assert_lock_strong(Threads_lock); if (jt->thread_state() != _thread_in_Java) { return false; } @@ -328,6 +338,7 @@ static JfrSamplerThread* _sampler_thread = nullptr; // without thread suspension and CPU context retrieval, // if we carefully order the loads of the thread state. bool JfrSamplerThread::sample_native_thread(JavaThread* jt) { + assert_lock_strong(Threads_lock); if (jt->thread_state() != _thread_in_native) { return false; } @@ -343,24 +354,14 @@ bool JfrSamplerThread::sample_native_thread(JavaThread* jt) { SafepointMechanism::arm_local_poll_release(jt); - // Take the Threads_lock for two purposes: - // 1) Avoid sampling through a safepoint which could result - // in touching oops in case of virtual threads. - // 2) Prevent JFR from issuing an epoch rotation while the sampler thread - // is actively processing a thread in native, as both threads are now - // outside the safepoint protocol. - - // OrderAccess::fence() as part of acquiring the lock prevents loads from floating up. - JfrMutexTryLock threads_lock(Threads_lock); - - if (!threads_lock.acquired() || !jt->has_last_Java_frame()) { - // Remove the native sample request and release the potentially waiting thread. - JfrSampleMonitor jsm(tl); - return false; + // Separate the arming of the poll (above) from the reading of JavaThread state (below). + if (UseSystemMemoryBarrier) { + SystemMemoryBarrier::emit(); + } else { + OrderAccess::fence(); } - if (jt->thread_state() != _thread_in_native) { - assert_lock_strong(Threads_lock); + if (jt->thread_state() != _thread_in_native || !jt->has_last_Java_frame()) { JfrSampleMonitor jsm(tl); if (jsm.is_waiting()) { // The thread has already returned from native, diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp index 309ae961808..cdebcbcfcb5 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" @@ -460,15 +462,6 @@ static void release_locks(Thread* thread) { assert(thread != nullptr, "invariant"); assert(!thread->is_Java_thread() || JavaThread::cast(thread)->thread_state() == _thread_in_vm, "invariant"); -#ifdef ASSERT - Mutex* owned_lock = thread->owned_locks(); - while (owned_lock != nullptr) { - Mutex* next = owned_lock->next(); - owned_lock->unlock(); - owned_lock = next; - } -#endif // ASSERT - if (Threads_lock->owned_by_self()) { Threads_lock->unlock(); } @@ -550,17 +543,14 @@ class JavaThreadInVMAndNative : public StackObj { } }; -static void post_events(bool emit_old_object_samples, bool emit_event_shutdown, Thread* thread) { - if (emit_old_object_samples) { - LeakProfiler::emit_events(max_jlong, false, false); - } - if (emit_event_shutdown) { +static void post_events(bool exception_handler, bool oom, Thread * thread) { + if (exception_handler) { EventShutdown e; - e.set_reason("VM Error"); + e.set_reason(oom ? "CrashOnOutOfMemoryError" : "VM Error"); e.commit(); } EventDumpReason event; - event.set_reason(emit_old_object_samples ? "Out of Memory" : "Crash"); + event.set_reason(exception_handler && oom ? "CrashOnOutOfMemoryError" : exception_handler ? "Crash" : "Out of Memory"); event.set_recordingId(-1); event.commit(); } @@ -594,20 +584,40 @@ static bool guard_reentrancy() { return false; } -void JfrEmergencyDump::on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown) { +void JfrEmergencyDump::on_vm_shutdown(bool exception_handler, bool oom) { if (!guard_reentrancy()) { return; } + Thread* const thread = Thread::current_or_null_safe(); assert(thread != nullptr, "invariant"); - if (thread->is_Watcher_thread()) { - log_info(jfr, system)("The Watcher thread crashed so no jfr emergency dump will be generated."); - return; - } + // Ensure a JavaThread is _thread_in_vm when we make this call JavaThreadInVMAndNative jtivm(thread); + post_events(exception_handler, oom, thread); + + if (thread->is_Watcher_thread()) { + // We cannot attempt an emergency dump using the Watcher thread + // because we rely on the WatcherThread task "is_error_reported()", + // to exit the VM after a hardcoded timeout, should the relatively + // risky operation of an emergency dump fail (deadlock, livelock). + log_warning(jfr, system) + ("The Watcher thread crashed so no jfr emergency dump will be generated."); + return; + } + + if (thread->is_VM_thread()) { + const VM_Operation* const operation = VMThread::vm_operation(); + if (operation != nullptr && operation->type() == VM_Operation::VMOp_JFROldObject) { + // We will not be able to issue a rotation because the rotation lock + // is held by the JFR Recorder Thread that issued the VM_Operation. + log_warning(jfr, system) + ("The VM Thread crashed as part of emitting leak profiler events so no jfr emergency dump will be generated."); + return; + } + } + release_locks(thread); - post_events(emit_old_object_samples, emit_event_shutdown, thread); // if JavaThread, transition to _thread_in_native to issue a final flushpoint NoHandleMark nhm; diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp index 04c2851a516..b337d73364a 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ class JfrEmergencyDump : AllStatic { static const char* chunk_path(const char* repository_path); static void on_vm_error(const char* repository_path); static void on_vm_error_report(outputStream* st, const char* repository_path); - static void on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown); + static void on_vm_shutdown(bool exception_handler, bool oom); }; #endif // SHARE_JFR_RECORDER_REPOSITORY_JFREMERGENCYDUMP_HPP diff --git a/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp b/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp index a9ba456ad76..6db7a42ab27 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ (MSGBIT(MSG_START)) | \ (MSGBIT(MSG_CLONE_IN_MEMORY)) | \ (MSGBIT(MSG_VM_ERROR)) | \ - (MSGBIT(MSG_FLUSHPOINT)) \ + (MSGBIT(MSG_FLUSHPOINT)) | \ + (MSGBIT(MSG_EMIT_LEAKP_REFCHAINS)) \ ) static JfrPostBox* _instance = nullptr; @@ -165,7 +166,7 @@ void JfrPostBox::notify_waiters() { assert(JfrMsg_lock->owned_by_self(), "incrementing _msg_handled_serial is protected by JfrMsg_lock."); // Update made visible on release of JfrMsg_lock via fence instruction in Monitor::IUnlock. ++_msg_handled_serial; - JfrMsg_lock->notify(); + JfrMsg_lock->notify_all(); } // safeguard to ensure no threads are left waiting diff --git a/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp b/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp index 10457261643..92f70b1dc9b 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ enum JFR_Msg { MSG_SHUTDOWN, MSG_VM_ERROR, MSG_FLUSHPOINT, + MSG_EMIT_LEAKP_REFCHAINS, MSG_NO_OF_MSGS }; @@ -51,23 +52,25 @@ enum JFR_Msg { * * Synchronous messages (posting thread waits for message completion): * - * MSG_CLONE_IN_MEMORY (0) ; MSGBIT(MSG_CLONE_IN_MEMORY) == (1 << 0) == 0x1 - * MSG_START(1) ; MSGBIT(MSG_START) == (1 << 0x1) == 0x2 - * MSG_STOP (2) ; MSGBIT(MSG_STOP) == (1 << 0x2) == 0x4 - * MSG_ROTATE (3) ; MSGBIT(MSG_ROTATE) == (1 << 0x3) == 0x8 - * MSG_VM_ERROR (8) ; MSGBIT(MSG_VM_ERROR) == (1 << 0x8) == 0x100 - * MSG_FLUSHPOINT (9) ; MSGBIT(MSG_FLUSHPOINT) == (1 << 0x9) == 0x200 + * MSG_CLONE_IN_MEMORY (0) ; MSGBIT(MSG_CLONE_IN_MEMORY) == (1 << 0) == 0x1 + * MSG_START(1) ; MSGBIT(MSG_START) == (1 << 0x1) == 0x2 + * MSG_STOP (2) ; MSGBIT(MSG_STOP) == (1 << 0x2) == 0x4 + * MSG_ROTATE (3) ; MSGBIT(MSG_ROTATE) == (1 << 0x3) == 0x8 + * MSG_VM_ERROR (8) ; MSGBIT(MSG_VM_ERROR) == (1 << 0x8) == 0x100 + * MSG_FLUSHPOINT (9) ; MSGBIT(MSG_FLUSHPOINT) == (1 << 0x9) == 0x200 + * MSG_EMIT_LEAKP_REFCHAINS (10); MSGBIT(MSG_EMIT_LEAKP_REFCHAINS) == (1 << 0xa) == 0x400 * * Asynchronous messages (posting thread returns immediately upon deposit): * - * MSG_FULLBUFFER (4) ; MSGBIT(MSG_FULLBUFFER) == (1 << 0x4) == 0x10 - * MSG_CHECKPOINT (5) ; MSGBIT(CHECKPOINT) == (1 << 0x5) == 0x20 - * MSG_WAKEUP (6) ; MSGBIT(WAKEUP) == (1 << 0x6) == 0x40 - * MSG_SHUTDOWN (7) ; MSGBIT(MSG_SHUTDOWN) == (1 << 0x7) == 0x80 + * MSG_FULLBUFFER (4) ; MSGBIT(MSG_FULLBUFFER) == (1 << 0x4) == 0x10 + * MSG_CHECKPOINT (5) ; MSGBIT(CHECKPOINT) == (1 << 0x5) == 0x20 + * MSG_WAKEUP (6) ; MSGBIT(WAKEUP) == (1 << 0x6) == 0x40 + * MSG_SHUTDOWN (7) ; MSGBIT(MSG_SHUTDOWN) == (1 << 0x7) == 0x80 */ class JfrPostBox : public JfrCHeapObj { friend class JfrRecorder; + friend class JfrRecorderService; public: void post(JFR_Msg msg); diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 08250a1ae59..6f8d44fb1a4 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,7 @@ #include "runtime/safepoint.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" +#include "utilities/growableArray.hpp" // incremented on each flushpoint static u8 flushpoint_id = 0; @@ -391,6 +392,7 @@ class JfrSafepointWriteVMOperation : public VM_Operation { JfrRecorderService::JfrRecorderService() : _checkpoint_manager(JfrCheckpointManager::instance()), _chunkwriter(JfrRepository::chunkwriter()), + _post_box(JfrPostBox::instance()), _repository(JfrRepository::instance()), _stack_trace_repository(JfrStackTraceRepository::instance()), _storage(JfrStorage::instance()), @@ -670,17 +672,173 @@ void JfrRecorderService::evaluate_chunk_size_for_rotation() { JfrChunkRotation::evaluate(_chunkwriter); } -void JfrRecorderService::emit_leakprofiler_events(int64_t cutoff_ticks, bool emit_all, bool skip_bfs) { - DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(JavaThread::current())); - // Take the rotation lock to exclude flush() during event emits. This is because event emit - // also creates a number checkpoint events. Those checkpoint events require a future typeset checkpoint - // event for completeness, i.e. to be generated before being flushed to a segment. - // The upcoming flush() or rotation() after event emit completes this typeset checkpoint - // and serializes all event emit checkpoint events to the same segment. - JfrRotationLock lock; - // Take the rotation lock before the transition. - JavaThread* current_thread = JavaThread::current(); - MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); - ThreadInVMfromNative transition(current_thread); - LeakProfiler::emit_events(cutoff_ticks, emit_all, skip_bfs); +// LeakProfiler event serialization support. + +struct JfrLeakProfilerEmitRequest { + int64_t cutoff_ticks; + bool emit_all; + bool skip_bfs; + bool oom; +}; + +typedef GrowableArrayCHeap JfrLeakProfilerEmitRequestQueue; +static JfrLeakProfilerEmitRequestQueue* _queue = nullptr; +constexpr const static int64_t _no_path_to_gc_roots = 0; +static bool _oom_emit_request_posted = false; +static bool _oom_emit_request_delivered = false; + +static inline bool exclude_paths_to_gc_roots(int64_t cutoff_ticks) { + return cutoff_ticks <= _no_path_to_gc_roots; +} + +static void enqueue(const JfrLeakProfilerEmitRequest& request) { + assert(JfrRotationLock::is_owner(), "invariant"); + if (_queue == nullptr) { + _queue = new JfrLeakProfilerEmitRequestQueue(4); + } + assert(_queue != nullptr, "invariant"); + assert(!_oom_emit_request_posted, "invariant"); + if (request.oom) { + _oom_emit_request_posted = true; + } + _queue->append(request); +} + +static JfrLeakProfilerEmitRequest dequeue() { + assert(JfrRotationLock::is_owner(), "invariant"); + assert(_queue != nullptr, "invariant"); + assert(_queue->is_nonempty(), "invariant"); + const JfrLeakProfilerEmitRequest& request = _queue->first(); + _queue->remove_at(0); + return request; +} + +// This version of emit excludes path-to-gc-roots, i.e. it skips reference chains. +static void emit_leakprofiler_events(bool emit_all, bool skip_bfs, JavaThread* jt) { + assert(jt != nullptr, "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); + // Take the rotation lock to exclude flush() during event emits. This is because the event emit operation + // also creates a number of checkpoint events. Those checkpoint events require a future typeset checkpoint + // event for completeness, i.e., to be generated before being flushed to a segment. + // The upcoming flush() or rotation() after event emit completes this typeset checkpoint + // and serializes all checkpoint events to the same segment. + JfrRotationLock lock; + // Take the rotation lock before the thread transition, to avoid blocking safepoints. + if (_oom_emit_request_posted) { + // A request to emit leakprofiler events in response to CrashOnOutOfMemoryError + // is pending or has already been completed. We are about to crash at any time now. + assert(CrashOnOutOfMemoryError, "invariant"); + return; + } + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); + ThreadInVMfromNative transition(jt); + // Since we are not requesting path-to-gc-roots, i.e., reference chains, we need not issue a VM_Operation. + // Therefore, we can let the requesting thread process the request directly, since it already holds the requisite lock. + LeakProfiler::emit_events(_no_path_to_gc_roots, emit_all, skip_bfs); +} + +void JfrRecorderService::transition_and_post_leakprofiler_emit_msg(JavaThread* jt) { + assert(jt != nullptr, "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt);) + assert(!JfrRotationLock::is_owner(), "invariant"); + // Transition to _thread_in_VM and post a synchronous message to the JFR Recorder Thread + // for it to process our enqueued request, which includes paths-to-gc-roots, i.e., reference chains. + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); + ThreadInVMfromNative transition(jt); + _post_box.post(MSG_EMIT_LEAKP_REFCHAINS); +} + +// This version of emit includes path-to-gc-roots, i.e., it includes in the request traversing of reference chains. +// Traversing reference chains is performed as part of a VM_Operation, and we initiate it from the JFR Recorder Thread. +// Because multiple threads can concurrently report_on_java_out_of_memory(), having them all post a synchronous JFR msg, +// they rendezvous at a safepoint in a convenient state, ThreadBlockInVM. This mechanism prevents any thread from racing past +// this point and begin executing VMError::report_and_die(), until at least one oom request has been delivered. +void JfrRecorderService::emit_leakprofiler_events_paths_to_gc_roots(int64_t cutoff_ticks, + bool emit_all, + bool skip_bfs, + bool oom, + JavaThread* jt) { + assert(jt != nullptr, "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt);) + assert(!exclude_paths_to_gc_roots(cutoff_ticks), "invariant"); + + { + JfrRotationLock lock; + // Take the rotation lock to read and post a request for the JFR Recorder Thread. + if (_oom_emit_request_posted) { + if (!oom) { + // A request to emit leakprofiler events in response to CrashOnOutOfMemoryError + // is pending or has already been completed. We are about to crash at any time now. + assert(CrashOnOutOfMemoryError, "invariant"); + return; + } + } else { + assert(!_oom_emit_request_posted, "invariant"); + JfrLeakProfilerEmitRequest request = { cutoff_ticks, emit_all, skip_bfs, oom }; + enqueue(request); + } + } + JfrRecorderService service; + service.transition_and_post_leakprofiler_emit_msg(jt); +} + +// Leakprofiler serialization request, the jdk.jfr.internal.JVM.emitOldObjectSamples() Java entry point. +void JfrRecorderService::emit_leakprofiler_events(int64_t cutoff_ticks, + bool emit_all, + bool skip_bfs) { + JavaThread* const jt = JavaThread::current(); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt);) + if (exclude_paths_to_gc_roots(cutoff_ticks)) { + ::emit_leakprofiler_events(emit_all, skip_bfs, jt); + return; + } + emit_leakprofiler_events_paths_to_gc_roots(cutoff_ticks, emit_all, skip_bfs, /* oom */ false, jt); +} + +// Leakprofiler serialization request, the report_on_java_out_of_memory VM entry point. +void JfrRecorderService::emit_leakprofiler_events_on_oom() { + assert(CrashOnOutOfMemoryError, "invariant"); + if (EventOldObjectSample::is_enabled()) { + JavaThread* const jt = JavaThread::current(); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt);) + ThreadToNativeFromVM transition(jt); + emit_leakprofiler_events_paths_to_gc_roots(max_jlong, false, false, /* oom */ true, jt); + } +} + +// The worker routine for the JFR Recorder Thread when processing MSG_EMIT_LEAKP_REFCHAINS messages. +void JfrRecorderService::emit_leakprofiler_events() { + JavaThread* const jt = JavaThread::current(); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); + // Take the rotation lock before the transition. + JfrRotationLock lock; + if (_oom_emit_request_delivered) { + // A request to emit leakprofiler events in response to CrashOnOutOfMemoryError + // has already been completed. We are about to crash at any time now. + assert(_oom_emit_request_posted, "invariant"); + assert(CrashOnOutOfMemoryError, "invariant"); + return; + } + + assert(_queue->is_nonempty(), "invariant"); + + { + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); + ThreadInVMfromNative transition(jt); + while (_queue->is_nonempty()) { + const JfrLeakProfilerEmitRequest& request = dequeue(); + LeakProfiler::emit_events(request.cutoff_ticks, request.emit_all, request.skip_bfs); + if (_oom_emit_request_posted && request.oom) { + assert(CrashOnOutOfMemoryError, "invariant"); + _oom_emit_request_delivered = true; + break; + } + } + } + + // If processing involved an out-of-memory request, issue an immediate flush operation. + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); + if (_chunkwriter.is_valid() && _oom_emit_request_delivered) { + invoke_flush(); + } } diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp index e5b4500afc0..3759ff98828 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,23 @@ #include "jfr/utilities/jfrAllocation.hpp" +class JavaThread; class JfrCheckpointManager; class JfrChunkWriter; +class JfrPostBox; class JfrRepository; class JfrStackTraceRepository; class JfrStorage; class JfrStringPool; class JfrRecorderService : public StackObj { + friend class Jfr; friend class JfrSafepointClearVMOperation; friend class JfrSafepointWriteVMOperation; private: JfrCheckpointManager& _checkpoint_manager; JfrChunkWriter& _chunkwriter; + JfrPostBox& _post_box; JfrRepository& _repository; JfrStackTraceRepository& _stack_trace_repository; JfrStorage& _storage; @@ -64,6 +68,14 @@ class JfrRecorderService : public StackObj { void invoke_safepoint_write(); void post_safepoint_write(); + void transition_and_post_leakprofiler_emit_msg(JavaThread* jt); + + static void emit_leakprofiler_events_on_oom(); + static void emit_leakprofiler_events_paths_to_gc_roots(int64_t cutoff_ticks, + bool emit_all, + bool skip_bfs, + bool oom, + JavaThread* jt); public: JfrRecorderService(); void start(); @@ -72,8 +84,12 @@ class JfrRecorderService : public StackObj { void flushpoint(); void process_full_buffers(); void evaluate_chunk_size_for_rotation(); - void emit_leakprofiler_events(int64_t cutoff_ticks, bool emit_all, bool skip_bfs); + void emit_leakprofiler_events(); + static bool is_recording(); + static void emit_leakprofiler_events(int64_t cutoff_ticks, + bool emit_all, + bool skip_bfs); }; #endif // SHARE_JFR_RECORDER_SERVICE_JFRRECORDERSERVICE_HPP diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp index de015e9a502..bd01adf5b3a 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ void recorderthread_entry(JavaThread* thread, JavaThread* unused) { #define ROTATE (msgs & (MSGBIT(MSG_ROTATE)|MSGBIT(MSG_STOP))) #define FLUSHPOINT (msgs & (MSGBIT(MSG_FLUSHPOINT))) #define PROCESS_FULL_BUFFERS (msgs & (MSGBIT(MSG_ROTATE)|MSGBIT(MSG_STOP)|MSGBIT(MSG_FULLBUFFER))) + #define LEAKPROFILER_REFCHAINS (msgs & MSGBIT(MSG_EMIT_LEAKP_REFCHAINS)) JfrPostBox& post_box = JfrRecorderThreadEntry::post_box(); log_debug(jfr, system)("Recorder thread STARTED"); @@ -70,6 +71,9 @@ void recorderthread_entry(JavaThread* thread, JavaThread* unused) { if (PROCESS_FULL_BUFFERS) { service.process_full_buffers(); } + if (LEAKPROFILER_REFCHAINS) { + service.emit_leakprofiler_events(); + } // Check amount of data written to chunk already // if it warrants asking for a new chunk. service.evaluate_chunk_size_for_rotation(); @@ -98,5 +102,5 @@ void recorderthread_entry(JavaThread* thread, JavaThread* unused) { #undef ROTATE #undef FLUSHPOINT #undef PROCESS_FULL_BUFFERS - #undef SCAVENGE + #undef LEAKPROFILER_REFCHAINS } diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp index 1432d40e4b2..3d394d10d8b 100644 --- a/src/hotspot/share/jfr/utilities/jfrSet.hpp +++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #ifndef SHARE_JFR_UTILITIES_JFRSET_HPP #define SHARE_JFR_UTILITIES_JFRSET_HPP +#include "cppstdlib/new.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "memory/allocation.hpp" @@ -67,7 +68,9 @@ class JfrSetStorage : public AnyObj { } else { table = NEW_RESOURCE_ARRAY(K, table_size); } - memset(table, 0, table_size * sizeof(K)); + for (unsigned i = 0; i < table_size; ++i) { + ::new (&table[i]) K{}; + } return table; } @@ -88,7 +91,7 @@ class JfrSetStorage : public AnyObj { assert(is_nonempty(), "invariant"); for (unsigned i = 0; i < _table_size; ++i) { K k = _table[i]; - if (k != 0) { + if (k != K{}) { functor(k); } } @@ -136,11 +139,11 @@ class JfrSet : public JfrSetStorage { _resize_threshold = old_table_size; for (unsigned i = 0; i < old_table_size; ++i) { const K k = old_table[i]; - if (k != 0) { + if (k != K{}) { uint32_t idx = slot_idx(CONFIG::hash(k)); do { K v = this->_table[idx]; - if (v == 0) { + if (v == K{}) { this->_table[idx] = k; break; } @@ -161,7 +164,7 @@ class JfrSet : public JfrSetStorage { K* result = nullptr; while (true) { K v = this->_table[idx]; - if (v == 0) { + if (v == K{}) { result = &this->_table[idx]; break; } @@ -196,7 +199,7 @@ class JfrSet : public JfrSetStorage { // Already exists. return false; } - assert(*slot == 0, "invariant"); + assert(*slot == K{}, "invariant"); *slot = k; if (++this->_elements == _resize_threshold) { resize(); diff --git a/src/hotspot/share/oops/objArrayKlass.hpp b/src/hotspot/share/oops/objArrayKlass.hpp index 12db56351ed..cdf28b883e6 100644 --- a/src/hotspot/share/oops/objArrayKlass.hpp +++ b/src/hotspot/share/oops/objArrayKlass.hpp @@ -135,17 +135,16 @@ class ObjArrayKlass : public ArrayKlass { template inline void oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); - // Iterate over oop elements within [start, end), and metadata. - template - inline void oop_oop_iterate_range(objArrayOop a, OopClosureType* closure, int start, int end); - - public: - // Iterate over all oop elements. + // Iterate over all oop elements, and no metadata. template inline void oop_oop_iterate_elements(objArrayOop a, OopClosureType* closure); + // Iterate over oop elements within index range [start, end), and no metadata. + template + inline void oop_oop_iterate_elements_range(objArrayOop a, OopClosureType* closure, int start, int end); + private: - // Iterate over all oop elements with indices within mr. + // Iterate over all oop elements bounded by addresses [low, high), and no metadata. template inline void oop_oop_iterate_elements_bounded(objArrayOop a, OopClosureType* closure, void* low, void* high); diff --git a/src/hotspot/share/oops/objArrayKlass.inline.hpp b/src/hotspot/share/oops/objArrayKlass.inline.hpp index a92c42d21a8..ee559548529 100644 --- a/src/hotspot/share/oops/objArrayKlass.inline.hpp +++ b/src/hotspot/share/oops/objArrayKlass.inline.hpp @@ -38,10 +38,18 @@ template void ObjArrayKlass::oop_oop_iterate_elements(objArrayOop a, OopClosureType* closure) { - T* p = (T*)a->base(); - T* const end = p + a->length(); + oop_oop_iterate_elements_range(a, closure, 0, a->length()); +} - for (;p < end; p++) { +// Like oop_oop_iterate but only iterates over a specified range and only used +// for objArrayOops. +template +void ObjArrayKlass::oop_oop_iterate_elements_range(objArrayOop a, OopClosureType* closure, int start, int end) { + T* base = (T*)a->base(); + T* p = base + start; + T* const end_p = base + end; + + for (;p < end_p; ++p) { Devirtualizer::do_oop(closure, p); } } @@ -98,24 +106,4 @@ void ObjArrayKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, Me oop_oop_iterate_elements_bounded(a, closure, mr.start(), mr.end()); } -// Like oop_oop_iterate but only iterates over a specified range and only used -// for objArrayOops. -template -void ObjArrayKlass::oop_oop_iterate_range(objArrayOop a, OopClosureType* closure, int start, int end) { - T* low = (T*)a->base() + start; - T* high = (T*)a->base() + end; - - oop_oop_iterate_elements_bounded(a, closure, low, high); -} - -// Placed here to resolve include cycle between objArrayKlass.inline.hpp and objArrayOop.inline.hpp -template -void objArrayOopDesc::oop_iterate_range(OopClosureType* blk, int start, int end) { - if (UseCompressedOops) { - ((ObjArrayKlass*)klass())->oop_oop_iterate_range(this, blk, start, end); - } else { - ((ObjArrayKlass*)klass())->oop_oop_iterate_range(this, blk, start, end); - } -} - #endif // SHARE_OOPS_OBJARRAYKLASS_INLINE_HPP diff --git a/src/hotspot/share/oops/objArrayOop.hpp b/src/hotspot/share/oops/objArrayOop.hpp index 82bb41b5fd1..0af059efccf 100644 --- a/src/hotspot/share/oops/objArrayOop.hpp +++ b/src/hotspot/share/oops/objArrayOop.hpp @@ -83,9 +83,9 @@ class objArrayOopDesc : public arrayOopDesc { Klass* element_klass(); public: - // special iterators for index ranges, returns size of object + // Special iterators for an element index range. template - void oop_iterate_range(OopClosureType* blk, int start, int end); + void oop_iterate_elements_range(OopClosureType* blk, int start, int end); }; // See similar requirement for oopDesc. diff --git a/src/hotspot/share/oops/objArrayOop.inline.hpp b/src/hotspot/share/oops/objArrayOop.inline.hpp index 21f95b756de..63295a1459d 100644 --- a/src/hotspot/share/oops/objArrayOop.inline.hpp +++ b/src/hotspot/share/oops/objArrayOop.inline.hpp @@ -29,6 +29,7 @@ #include "oops/access.hpp" #include "oops/arrayOop.hpp" +#include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/globals.hpp" @@ -51,4 +52,13 @@ inline void objArrayOopDesc::obj_at_put(int index, oop value) { HeapAccess::oop_store_at(as_oop(), offset, value); } +template +void objArrayOopDesc::oop_iterate_elements_range(OopClosureType* blk, int start, int end) { + if (UseCompressedOops) { + ((ObjArrayKlass*)klass())->oop_oop_iterate_elements_range(this, blk, start, end); + } else { + ((ObjArrayKlass*)klass())->oop_oop_iterate_elements_range(this, blk, start, end); + } +} + #endif // SHARE_OOPS_OBJARRAYOOP_INLINE_HPP diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 40cd6337c17..e04da430ef0 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -1195,7 +1195,7 @@ const Type* XorLNode::Value(PhaseGVN* phase) const { return AddNode::Value(phase); } -Node* MaxNode::build_min_max_int(Node* a, Node* b, bool is_max) { +Node* MinMaxNode::build_min_max_int(Node* a, Node* b, bool is_max) { if (is_max) { return new MaxINode(a, b); } else { @@ -1203,7 +1203,7 @@ Node* MaxNode::build_min_max_int(Node* a, Node* b, bool is_max) { } } -Node* MaxNode::build_min_max_long(PhaseGVN* phase, Node* a, Node* b, bool is_max) { +Node* MinMaxNode::build_min_max_long(PhaseGVN* phase, Node* a, Node* b, bool is_max) { if (is_max) { return new MaxLNode(phase->C, a, b); } else { @@ -1211,7 +1211,7 @@ Node* MaxNode::build_min_max_long(PhaseGVN* phase, Node* a, Node* b, bool is_max } } -Node* MaxNode::build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, const Type* t, PhaseGVN& gvn) { +Node* MinMaxNode::build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, const Type* t, PhaseGVN& gvn) { bool is_int = gvn.type(a)->isa_int(); assert(is_int || gvn.type(a)->isa_long(), "int or long inputs"); assert(is_int == (gvn.type(b)->isa_int() != nullptr), "inconsistent inputs"); @@ -1243,7 +1243,7 @@ Node* MaxNode::build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, co return res; } -Node* MaxNode::build_min_max_diff_with_zero(Node* a, Node* b, bool is_max, const Type* t, PhaseGVN& gvn) { +Node* MinMaxNode::build_min_max_diff_with_zero(Node* a, Node* b, bool is_max, const Type* t, PhaseGVN& gvn) { bool is_int = gvn.type(a)->isa_int(); assert(is_int || gvn.type(a)->isa_long(), "int or long inputs"); assert(is_int == (gvn.type(b)->isa_int() != nullptr), "inconsistent inputs"); @@ -1290,7 +1290,7 @@ static bool can_overflow(const TypeLong* t, jlong c) { // Let = x_operands and = y_operands. // If x == y and neither add(x, x_off) nor add(y, y_off) overflow, return // add(x, op(x_off, y_off)). Otherwise, return nullptr. -Node* MaxNode::extract_add(PhaseGVN* phase, ConstAddOperands x_operands, ConstAddOperands y_operands) { +Node* MinMaxNode::extract_add(PhaseGVN* phase, ConstAddOperands x_operands, ConstAddOperands y_operands) { Node* x = x_operands.first; Node* y = y_operands.first; int opcode = Opcode(); @@ -1327,7 +1327,7 @@ static ConstAddOperands as_add_with_constant(Node* n) { return ConstAddOperands(x, c_type->is_int()->get_con()); } -Node* MaxNode::IdealI(PhaseGVN* phase, bool can_reshape) { +Node* MinMaxNode::IdealI(PhaseGVN* phase, bool can_reshape) { Node* n = AddNode::Ideal(phase, can_reshape); if (n != nullptr) { return n; @@ -1401,7 +1401,7 @@ Node* MaxINode::Identity(PhaseGVN* phase) { return in(2); } - return MaxNode::Identity(phase); + return MinMaxNode::Identity(phase); } //============================================================================= @@ -1434,7 +1434,7 @@ Node* MinINode::Identity(PhaseGVN* phase) { return in(1); } - return MaxNode::Identity(phase); + return MinMaxNode::Identity(phase); } //------------------------------add_ring--------------------------------------- @@ -1564,7 +1564,7 @@ Node* MaxLNode::Identity(PhaseGVN* phase) { return in(2); } - return MaxNode::Identity(phase); + return MinMaxNode::Identity(phase); } Node* MaxLNode::Ideal(PhaseGVN* phase, bool can_reshape) { @@ -1596,7 +1596,7 @@ Node* MinLNode::Identity(PhaseGVN* phase) { return in(1); } - return MaxNode::Identity(phase); + return MinMaxNode::Identity(phase); } Node* MinLNode::Ideal(PhaseGVN* phase, bool can_reshape) { @@ -1610,7 +1610,7 @@ Node* MinLNode::Ideal(PhaseGVN* phase, bool can_reshape) { return nullptr; } -int MaxNode::opposite_opcode() const { +int MinMaxNode::opposite_opcode() const { if (Opcode() == max_opcode()) { return min_opcode(); } else { @@ -1621,7 +1621,7 @@ int MaxNode::opposite_opcode() const { // Given a redundant structure such as Max/Min(A, Max/Min(B, C)) where A == B or A == C, return the useful part of the structure. // 'operation' is the node expected to be the inner 'Max/Min(B, C)', and 'operand' is the node expected to be the 'A' operand of the outer node. -Node* MaxNode::find_identity_operation(Node* operation, Node* operand) { +Node* MinMaxNode::find_identity_operation(Node* operation, Node* operand) { if (operation->Opcode() == Opcode() || operation->Opcode() == opposite_opcode()) { Node* n1 = operation->in(1); Node* n2 = operation->in(2); @@ -1645,17 +1645,17 @@ Node* MaxNode::find_identity_operation(Node* operation, Node* operand) { return nullptr; } -Node* MaxNode::Identity(PhaseGVN* phase) { +Node* MinMaxNode::Identity(PhaseGVN* phase) { if (in(1) == in(2)) { return in(1); } - Node* identity_1 = MaxNode::find_identity_operation(in(2), in(1)); + Node* identity_1 = MinMaxNode::find_identity_operation(in(2), in(1)); if (identity_1 != nullptr) { return identity_1; } - Node* identity_2 = MaxNode::find_identity_operation(in(1), in(2)); + Node* identity_2 = MinMaxNode::find_identity_operation(in(1), in(2)); if (identity_2 != nullptr) { return identity_2; } diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index 1bbdae92e48..4151ab5d065 100644 --- a/src/hotspot/share/opto/addnode.hpp +++ b/src/hotspot/share/opto/addnode.hpp @@ -324,14 +324,16 @@ public: //------------------------------MaxNode---------------------------------------- // Max (or min) of 2 values. Included with the ADD nodes because it inherits // all the behavior of addition on a ring. -class MaxNode : public AddNode { +class MinMaxNode : public AddNode { private: static Node* build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, const Type* t, PhaseGVN& gvn); static Node* build_min_max_diff_with_zero(Node* a, Node* b, bool is_max, const Type* t, PhaseGVN& gvn); Node* extract_add(PhaseGVN* phase, ConstAddOperands x_operands, ConstAddOperands y_operands); public: - MaxNode( Node *in1, Node *in2 ) : AddNode(in1,in2) {} + MinMaxNode(Node* in1, Node* in2) : AddNode(in1, in2) { + init_class_id(Class_MinMax); + } virtual int Opcode() const = 0; virtual int max_opcode() const = 0; virtual int min_opcode() const = 0; @@ -373,9 +375,9 @@ public: //------------------------------MaxINode--------------------------------------- // Maximum of 2 integers. Included with the ADD nodes because it inherits // all the behavior of addition on a ring. -class MaxINode : public MaxNode { +class MaxINode : public MinMaxNode { public: - MaxINode( Node *in1, Node *in2 ) : MaxNode(in1,in2) {} + MaxINode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring( const Type *, const Type * ) const; virtual const Type *add_id() const { return TypeInt::make(min_jint); } @@ -390,9 +392,9 @@ public: //------------------------------MinINode--------------------------------------- // MINimum of 2 integers. Included with the ADD nodes because it inherits // all the behavior of addition on a ring. -class MinINode : public MaxNode { +class MinINode : public MinMaxNode { public: - MinINode( Node *in1, Node *in2 ) : MaxNode(in1,in2) {} + MinINode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring( const Type *, const Type * ) const; virtual const Type *add_id() const { return TypeInt::make(max_jint); } @@ -406,9 +408,9 @@ public: //------------------------------MaxLNode--------------------------------------- // MAXimum of 2 longs. -class MaxLNode : public MaxNode { +class MaxLNode : public MinMaxNode { public: - MaxLNode(Compile* C, Node* in1, Node* in2) : MaxNode(in1, in2) { + MaxLNode(Compile* C, Node* in1, Node* in2) : MinMaxNode(in1, in2) { init_flags(Flag_is_macro); C->add_macro_node(this); } @@ -425,9 +427,9 @@ public: //------------------------------MinLNode--------------------------------------- // MINimum of 2 longs. -class MinLNode : public MaxNode { +class MinLNode : public MinMaxNode { public: - MinLNode(Compile* C, Node* in1, Node* in2) : MaxNode(in1, in2) { + MinLNode(Compile* C, Node* in1, Node* in2) : MinMaxNode(in1, in2) { init_flags(Flag_is_macro); C->add_macro_node(this); } @@ -444,9 +446,9 @@ public: //------------------------------MaxFNode--------------------------------------- // Maximum of 2 floats. -class MaxFNode : public MaxNode { +class MaxFNode : public MinMaxNode { public: - MaxFNode(Node *in1, Node *in2) : MaxNode(in1, in2) {} + MaxFNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring(const Type*, const Type*) const; virtual const Type *add_id() const { return TypeF::NEG_INF; } @@ -458,9 +460,9 @@ public: //------------------------------MinFNode--------------------------------------- // Minimum of 2 floats. -class MinFNode : public MaxNode { +class MinFNode : public MinMaxNode { public: - MinFNode(Node *in1, Node *in2) : MaxNode(in1, in2) {} + MinFNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring(const Type*, const Type*) const; virtual const Type *add_id() const { return TypeF::POS_INF; } @@ -472,9 +474,9 @@ public: //------------------------------MaxHFNode-------------------------------------- // Maximum of 2 half floats. -class MaxHFNode : public MaxNode { +class MaxHFNode : public MinMaxNode { public: - MaxHFNode(Node* in1, Node* in2) : MaxNode(in1, in2) {} + MaxHFNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type* add_ring(const Type*, const Type*) const; virtual const Type* add_id() const { return TypeH::NEG_INF; } @@ -486,9 +488,9 @@ public: //------------------------------MinHFNode--------------------------------------- // Minimum of 2 half floats. -class MinHFNode : public MaxNode { +class MinHFNode : public MinMaxNode { public: - MinHFNode(Node* in1, Node* in2) : MaxNode(in1, in2) {} + MinHFNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type* add_ring(const Type*, const Type*) const; virtual const Type* add_id() const { return TypeH::POS_INF; } @@ -500,9 +502,9 @@ public: //------------------------------MaxDNode--------------------------------------- // Maximum of 2 doubles. -class MaxDNode : public MaxNode { +class MaxDNode : public MinMaxNode { public: - MaxDNode(Node *in1, Node *in2) : MaxNode(in1, in2) {} + MaxDNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring(const Type*, const Type*) const; virtual const Type *add_id() const { return TypeD::NEG_INF; } @@ -514,9 +516,9 @@ public: //------------------------------MinDNode--------------------------------------- // Minimum of 2 doubles. -class MinDNode : public MaxNode { +class MinDNode : public MinMaxNode { public: - MinDNode(Node *in1, Node *in2) : MaxNode(in1, in2) {} + MinDNode(Node* in1, Node* in2) : MinMaxNode(in1, in2) {} virtual int Opcode() const; virtual const Type *add_ring(const Type*, const Type*) const; virtual const Type *add_id() const { return TypeD::POS_INF; } diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 7b5c3855a9e..792384b1ec1 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1058,6 +1058,39 @@ void ConnectionGraph::updates_after_load_split(Node* data_phi, Node* previous_lo // "new_load" might actually be a constant, parameter, etc. if (new_load->is_Load()) { Node* new_addp = new_load->in(MemNode::Address); + + // If new_load is a Load but not from an AddP, it means that the load is folded into another + // load. And since this load is not from a field, we cannot create a unique type for it. + // For example: + // + // if (b) { + // Holder h1 = new Holder(); + // Object o = ...; + // h.o = o.getClass(); + // } else { + // Holder h2 = ...; + // } + // Holder h = Phi(h1, h2); + // Object r = h.o; + // + // Then, splitting r through the merge point results in: + // + // if (b) { + // Holder h1 = new Holder(); + // Object o = ...; + // h.o = o.getClass(); + // Object o1 = h.o; + // } else { + // Holder h2 = ...; + // Object o2 = h2.o; + // } + // Object r = Phi(o1, o2); + // + // In this case, o1 is folded to o.getClass() which is a Load but not from an AddP, but from + // an OopHandle that is loaded from the Klass of o. + if (!new_addp->is_AddP()) { + continue; + } Node* base = get_addp_base(new_addp); // The base might not be something that we can create an unique diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index dacc1a1a734..8dc34af9c19 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -979,9 +979,9 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { Node* inner_iters_max = nullptr; if (stride_con > 0) { - inner_iters_max = MaxNode::max_diff_with_zero(limit, outer_phi, TypeInteger::bottom(bt), _igvn); + inner_iters_max = MinMaxNode::max_diff_with_zero(limit, outer_phi, TypeInteger::bottom(bt), _igvn); } else { - inner_iters_max = MaxNode::max_diff_with_zero(outer_phi, limit, TypeInteger::bottom(bt), _igvn); + inner_iters_max = MinMaxNode::max_diff_with_zero(outer_phi, limit, TypeInteger::bottom(bt), _igvn); } Node* inner_iters_limit = _igvn.integercon(iters_limit, bt); @@ -989,7 +989,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { // Long.MIN_VALUE to Long.MAX_VALUE for instance). Use an unsigned // min. const TypeInteger* inner_iters_actual_range = TypeInteger::make(0, iters_limit, Type::WidenMin, bt); - Node* inner_iters_actual = MaxNode::unsigned_min(inner_iters_max, inner_iters_limit, inner_iters_actual_range, _igvn); + Node* inner_iters_actual = MinMaxNode::unsigned_min(inner_iters_max, inner_iters_limit, inner_iters_actual_range, _igvn); Node* inner_iters_actual_int; if (bt == T_LONG) { @@ -1618,7 +1618,7 @@ void PhaseIdealLoop::transform_long_range_checks(int stride_con, const Node_List Node* max_jint_plus_one_long = longcon((jlong)max_jint + 1); Node* max_range = new AddLNode(max_jint_plus_one_long, L); register_new_node(max_range, entry_control); - R = MaxNode::unsigned_min(R, max_range, TypeLong::POS, _igvn); + R = MinMaxNode::unsigned_min(R, max_range, TypeLong::POS, _igvn); set_subtree_ctrl(R, true); } @@ -1717,9 +1717,9 @@ void PhaseIdealLoop::transform_long_range_checks(int stride_con, const Node_List } Node* PhaseIdealLoop::clamp(Node* R, Node* L, Node* H) { - Node* min = MaxNode::signed_min(R, H, TypeLong::LONG, _igvn); + Node* min = MinMaxNode::signed_min(R, H, TypeLong::LONG, _igvn); set_subtree_ctrl(min, true); - Node* max = MaxNode::signed_max(L, min, TypeLong::LONG, _igvn); + Node* max = MinMaxNode::signed_max(L, min, TypeLong::LONG, _igvn); set_subtree_ctrl(max, true); return max; } @@ -3485,14 +3485,14 @@ void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) { // the loop body to be run for LoopStripMiningIter. Node* max = nullptr; if (stride > 0) { - max = MaxNode::max_diff_with_zero(limit, iv_phi, TypeInt::INT, *igvn); + max = MinMaxNode::max_diff_with_zero(limit, iv_phi, TypeInt::INT, *igvn); } else { - max = MaxNode::max_diff_with_zero(iv_phi, limit, TypeInt::INT, *igvn); + max = MinMaxNode::max_diff_with_zero(iv_phi, limit, TypeInt::INT, *igvn); } // sub is positive and can be larger than the max signed int // value. Use an unsigned min. Node* const_iters = igvn->intcon(scaled_iters); - Node* min = MaxNode::unsigned_min(max, const_iters, TypeInt::make(0, scaled_iters, Type::WidenMin), *igvn); + Node* min = MinMaxNode::unsigned_min(max, const_iters, TypeInt::make(0, scaled_iters, Type::WidenMin), *igvn); // min is the number of iterations for the next inner loop execution: // unsigned_min(max(limit - iv_phi, 0), scaled_iters) if stride > 0 // unsigned_min(max(iv_phi - limit, 0), scaled_iters) if stride < 0 diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 80818a4ddc7..4df03714376 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2577,11 +2577,11 @@ void PhaseMacroExpand::eliminate_opaque_looplimit_macro_nodes() { // a CMoveL construct now. At least until here, the type could be computed // precisely. CMoveL is not so smart, but we can give it at least the best // type we know abouot n now. - Node* repl = MaxNode::signed_max(n->in(1), n->in(2), _igvn.type(n), _igvn); + Node* repl = MinMaxNode::signed_max(n->in(1), n->in(2), _igvn.type(n), _igvn); _igvn.replace_node(n, repl); success = true; } else if (n->Opcode() == Op_MinL) { - Node* repl = MaxNode::signed_min(n->in(1), n->in(2), _igvn.type(n), _igvn); + Node* repl = MinMaxNode::signed_min(n->in(1), n->in(2), _igvn.type(n), _igvn); _igvn.replace_node(n, repl); success = true; } diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 5b76f5b42cf..0d4fb6791a4 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -3913,7 +3913,6 @@ const Type* SCMemProjNode::Value(PhaseGVN* phase) const LoadStoreNode::LoadStoreNode( Node *c, Node *mem, Node *adr, Node *val, const TypePtr* at, const Type* rt, uint required ) : Node(required), _type(rt), - _adr_type(at), _barrier_data(0) { init_req(MemNode::Control, c ); @@ -3921,6 +3920,7 @@ LoadStoreNode::LoadStoreNode( Node *c, Node *mem, Node *adr, Node *val, const Ty init_req(MemNode::Address, adr); init_req(MemNode::ValueIn, val); init_class_id(Class_LoadStore); + DEBUG_ONLY(_adr_type = at; adr_type();) } //------------------------------Value----------------------------------------- @@ -3944,6 +3944,11 @@ const Type* LoadStoreNode::Value(PhaseGVN* phase) const { return bottom_type(); } +const TypePtr* LoadStoreNode::adr_type() const { + const TypePtr* cross_check = DEBUG_ONLY(_adr_type) NOT_DEBUG(nullptr); + return MemNode::calculate_adr_type(in(MemNode::Address)->bottom_type(), cross_check); +} + uint LoadStoreNode::ideal_reg() const { return _type->ideal_reg(); } diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index d554c037012..e84556528e6 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -797,11 +797,6 @@ public: virtual int Opcode() const; virtual bool is_CFG() const { return false; } virtual const Type *bottom_type() const {return Type::MEMORY;} - virtual const TypePtr *adr_type() const { - Node* ctrl = in(0); - if (ctrl == nullptr) return nullptr; // node is dead - return ctrl->in(MemNode::Memory)->adr_type(); - } virtual uint ideal_reg() const { return 0;} // memory projections don't have a register virtual const Type* Value(PhaseGVN* phase) const; #ifndef PRODUCT @@ -814,9 +809,11 @@ public: class LoadStoreNode : public Node { private: const Type* const _type; // What kind of value is loaded? - const TypePtr* _adr_type; // What kind of memory is being addressed? uint8_t _barrier_data; // Bit field with barrier information virtual uint size_of() const; // Size is bigger +#ifdef ASSERT + const TypePtr* _adr_type; // What kind of memory is being addressed? +#endif // ASSERT public: LoadStoreNode( Node *c, Node *mem, Node *adr, Node *val, const TypePtr* at, const Type* rt, uint required ); virtual bool depends_only_on_test() const { return false; } @@ -824,7 +821,7 @@ public: virtual const Type *bottom_type() const { return _type; } virtual uint ideal_reg() const; - virtual const class TypePtr *adr_type() const { return _adr_type; } // returns bottom_type of address + virtual const TypePtr* adr_type() const; virtual const Type* Value(PhaseGVN* phase) const; bool result_not_used() const; diff --git a/src/hotspot/share/opto/movenode.cpp b/src/hotspot/share/opto/movenode.cpp index 66db1df339b..6b6becb434f 100644 --- a/src/hotspot/share/opto/movenode.cpp +++ b/src/hotspot/share/opto/movenode.cpp @@ -271,9 +271,9 @@ Node* CMoveNode::Ideal_minmax(PhaseGVN* phase, CMoveNode* cmove) { // Create the Min/Max node based on the type and kind if (cmp_op == Op_CmpL) { - return MaxNode::build_min_max_long(phase, cmp_l, cmp_r, is_max); + return MinMaxNode::build_min_max_long(phase, cmp_l, cmp_r, is_max); } else { - return MaxNode::build_min_max_int(cmp_l, cmp_r, is_max); + return MinMaxNode::build_min_max_int(cmp_l, cmp_r, is_max); } } diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 0adb2072100..f1d9785a746 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -130,6 +130,7 @@ class MemBarNode; class MemBarStoreStoreNode; class MemNode; class MergeMemNode; +class MinMaxNode; class MoveNode; class MulNode; class MultiNode; @@ -809,6 +810,7 @@ public: DEFINE_CLASS_ID(AddP, Node, 9) DEFINE_CLASS_ID(BoxLock, Node, 10) DEFINE_CLASS_ID(Add, Node, 11) + DEFINE_CLASS_ID(MinMax, Add, 0) DEFINE_CLASS_ID(Mul, Node, 12) DEFINE_CLASS_ID(ClearArray, Node, 14) DEFINE_CLASS_ID(Halt, Node, 15) @@ -986,6 +988,7 @@ public: DEFINE_CLASS_QUERY(MemBar) DEFINE_CLASS_QUERY(MemBarStoreStore) DEFINE_CLASS_QUERY(MergeMem) + DEFINE_CLASS_QUERY(MinMax) DEFINE_CLASS_QUERY(Move) DEFINE_CLASS_QUERY(Mul) DEFINE_CLASS_QUERY(Multi) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 1e4cd42e09a..52badca8050 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -762,26 +762,36 @@ bool PhaseGVN::is_dominator_helper(Node *d, Node *n, bool linear_only) { //------------------------------dead_loop_check-------------------------------- // Check for a simple dead loop when a data node references itself directly // or through an other data node excluding cons and phis. -void PhaseGVN::dead_loop_check( Node *n ) { - // Phi may reference itself in a loop - if (n != nullptr && !n->is_dead_loop_safe() && !n->is_CFG()) { - // Do 2 levels check and only data inputs. - bool no_dead_loop = true; - uint cnt = n->req(); - for (uint i = 1; i < cnt && no_dead_loop; i++) { - Node *in = n->in(i); - if (in == n) { - no_dead_loop = false; - } else if (in != nullptr && !in->is_dead_loop_safe()) { - uint icnt = in->req(); - for (uint j = 1; j < icnt && no_dead_loop; j++) { - if (in->in(j) == n || in->in(j) == in) - no_dead_loop = false; - } +void PhaseGVN::dead_loop_check(Node* n) { + // Phi may reference itself in a loop. + if (n == nullptr || n->is_dead_loop_safe() || n->is_CFG()) { + return; + } + + // Do 2 levels check and only data inputs. + for (uint i = 1; i < n->req(); i++) { + Node* in = n->in(i); + if (in == n) { + n->dump_bfs(100, nullptr, ""); + fatal("Dead loop detected, node references itself: %s (%d)", + n->Name(), n->_idx); + } + + if (in == nullptr || in->is_dead_loop_safe()) { + continue; + } + for (uint j = 1; j < in->req(); j++) { + if (in->in(j) == n) { + n->dump_bfs(100, nullptr, ""); + fatal("Dead loop detected, node input references current node: %s (%d) -> %s (%d)", + in->Name(), in->_idx, n->Name(), n->_idx); + } + if (in->in(j) == in) { + n->dump_bfs(100, nullptr, ""); + fatal("Dead loop detected, node input references itself: %s (%d)", + in->Name(), in->_idx); } } - if (!no_dead_loop) { n->dump_bfs(100, nullptr, ""); } - assert(no_dead_loop, "dead loop detected"); } } @@ -2623,6 +2633,15 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ } } } + // Check for Max/Min(A, Max/Min(B, C)) where A == B or A == C + if (use->is_MinMax()) { + for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { + Node* u = use->fast_out(i2); + if (u->Opcode() == use->Opcode()) { + worklist.push(u); + } + } + } auto enqueue_init_mem_projs = [&](ProjNode* proj) { add_users_to_worklist0(proj, worklist); }; diff --git a/src/hotspot/share/opto/rangeinference.hpp b/src/hotspot/share/opto/rangeinference.hpp index ebfd98ca4a6..66ea741a2da 100644 --- a/src/hotspot/share/opto/rangeinference.hpp +++ b/src/hotspot/share/opto/rangeinference.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,7 +147,7 @@ public: static const Type* int_type_xmeet(const CT* i1, const Type* t2); template - static CTP int_type_union(CTP t1, CTP t2) { + static auto 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; @@ -209,7 +209,7 @@ public: 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) { + static TypeIntMirror make(const TypeIntPrototype& t, int widen = 0) { 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, @@ -217,11 +217,15 @@ public: canonicalized_t._data._bits}; } + TypeIntMirror meet(const TypeIntMirror& o) const { + return TypeIntHelper::int_type_union(this, &o); + } + // 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. + static TypeIntMirror make(const TypeIntMirror& t, int widen); 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; @@ -322,7 +326,7 @@ private: // Infer a result given the input types of a binary operation template static CTP infer_binary(CTP t1, CTP t2, Inference infer) { - CTP res; + TypeIntMirror, U> res; bool is_init = false; SimpleIntervalIterable t1_simple_intervals(t1); @@ -330,10 +334,10 @@ private: for (auto& st1 : t1_simple_intervals) { for (auto& st2 : t2_simple_intervals) { - CTP current = infer(st1, st2); + TypeIntMirror, U> current = infer(st1, st2); if (is_init) { - res = res->meet(current)->template cast>(); + res = res.meet(current); } else { is_init = true; res = current; @@ -342,7 +346,22 @@ private: } assert(is_init, "must be initialized"); - return res; + // It is important that widen is computed on the whole result instead of during each step. This + // is because we normalize the widen of small Type instances to 0, so computing the widen value + // for each step and taking the union of them may return a widen value that conflicts with + // other computations, trigerring the monotonicity assert during CCP. + // + // For example, let us consider the operation r = x ^ y: + // - During the first step of CCP, type(x) = {0}, type(y) = [-2, 2], w = 3. + // Since x is a constant that is the identity element of the xor operation, type(r) = type(y) = [-2, 2], w = 3 + // - During the second step, type(x) is widened to [0, 2], w = 0. + // We then compute the range for: + // r1 = x ^ y1, type(x) = [0, 2], w = 0, type(y1) = [0, 2], w = 0 + // r2 = x ^ y2, type(x) = [0, 2], w = 0, type(y2) = [-2, -1], w = 0 + // This results in type(r1) = [0, 3], w = 0, and type(r2) = [-4, -1], w = 0 + // So the union of type(r1) and type(r2) is [-4, 3], w = 0. This widen value is smaller than + // that of the previous step, triggering the monotonicity assert. + return CT::make(res, MAX2(t1->_widen, t2->_widen)); } public: @@ -357,7 +376,7 @@ public: 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)); + return TypeIntMirror, U>::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}); }); } @@ -372,7 +391,7 @@ public: 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)); + return TypeIntMirror, U>::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}); }); } @@ -385,7 +404,7 @@ public: 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)); + return TypeIntMirror, U>::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}); }); } }; diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 73e2ba0045a..285b4984cd1 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -799,6 +799,9 @@ public: 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(); } + static const TypeInt* make(const TypeIntMirror& t, int widen) { + return (new TypeInt(TypeIntPrototype{{t._lo, t._hi}, {t._ulo, t._uhi}, t._bits}, widen, false))->hashcons()->is_int(); + } // Check for single integer bool is_con() const { return _lo == _hi; } @@ -881,6 +884,9 @@ public: 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(); } + static const TypeLong* make(const TypeIntMirror& t, int widen) { + return (new TypeLong(TypeIntPrototype{{t._lo, t._hi}, {t._ulo, t._uhi}, t._bits}, widen, false))->hashcons()->is_long(); + } // Check for single integer bool is_con() const { return _lo == _hi; } diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 1755b0453eb..8e0ca927a16 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -1122,7 +1122,7 @@ Node* make_last(Node* initL, jint stride, Node* limitL, PhaseIdealLoop* phase) { Node* last = new AddLNode(initL, k_mul_stride); // Make sure that the last does not lie "before" init. - Node* last_clamped = MaxNode::build_min_max_long(&igvn, initL, last, stride > 0); + Node* last_clamped = MinMaxNode::build_min_max_long(&igvn, initL, last, stride > 0); phase->register_new_node_with_ctrl_of(diffL, initL); phase->register_new_node_with_ctrl_of(diffL_m1, initL); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index ef5aca96a57..6d6937a97e9 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +115,6 @@ #if INCLUDE_MANAGEMENT #include "services/finalizerService.hpp" #endif -#ifdef LINUX -#include "osContainer_linux.hpp" -#endif #include @@ -500,11 +497,9 @@ JVM_LEAF(jboolean, JVM_IsUseContainerSupport(void)) JVM_END JVM_LEAF(jboolean, JVM_IsContainerized(void)) -#ifdef LINUX - if (OSContainer::is_containerized()) { + if (os::is_containerized()) { return JNI_TRUE; } -#endif return JNI_FALSE; JVM_END diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 1c2f5527ff9..de5bc9ea58f 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,7 +129,6 @@ #ifdef LINUX #include "cgroupSubsystem_linux.hpp" #include "os_linux.hpp" -#include "osContainer_linux.hpp" #endif #define CHECK_JNI_EXCEPTION_(env, value) \ @@ -2582,14 +2581,12 @@ WB_ENTRY(jboolean, WB_CheckLibSpecifiesNoexecstack(JNIEnv* env, jobject o, jstri WB_END WB_ENTRY(jboolean, WB_IsContainerized(JNIEnv* env, jobject o)) - LINUX_ONLY(return OSContainer::is_containerized();) - return false; + return os::is_containerized(); WB_END // Physical memory of the host machine (including containers) WB_ENTRY(jlong, WB_HostPhysicalMemory(JNIEnv* env, jobject o)) - LINUX_ONLY(return static_cast(os::Linux::physical_memory());) - return static_cast(os::physical_memory()); + return static_cast(os::Machine::physical_memory()); WB_END // Available memory of the host machine (container-aware) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index cf0a1ab9757..546ae610769 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "runtime/vm_version.hpp" #include "services/management.hpp" #include "utilities/align.hpp" -#include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" @@ -1207,16 +1206,22 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, } char token[1024]; - int pos = 0; + size_t pos = 0; bool in_white_space = true; bool in_comment = false; bool in_quote = false; - int quote_c = 0; + char quote_c = 0; bool result = true; - int c = getc(stream); - while(c != EOF && pos < (int)(sizeof(token)-1)) { + int c_or_eof = getc(stream); + while (c_or_eof != EOF && pos < (sizeof(token) - 1)) { + // We have checked the c_or_eof for EOF. getc should only ever return the + // EOF or an unsigned char converted to an int. We cast down to a char to + // avoid the char to int promotions we would otherwise do in the comparisons + // below (which would be incorrect if we ever compared to a non-ascii char), + // and the int to char conversions we would otherwise do in the assignments. + const char c = static_cast(c_or_eof); if (in_white_space) { if (in_comment) { if (c == '\n') in_comment = false; @@ -1224,7 +1229,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, if (c == '#') in_comment = true; else if (!isspace((unsigned char) c)) { in_white_space = false; - token[pos++] = checked_cast(c); + token[pos++] = c; } } } else { @@ -1244,10 +1249,10 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, } else if (in_quote && (c == quote_c)) { in_quote = false; } else { - token[pos++] = checked_cast(c); + token[pos++] = c; } } - c = getc(stream); + c_or_eof = getc(stream); } if (pos > 0) { token[pos] = '\0'; diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index c49a9f5d4b8..ee4f776df06 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -466,10 +466,7 @@ void before_exit(JavaThread* thread, bool halt) { event.commit(); } - // 2nd argument (emit_event_shutdown) should be set to false - // because EventShutdown would be emitted at Threads::destroy_vm(). - // (one of the callers of before_exit()) - JFR_ONLY(Jfr::on_vm_shutdown(true, false, halt);) + JFR_ONLY(Jfr::on_vm_shutdown(false, halt);) // Stop the WatcherThread. We do this before disenrolling various // PeriodicTasks to reduce the likelihood of races. diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index cf18388c625..1c06bf3c521 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,10 +81,6 @@ #include "utilities/permitForbiddenFunctions.hpp" #include "utilities/powerOfTwo.hpp" -#ifdef LINUX -#include "osContainer_linux.hpp" -#endif - #ifndef _WINDOWS # include #endif @@ -2205,11 +2201,14 @@ static void assert_nonempty_range(const char* addr, size_t bytes) { } bool os::used_memory(physical_memory_size_type& value) { -#ifdef LINUX - if (OSContainer::is_containerized()) { - return OSContainer::memory_usage_in_bytes(value); + if (is_containerized()) { + return Container::used_memory(value); } -#endif + + return Machine::used_memory(value); +} + +bool os::Machine::used_memory(physical_memory_size_type& value) { physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); @@ -2218,6 +2217,44 @@ bool os::used_memory(physical_memory_size_type& value) { return true; } +#ifndef LINUX +bool os::is_containerized() { + return false; +} + +bool os::Container::processor_count(double& value) { + return false; +} + +bool os::Container::available_memory(physical_memory_size_type& value) { + return false; +} + +bool os::Container::used_memory(physical_memory_size_type& value) { + return false; +} + +bool os::Container::total_swap_space(physical_memory_size_type& value) { + return false; +} + +bool os::Container::free_swap_space(physical_memory_size_type& value) { + return false; +} + +bool os::Container::memory_limit(physical_memory_size_type& value) { + return false; +} + +bool os::Container::memory_soft_limit(physical_memory_size_type& value) { + return false; +} + +bool os::Container::memory_throttle_limit(physical_memory_size_type& value) { + return false; +} +#endif + bool os::commit_memory(char* addr, size_t bytes, bool executable) { assert_nonempty_range(addr, bytes); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index d585d3e5fc0..29c872157fd 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -342,6 +342,52 @@ class os: AllStatic { static bool is_server_class_machine(); static size_t rss(); + // On platforms with container support (currently only Linux) we combine machine values with + // potential container values in os:: methods, abstracting which value is actually used. + // The os::Machine and os::Container classes and containing methods are used to get machine + // and container values (when available) separately. + static bool is_containerized(); + + // The os::Machine class reports system resource metrics from the perspective of the operating + // system, without considering container-imposed limits. The values returned by these methods + // reflect the resources visible to the process as reported by the OS, and may already be + // affected by mechanisms such as virtualization, hypervisor limits, or process affinity, + // but do NOT consider further restrictions imposed by container runtimes (e.g., cgroups) + class Machine : AllStatic { + public: + static int active_processor_count(); + + [[nodiscard]] static bool available_memory(physical_memory_size_type& value); + [[nodiscard]] static bool used_memory(physical_memory_size_type& value); + [[nodiscard]] static bool free_memory(physical_memory_size_type& value); + + [[nodiscard]] static bool total_swap_space(physical_memory_size_type& value); + [[nodiscard]] static bool free_swap_space(physical_memory_size_type& value); + + static physical_memory_size_type physical_memory(); + }; + + // The os::Container class reports resource limits as imposed by a supported container runtime + // (currently only cgroup-based Linux runtimes). If the process is running inside a + // containerized environment, methods from this class report the effective limits imposed + // by the container, which may be more restrictive than what os::Machine reports. + // Methods return true and set the out-parameter if a limit is found, + // or false if no limit exists or it cannot be determined. + class Container : AllStatic { + public: + [[nodiscard]] static bool processor_count(double& value); // Returns the core-equivalent CPU quota + + [[nodiscard]] static bool available_memory(physical_memory_size_type& value); + [[nodiscard]] static bool used_memory(physical_memory_size_type& value); + + [[nodiscard]] static bool total_swap_space(physical_memory_size_type& value); + [[nodiscard]] static bool free_swap_space(physical_memory_size_type& value); + + [[nodiscard]] static bool memory_limit(physical_memory_size_type& value); + [[nodiscard]] static bool memory_soft_limit(physical_memory_size_type& value); + [[nodiscard]] static bool memory_throttle_limit(physical_memory_size_type& value); + }; + // Returns the id of the processor on which the calling thread is currently executing. // The returned value is guaranteed to be between 0 and (os::processor_count() - 1). static uint processor_id(); diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index f3c08ae62f7..bfbd4727e9a 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -36,6 +36,7 @@ #include "memory/resourceArea.hpp" #include "nmt/memTracker.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.inline.hpp" @@ -82,7 +83,7 @@ Thread::Thread(MemTag mem_tag) { _threads_hazard_ptr = nullptr; _threads_list_ptr = nullptr; _nested_threads_hazard_ptr_cnt = 0; - _rcu_counter = 0; + _rcu_counter.store_relaxed(0); // the handle mark links itself to last_handle_mark new HandleMark(this); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 181dfc46f87..dcd6fb2d3fd 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,6 +30,7 @@ #include "gc/shared/threadLocalAllocBuffer.hpp" #include "jni.h" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" @@ -238,9 +239,9 @@ class Thread: public ThreadShadow { // Support for GlobalCounter private: - volatile uintx _rcu_counter; + Atomic _rcu_counter; public: - volatile uintx* get_rcu_counter() { + Atomic* get_rcu_counter() { return &_rcu_counter; } diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index de39fe32dc1..0e1ca1efb98 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +63,17 @@ #include "utilities/nativeStackPrinter.hpp" #include "utilities/unsigned5.hpp" #include "utilities/vmError.hpp" +#if INCLUDE_JFR +#include "jfr/jfr.hpp" +#endif #include #include -// These functions needs to be exported on Windows only -#define DEBUGEXPORT WINDOWS_ONLY(JNIEXPORT) +// These functions needs to be exported on Windows +// On Linux it is also beneficial to export them to avoid +// losing them e.g. with linktime gc +#define DEBUGEXPORT JNIEXPORT // Support for showing register content on asserts/guarantees. #ifdef CAN_SHOW_REGISTERS_ON_ASSERT @@ -262,6 +267,8 @@ void report_untested(const char* file, int line, const char* message) { void report_java_out_of_memory(const char* message) { static int out_of_memory_reported = 0; + JFR_ONLY(Jfr::on_report_java_out_of_memory();) + // A number of threads may attempt to report OutOfMemoryError at around the // same time. To avoid dumping the heap or executing the data collection // commands multiple times we just do it once when the first threads reports @@ -648,13 +655,12 @@ extern "C" DEBUGEXPORT intptr_t u5p(intptr_t addr, void pp(intptr_t p) { pp((void*)p); } void pp(oop p) { pp((void*)p); } -void help() { +extern "C" DEBUGEXPORT void help() { Command c("help"); tty->print_cr("basic"); tty->print_cr(" pp(void* p) - try to make sense of p"); tty->print_cr(" ps() - print current thread stack"); tty->print_cr(" pss() - print all thread stacks"); - tty->print_cr(" pm(int pc) - print Method* given compiled PC"); tty->print_cr(" findnm(intptr_t pc) - find nmethod*"); tty->print_cr(" findm(intptr_t pc) - find Method*"); tty->print_cr(" find(intptr_t x) - find & print nmethod/stub/bytecode/oop based on pointer into it"); diff --git a/src/hotspot/share/utilities/globalCounter.cpp b/src/hotspot/share/utilities/globalCounter.cpp index 7019273d937..114d3b5fed1 100644 --- a/src/hotspot/share/utilities/globalCounter.cpp +++ b/src/hotspot/share/utilities/globalCounter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ */ #include "memory/iterator.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" #include "runtime/threadSMR.inline.hpp" #include "runtime/vmThread.hpp" @@ -41,7 +41,7 @@ class GlobalCounter::CounterThreadCheck : public ThreadClosure { SpinYield yield; // Loops on this thread until it has exited the critical read section. while(true) { - uintx cnt = AtomicAccess::load_acquire(thread->get_rcu_counter()); + uintx cnt = thread->get_rcu_counter()->load_acquire(); // This checks if the thread's counter is active. And if so is the counter // for a pre-existing reader (belongs to this grace period). A pre-existing // reader will have a lower counter than the global counter version for this @@ -57,9 +57,9 @@ class GlobalCounter::CounterThreadCheck : public ThreadClosure { }; void GlobalCounter::write_synchronize() { - assert((*Thread::current()->get_rcu_counter() & COUNTER_ACTIVE) == 0x0, "must be outside a critcal section"); - // AtomicAccess::add must provide fence since we have storeload dependency. - uintx gbl_cnt = AtomicAccess::add(&_global_counter._counter, COUNTER_INCREMENT); + assert((Thread::current()->get_rcu_counter()->load_relaxed() & COUNTER_ACTIVE) == 0x0, "must be outside a critcal section"); + // Atomic add must provide fence since we have storeload dependency. + uintx gbl_cnt = _global_counter._counter.add_then_fetch(COUNTER_INCREMENT); // Do all RCU threads. CounterThreadCheck ctc(gbl_cnt); diff --git a/src/hotspot/share/utilities/globalCounter.hpp b/src/hotspot/share/utilities/globalCounter.hpp index c78831acfa5..80fc1b3e94e 100644 --- a/src/hotspot/share/utilities/globalCounter.hpp +++ b/src/hotspot/share/utilities/globalCounter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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/allStatic.hpp" #include "memory/padded.hpp" +#include "runtime/atomic.hpp" class Thread; @@ -47,7 +48,7 @@ class GlobalCounter : public AllStatic { // counter is on a separate cacheline. struct PaddedCounter { DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0); - volatile uintx _counter; + Atomic _counter; DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(volatile uintx)); }; diff --git a/src/hotspot/share/utilities/globalCounter.inline.hpp b/src/hotspot/share/utilities/globalCounter.inline.hpp index 9cc746173b8..ed37b8a878d 100644 --- a/src/hotspot/share/utilities/globalCounter.inline.hpp +++ b/src/hotspot/share/utilities/globalCounter.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,30 +27,29 @@ #include "utilities/globalCounter.hpp" -#include "runtime/atomicAccess.hpp" +#include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" inline GlobalCounter::CSContext GlobalCounter::critical_section_begin(Thread *thread) { assert(thread == Thread::current(), "must be current thread"); - uintx old_cnt = AtomicAccess::load(thread->get_rcu_counter()); + uintx old_cnt = thread->get_rcu_counter()->load_relaxed(); // Retain the old counter value if already active, e.g. nested. // Otherwise, set the counter to the current version + active bit. uintx new_cnt = old_cnt; if ((new_cnt & COUNTER_ACTIVE) == 0) { - new_cnt = AtomicAccess::load(&_global_counter._counter) | COUNTER_ACTIVE; + new_cnt = _global_counter._counter.load_relaxed() | COUNTER_ACTIVE; } - AtomicAccess::release_store_fence(thread->get_rcu_counter(), new_cnt); + thread->get_rcu_counter()->release_store_fence(new_cnt); return static_cast(old_cnt); } inline void GlobalCounter::critical_section_end(Thread *thread, CSContext context) { assert(thread == Thread::current(), "must be current thread"); - assert((*thread->get_rcu_counter() & COUNTER_ACTIVE) == COUNTER_ACTIVE, "must be in critical section"); + assert((thread->get_rcu_counter()->load_relaxed() & COUNTER_ACTIVE) == COUNTER_ACTIVE, "must be in critical section"); // Restore the counter value from before the associated begin. - AtomicAccess::release_store(thread->get_rcu_counter(), - static_cast(context)); + thread->get_rcu_counter()->release_store(static_cast(context)); } class GlobalCounter::CriticalSection { diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index a290602e0be..88f81b31293 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2024 SAP SE. All rights reserved. * Copyright (c) 2023, 2025, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -1898,7 +1898,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt log.set_fd(-1); } - JFR_ONLY(Jfr::on_vm_shutdown(static_cast(_id) == OOM_JAVA_HEAP_FATAL, true);) + JFR_ONLY(Jfr::on_vm_shutdown(true, false, static_cast(_id) == OOM_JAVA_HEAP_FATAL);) if (PrintNMTStatistics) { fdStream fds(fd_out); diff --git a/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c index efbd0ca5684..54d640b03a4 100644 --- a/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +63,7 @@ Java_sun_nio_ch_FileDispatcherImpl_transferFrom0(JNIEnv *env, jobject this, if (n < 0) { if (errno == EAGAIN) return IOS_UNAVAILABLE; - if (errno == ENOSYS) + if (errno == ENOSYS || errno == EOPNOTSUPP) return IOS_UNSUPPORTED_CASE; if ((errno == EBADF || errno == EINVAL || errno == EXDEV) && ((ssize_t)count >= 0)) @@ -103,6 +103,7 @@ Java_sun_nio_ch_FileDispatcherImpl_transferTo0(JNIEnv *env, jobject this, case EINVAL: case ENOSYS: case EXDEV: + case EOPNOTSUPP: // ignore and try sendfile() break; default: diff --git a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c index c90e99dda07..4677411b0ba 100644 --- a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c +++ b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -193,6 +193,7 @@ Java_sun_nio_fs_LinuxNativeDispatcher_directCopy0 case EINVAL: case ENOSYS: case EXDEV: + case EOPNOTSUPP: // ignore and try sendfile() break; default: diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index a9da1c32490..85ca80735f8 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1448,6 +1448,7 @@ public final class Integer extends Number * @param divisor the value doing the dividing * @return the unsigned quotient of the first argument divided by * the second argument + * @throws ArithmeticException if the divisor is zero * @see #remainderUnsigned * @since 1.8 */ @@ -1466,6 +1467,7 @@ public final class Integer extends Number * @param divisor the value doing the dividing * @return the unsigned remainder of the first argument divided by * the second argument + * @throws ArithmeticException if the divisor is zero * @see #divideUnsigned * @since 1.8 */ diff --git a/src/java.base/share/classes/java/lang/LazyConstant.java b/src/java.base/share/classes/java/lang/LazyConstant.java index 703d67b8abf..85f9d0e82fd 100644 --- a/src/java.base/share/classes/java/lang/LazyConstant.java +++ b/src/java.base/share/classes/java/lang/LazyConstant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +87,8 @@ import java.util.function.Supplier; * is thrown. Hence, a lazy constant can never hold a {@code null} value. Clients who * want to use a nullable constant can wrap the value into an {@linkplain Optional} holder. *

- * If the computing function recursively invokes itself (directly or indirectly via - * the lazy constant), an {@linkplain IllegalStateException} is thrown, and the lazy - * constant is not initialized. + * If the computing function recursively invokes itself via the lazy constant, an + * {@linkplain IllegalStateException} is thrown, and the lazy constant is not initialized. * *

Composing lazy constants

* A lazy constant can depend on other lazy constants, forming a dependency graph diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index c5cd9650f2d..5fa1b8fc2ea 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1411,6 +1411,7 @@ public final class Long extends Number * @param divisor the value doing the dividing * @return the unsigned quotient of the first argument divided by * the second argument + * @throws ArithmeticException if the divisor is zero * @see #remainderUnsigned * @since 1.8 */ @@ -1434,6 +1435,7 @@ public final class Long extends Number * @param divisor the value doing the dividing * @return the unsigned remainder of the first argument divided by * the second argument + * @throws ArithmeticException if the divisor is zero * @see #divideUnsigned * @since 1.8 */ diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 2b931a7d2e0..78098e39a17 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -1354,6 +1354,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if {@code byteLength < 0} + * @since 27 */ String getString(long offset, Charset charset, long byteLength); @@ -2669,6 +2670,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - B} where {@code B} is the size, * in bytes, of the substring of {@code src} encoded using the given charset * @return the number of copied bytes. + * @since 27 */ @ForceInline static long copy(String src, Charset dstEncoding, int srcIndex, MemorySegment dst, long dstOffset, int numChars) { diff --git a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java index 5b213af544f..03d92ec24ef 100644 --- a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java +++ b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java @@ -183,6 +183,7 @@ public interface SegmentAllocator { * {@code this.allocate(B)}, where {@code B} is the size, in bytes, of * the string encoded using the provided charset * (e.g. {@code str.getBytes(charset).length}); + * @since 27 */ @ForceInline default MemorySegment allocateFrom(String str, Charset charset, int srcIndex, int numChars) { diff --git a/src/java.base/share/classes/java/security/CodeSource.java b/src/java.base/share/classes/java/security/CodeSource.java index 7476b8a1d61..9e69b2f0849 100644 --- a/src/java.base/share/classes/java/security/CodeSource.java +++ b/src/java.base/share/classes/java/security/CodeSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,7 +238,12 @@ public class CodeSource implements java.io.Serializable { } else if (certs != null) { // Convert the certs to code signers signers = convertCertArrayToSignerArray(certs); - return signers.clone(); + if (signers != null) { + return signers.clone(); + + } else { + return new CodeSigner[0]; + } } else { return null; diff --git a/src/java.base/share/classes/java/util/List.java b/src/java.base/share/classes/java/util/List.java index 43408de292a..5f9a90e1748 100644 --- a/src/java.base/share/classes/java/util/List.java +++ b/src/java.base/share/classes/java/util/List.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1224,7 +1224,7 @@ public interface List extends SequencedCollection { * The returned list and its {@link List#subList(int, int) subList()} or * {@link List#reversed()} views implement the {@link RandomAccess} interface. *

- * If the provided computing function recursively calls itself or the returned + * If the provided computing function recursively calls itself via the returned * lazy list for the same index, an {@linkplain IllegalStateException} * will be thrown. *

diff --git a/src/java.base/share/classes/java/util/Map.java b/src/java.base/share/classes/java/util/Map.java index 177f0522b1b..fa16fb89050 100644 --- a/src/java.base/share/classes/java/util/Map.java +++ b/src/java.base/share/classes/java/util/Map.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1777,7 +1777,7 @@ public interface Map { * The values of any {@link Map#values()} or {@link Map#entrySet()} views of * the returned map are also lazily computed. *

- * If the provided computing function recursively calls itself or + * If the provided computing function recursively calls itself via * the returned lazy map for the same key, an {@linkplain IllegalStateException} * will be thrown. *

diff --git a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java index ace60e41af9..3c68c669d05 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +64,6 @@ final class SSLConfiguration implements Cloneable { // the configured named groups for the "supported_groups" extensions String[] namedGroups; - // the maximum protocol version of enabled protocols - ProtocolVersion maximumProtocolVersion; - // Configurations per SSLSocket or SSLEngine instance. boolean isClientMode; boolean enableSessionCreation; @@ -249,13 +246,6 @@ final class SSLConfiguration implements Cloneable { CustomizedServerSignatureSchemes.signatureSchemes : SupportedSigSchemes.DEFAULT; this.namedGroups = NamedGroup.SupportedGroups.namedGroups; - this.maximumProtocolVersion = ProtocolVersion.NONE; - for (ProtocolVersion pv : enabledProtocols) { - if (pv.compareTo(maximumProtocolVersion) > 0) { - this.maximumProtocolVersion = pv; - } - } - // Configurations per SSLSocket or SSLEngine instance. this.isClientMode = isClientMode; this.enableSessionCreation = true; @@ -323,13 +313,6 @@ final class SSLConfiguration implements Cloneable { sa = params.getProtocols(); if (sa != null) { this.enabledProtocols = ProtocolVersion.namesOf(sa); - - this.maximumProtocolVersion = ProtocolVersion.NONE; - for (ProtocolVersion pv : enabledProtocols) { - if (pv.compareTo(maximumProtocolVersion) > 0) { - this.maximumProtocolVersion = pv; - } - } } // otherwise, use the default values if (params.getNeedClientAuth()) { diff --git a/src/java.base/share/classes/sun/security/ssl/TransportContext.java b/src/java.base/share/classes/sun/security/ssl/TransportContext.java index 980d9c4a6ce..35bdd2fff36 100644 --- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java +++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +144,6 @@ final class TransportContext implements ConnectionContext { // initial security parameters this.conSession = new SSLSessionImpl(); - this.protocolVersion = this.sslConfig.maximumProtocolVersion; this.clientVerifyData = emptyByteArray; this.serverVerifyData = emptyByteArray; diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 9fb830da338..7f415da5270 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1294,7 +1294,7 @@ public final class Main { } if (alias != null) { - doPrintEntry(rb.getString("the.certificate"), alias, out); + doPrintEntry(alias, out); } else { doPrintEntries(out); } @@ -2177,9 +2177,10 @@ public final class Main { /** * Prints a single keystore entry. */ - private void doPrintEntry(String label, String alias, PrintStream out) + private void doPrintEntry(String alias, PrintStream out) throws Exception { + String label = "<" + alias + ">"; CertPathConstraintsParameters cpcp; if (!keyStore.containsAlias(alias)) { MessageFormat form = new MessageFormat @@ -2631,7 +2632,7 @@ public final class Main { List aliases = Collections.list(keyStore.aliases()); aliases.sort(String::compareTo); for (String alias : aliases) { - doPrintEntry("<" + alias + ">", alias, out); + doPrintEntry(alias, out); if (verbose || rfc) { out.println(rb.getString("NEWLINE")); out.println(rb.getString diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 30661a3f387..956a6aa144b 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1994, 2026, Oracle and/or its affiliates. All rights reserved. # 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,7 +61,7 @@ To launch a source-file program: : Specifies the name of the class to be launched. Command-line entries following `classname` are the arguments for the main method. -`-jar` *jarfile* +[`-jar`]{#-jar} *jarfile* : Executes a program encapsulated in a JAR file. The *jarfile* argument is the name of a JAR file with a manifest that contains a line in the form `Main-Class:`*classname* that defines the class with the @@ -70,7 +70,7 @@ To launch a source-file program: is the source of all user classes, and other class path settings are ignored. If you're using JAR files, then see [jar](jar.html). -`-m` or `--module` *module*\[`/`*mainclass*\] +[`-m`]{#-m} or `--module` *module*\[`/`*mainclass*\] : Executes the main class in a module specified by *mainclass* if it is given, or, if it is not given, the value in the *module*. In other words, *mainclass* can be used when it is not specified by the module, or to @@ -370,7 +370,7 @@ the JVM. > **Note:** To specify an argument for a long option, you can use either `--`*name*`=`*value* or `--`*name* *value*. -`-agentlib:`*libname*\[`=`*options*\] +[`-agentlib:`]{#-agentlib}*libname*\[`=`*options*\] : Loads the specified native agent library. After the library name, a comma-separated list of options specific to the library can be used. If the option `-agentlib:foo` is specified, then the JVM attempts to @@ -393,12 +393,12 @@ the JVM. > `-agentlib:jdwp=transport=dt_socket,server=y,address=8000` -`-agentpath:`*pathname*\[`=`*options*\] +[`-agentpath:`]{#-agentpath}*pathname*\[`=`*options*\] : Loads the native agent library specified by the absolute path name. This option is equivalent to `-agentlib` but uses the full path and file name of the library. -`--class-path` *classpath*, `-classpath` *classpath*, or `-cp` *classpath* +[`--class-path`]{#--class-path} *classpath*, `-classpath` *classpath*, or `-cp` *classpath* : Specifies a list of directories, JAR files, and ZIP archives to search for class files. @@ -424,15 +424,15 @@ the JVM. expanded except by querying the environment, such as by calling `System.getenv("CLASSPATH")`. -`--disable-@files` +[`--disable-@files`]{#--disable-@files} : Can be used anywhere on the command line, including in an argument file, to prevent further `@filename` expansion. This option stops expanding `@`-argfiles after the option. -`--enable-preview` +[`--enable-preview`]{#--enable-preview} : Allows classes to depend on [preview features](https://docs.oracle.com/en/java/javase/12/language/index.html#JSLAN-GUID-5A82FE0E-0CA4-4F1F-B075-564874FE2823) of the release. -`--enable-native-access` *module*\[`,`*module*...\] +[`--enable-native-access`]{#--enable-native-access} *module*\[`,`*module*...\] : Native access involves access to code or data outside the Java runtime. This is generally unsafe and, if done incorrectly, might crash the JVM or result in memory corruption. Native access can occur as a result of calling a method that @@ -465,7 +465,7 @@ the JVM. run it with `--illegal-native-access=deny` along with any necessary `--enable-native-access` options. -`--enable-final-field-mutation` *module*\[,*module*...\] +[`--enable-final-field-mutation`]{#--enable-final-field-mutation} *module*\[,*module*...\] : Mutation of final fields is possible with the reflection API of the Java Platform. However, it compromises safety and performance in all programs. This option allows code in the specified modules to mutate final fields by reflection. @@ -498,13 +498,13 @@ the JVM. run it with `--illegal-final-field-mutation=deny` along with any necessary `--enable-final-field-mutation` options. -`--finalization=`*value* +[`--finalization=`]{#--finalization}*value* : Controls whether the JVM performs finalization of objects. Valid values are "enabled" and "disabled". Finalization is enabled by default, so the value "enabled" does nothing. The value "disabled" disables finalization, so that no finalizers are invoked. -`--module-path` *modulepath*... or `-p` *modulepath* +[`--module-path`]{#--module-path} *modulepath*... or `-p` *modulepath* : Specifies where to find application modules with a list of path elements. The elements of a module path can be a file path to a module or a directory containing modules. Each module is either a modular JAR or an @@ -513,7 +513,7 @@ the JVM. On Windows, semicolons (`;`) separate path elements in this list; on other platforms it is a colon (`:`). -`--upgrade-module-path` *modulepath*... +[`--upgrade-module-path`]{#--upgrade-module-path} *modulepath*... : Specifies where to find module replacements of upgradeable modules in the runtime image with a list of path elements. The elements of a module path can be a file path to a module or a directory @@ -523,33 +523,33 @@ the JVM. On Windows, semicolons (`;`) separate path elements in this list; on other platforms it is a colon (`:`). -`--add-modules` *module*\[`,`*module*...\] +[`--add-modules`]{#--add-modules} *module*\[`,`*module*...\] : Specifies the root modules to resolve in addition to the initial module. *module* can also be `ALL-DEFAULT`, `ALL-SYSTEM`, and `ALL-MODULE-PATH`. -`--list-modules` +[`--list-modules`]{#--list-modules} : Lists the observable modules and then exits. -`-d` *module\_name* or `--describe-module` *module\_name* +[`-d`]{#-d} *module\_name* or `--describe-module` *module\_name* : Describes a specified module and then exits. -`--dry-run` +[`--dry-run`]{#--dry-run} : Creates the VM but doesn't execute the main method. This `--dry-run` option might be useful for validating the command-line options such as the module system configuration. -`--validate-modules` +[`--validate-modules`]{#--validate-modules} : Validates all modules and exit. This option is helpful for finding conflicts and other errors with modules on the module path. -`-D`*property*`=`*value* +[`-D`]{#-D}*property*`=`*value* : Sets a system property value. The *property* variable is a string with no spaces that represents the name of the property. The *value* variable is a string that represents the value of the property. If *value* is a string with spaces, then enclose it in quotation marks (for example `-Dfoo="foo bar"`). -`-disableassertions`\[`:`\[*packagename*\]...\|`:`*classname*\] or `-da`\[`:`\[*packagename*\]...\|`:`*classname*\] +[`-disableassertions`]{#-disableassertions}\[`:`\[*packagename*\]...\|`:`*classname*\] or `-da`\[`:`\[*packagename*\]...\|`:`*classname*\] : Disables assertions. By default, assertions are disabled in all packages and classes. With no arguments, `-disableassertions` (`-da`) disables assertions in all packages and classes. With the *packagename* argument @@ -574,10 +574,10 @@ the JVM. > `java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat MyClass` -`-disablesystemassertions` or `-dsa` +[`-disablesystemassertions`]{#-disablesystemassertions} or `-dsa` : Disables assertions in all system classes. -`-enableassertions`\[`:`\[*packagename*\]...\|`:`*classname*\] or `-ea`\[`:`\[*packagename*\]...\|`:`*classname*\] +[`-enableassertions`]{#-enableassertions}\[`:`\[*packagename*\]...\|`:`*classname*\] or `-ea`\[`:`\[*packagename*\]...\|`:`*classname*\] : Enables assertions. By default, assertions are disabled in all packages and classes. With no arguments, `-enableassertions` (`-ea`) enables assertions in all packages and classes. With the *packagename* argument ending in @@ -604,28 +604,28 @@ the JVM. > `java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat MyClass` -`-enablesystemassertions` or `-esa` +[`-enablesystemassertions`]{#-enablesystemassertions} or `-esa` : Enables assertions in all system classes. -`-help`, `-h`, or `-?` +[`-help`]{#-help}, `-h`, or `-?` : Prints the help message to the error stream. -`--help` +[`--help`]{#--help} : Prints the help message to the output stream. -`-javaagent:`*jarpath*\[`=`*options*\] +[`-javaagent:`]{#-javaagent_}*jarpath*\[`=`*options*\] : Loads the specified Java programming language agent. See `java.lang.instrument`. -`--show-version` +[`--show-version`]{#--show-version} : Prints the product version to the output stream and continues. -`-showversion` +[`-showversion`]{#-showversion} : Prints the product version to the error stream and continues. -`--show-module-resolution` +[`--show-module-resolution`]{#--show-module-resolution} : Shows module resolution output during startup. -`-splash:`*imagepath* +[`-splash:`]{#-splash_}*imagepath* : Shows the splash screen with the image specified by *imagepath*. HiDPI scaled images are automatically supported and used if available. The unscaled image file name, such as `image.ext`, should always be passed as @@ -639,29 +639,29 @@ the JVM. See the SplashScreen API documentation for more information. -`-verbose:class` +[`-verbose:class`]{#-verbose_class} : Displays information about each loaded class. -`-verbose:gc` +[`-verbose:gc`]{#-verbose_gc} : Displays information about each garbage collection (GC) event. -`-verbose:jni` +[`-verbose:jni`]{#-verbose_jni} : Displays information about the use of native methods and other Java Native Interface (JNI) activity. -`-verbose:module` +[`-verbose:module`]{#-verbose_module} : Displays information about the modules in use. -`--version` +[`--version`]{#--version} : Prints product version to the output stream and exits. -`-version` +[`-version`]{#-version} : Prints product version to the error stream and exits. -`-X` +[`-X`]{#-X} : Prints the help on extra options to the error stream. -`--help-extra` +[`--help-extra`]{#--help-extra} : Prints the help on extra options to the output stream. `@`*argfile* @@ -688,7 +688,7 @@ the JVM. The following `java` options are general purpose options that are specific to the Java HotSpot Virtual Machine. -`-Xbatch` +[`-Xbatch`]{#-Xbatch} : Disables background compilation. By default, the JVM compiles the method as a background task, running the method in interpreter mode until the background compilation is finished. The `-Xbatch` flag disables background @@ -696,14 +696,14 @@ the Java HotSpot Virtual Machine. task until completed. This option is equivalent to `-XX:-BackgroundCompilation`. -`-Xbootclasspath/a:`*directories*\|*zip*\|*JAR-files* +[`-Xbootclasspath/a:`]{#-Xbootclasspath}*directories*\|*zip*\|*JAR-files* : Specifies a list of directories, JAR files, and ZIP archives to append to the end of the default bootstrap class path. On Windows, semicolons (`;`) separate entities in this list; on other platforms it is a colon (`:`). -`-Xcheck:jni` +[`-Xcheck:jni`]{#-Xcheck_jni} : Performs additional checks for Java Native Interface (JNI) functions. The following checks are considered indicative of significant problems @@ -739,22 +739,22 @@ the Java HotSpot Virtual Machine. Expect a performance degradation when this option is used. -`-Xcomp` +[`-Xcomp`]{#-Xcomp} : Testing mode to exercise JIT compilers. This option should not be used in production environments. -`-Xdebug` +[`-Xdebug`]{#-Xdebug} : Does nothing; deprecated for removal in a future release. -`-Xdiag` +[`-Xdiag`]{#-Xdiag} : Shows additional diagnostic messages. -`-Xint` +[`-Xint`]{#-Xint} : Runs the application in interpreted-only mode. Compilation to native code is disabled, and all bytecode is executed by the interpreter. The performance benefits offered by the just-in-time (JIT) compiler aren't present in this mode. -`-Xinternalversion` +[`-Xinternalversion`]{#-Xinternalversion} : Displays more detailed JVM version information than the `-version` option, and then exits. @@ -763,11 +763,11 @@ the Java HotSpot Virtual Machine. logging framework. See [Enable Logging with the JVM Unified Logging Framework]. -`-Xmixed` +[`-Xmixed`]{#-Xmixed} : Executes all bytecode by the interpreter except for hot methods, which are compiled to native code. On by default. Use `-Xint` to switch off. -`-Xmn` *size* +[`-Xmn`]{#-Xmn} *size* : Sets the initial and maximum size (in bytes) of the heap for the young generation (nursery) in the generational collectors. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or @@ -793,7 +793,7 @@ the Java HotSpot Virtual Machine. the heap for the young generation, you can use `-XX:NewSize` to set the initial size and `-XX:MaxNewSize` to set the maximum size. -`-Xms` *size* +[`-Xms`]{#-Xms} *size* : Sets the minimum and the initial size (in bytes) of the heap. This value must be a multiple of 1024 and greater than 1 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` @@ -815,7 +815,7 @@ the Java HotSpot Virtual Machine. initial heap size. If it appears after `-Xms` on the command line, then the initial heap size gets set to the value specified with `-XX:InitialHeapSize`. -`-Xmx` *size* +[`-Xmx`]{#-Xmx} *size* : Specifies the maximum size (in bytes) of the heap. This value must be a multiple of 1024 and greater than 2 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` @@ -832,7 +832,7 @@ the Java HotSpot Virtual Machine. The `-Xmx` option is equivalent to `-XX:MaxHeapSize`. -`-Xnoclassgc` +[`-Xnoclassgc`]{#-Xnoclassgc} : Disables garbage collection (GC) of classes. This can save some GC time, which shortens interruptions during the application run. When you specify `-Xnoclassgc` at startup, the class objects in the application are left @@ -840,7 +840,7 @@ the Java HotSpot Virtual Machine. more memory being permanently occupied which, if not used carefully, throws an out-of-memory exception. -`-Xrs` +[`-Xrs`]{#-Xrs} : Reduces the use of operating system signals by the JVM. Shutdown hooks enable the orderly shutdown of a Java application by running user cleanup code (such as closing database connections) at shutdown, even if the JVM @@ -890,7 +890,7 @@ the Java HotSpot Virtual Machine. User code is responsible for causing shutdown hooks to run, for example, by calling `System.exit()` when the JVM is to be terminated. -`-Xshare:`*mode* +[`-Xshare:`]{#-Xshare_}*mode* : Sets the class data sharing (CDS) mode. Possible *mode* arguments for this option include the following: @@ -910,10 +910,10 @@ the Java HotSpot Virtual Machine. `off` : Do not attempt to use shared class data. -`-XshowSettings` +[`-XshowSettings`]{#-XshowSettings} : Shows all settings and then continues. -`-XshowSettings:`*category* +[`-XshowSettings:`]{#-XshowSettings_}*category* : Shows settings and continues. Possible *category* arguments for this option include the following: @@ -942,7 +942,7 @@ the Java HotSpot Virtual Machine. `system` : **Linux only:** Shows host system or container configuration and continues. -`-Xss` *size* +[`-Xss`]{#-Xss} *size* : Sets the thread stack size (in bytes). Append the letter `k` or `K` to indicate KB, `m` or `M` to indicate MB, or `g` or `G` to indicate GB. The actual size may be rounded up to a multiple of the system page size as @@ -970,32 +970,32 @@ the Java HotSpot Virtual Machine. This option is similar to `-XX:ThreadStackSize`. -`--add-reads` *module*`=`*target-module*(`,`*target-module*)\* +[`--add-reads`]{#--add-reads} *module*`=`*target-module*(`,`*target-module*)\* : Updates *module* to read the *target-module*, regardless of the module declaration. *target-module* can be `ALL-UNNAMED` to read all unnamed modules. -`--add-exports` *module*`/`*package*`=`*target-module*(`,`*target-module*)\* +[`--add-exports`]{#--add-exports} *module*`/`*package*`=`*target-module*(`,`*target-module*)\* : Updates *module* to export *package* to *target-module*, regardless of module declaration. *target-module* can be `ALL-UNNAMED` to export to all unnamed modules. -`--add-opens` *module*`/`*package*`=`*target-module*(`,`*target-module*)\* +[`--add-opens`]{#--add-opens} *module*`/`*package*`=`*target-module*(`,`*target-module*)\* : Updates *module* to open *package* to *target-module*, regardless of module declaration. -`--limit-modules` *module*\[`,`*module*...\] +[`--limit-modules`]{#--limit-modules} *module*\[`,`*module*...\] : Specifies the limit of the universe of observable modules. -`--patch-module` *module*`=`*file*(`;`*file*)\* +[`--patch-module`]{#--patch-module} *module*`=`*file*(`;`*file*)\* : Overrides or augments a module with classes and resources in JAR files or directories. -`--source` *version* +[`--source`]{#--source} *version* : Sets the version of the source in source-file mode. -`--sun-misc-unsafe-memory-access=` *value* +[`--sun-misc-unsafe-memory-access=`]{#--sun-misc-unsafe-memory-access} *value* : Allow or deny usage of unsupported API `sun.misc.Unsafe`. *value* is one of: `allow` @@ -1021,20 +1021,20 @@ the Java HotSpot Virtual Machine. The following extra options are macOS specific. -`-XstartOnFirstThread` +[`-XstartOnFirstThread`]{#-XstartOnFirstThread} : Runs the `main()` method on the first (AppKit) thread. -`-Xdock:name=`*application\_name* +[`-Xdock:name=`]{#-Xdock_name}*application\_name* : Overrides the default application name displayed in dock. -`-Xdock:icon=`*path\_to\_icon\_file* +[`-Xdock:icon=`]{#-Xdock_icon}*path\_to\_icon\_file* : Overrides the default icon displayed in dock. ## Advanced Options for Java These `java` options can be used to enable other advanced options. -`-XX:+UnlockDiagnosticVMOptions` +[`-XX:+UnlockDiagnosticVMOptions`]{#-XX__UnlockDiagnosticVMOptions} : Unlocks the options intended for diagnosing the JVM. By default, this option is disabled and diagnostic options aren't available. @@ -1046,7 +1046,7 @@ These `java` options can be used to enable other advanced options. of these options may be removed or their behavior changed without any warning. -`-XX:+UnlockExperimentalVMOptions` +[`-XX:+UnlockExperimentalVMOptions`]{#-XX__UnlockExperimentalVMOptions} : Unlocks the options that provide experimental features in the JVM. By default, this option is disabled and experimental features aren't available. @@ -1054,7 +1054,7 @@ These `java` options can be used to enable other advanced options. These `java` options control the runtime behavior of the Java HotSpot VM. -`-XX:ActiveProcessorCount=`*x* +[`-XX:ActiveProcessorCount=`]{#-XX_ActiveProcessorCount}*x* : Overrides the number of CPUs that the VM will use to calculate the size of thread pools it will use for various operations such as Garbage Collection and ForkJoinPool. @@ -1066,7 +1066,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. `-XX:-UseContainerSupport` for a description of enabling and disabling container support. -`-XX:AllocateHeapAt=`*path* +[`-XX:AllocateHeapAt=`]{#-XX_AllocateHeapAt}*path* : Takes a path to the file system and uses memory mapping to allocate the object heap on the memory device. Using this option enables the HotSpot VM to allocate the Java object heap on an alternative memory device, such as @@ -1084,7 +1084,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. The existing heap related flags (such as `-Xmx` and `-Xms`) and garbage-collection related flags continue to work as before. -`-XX:-CompactStrings` +[`-XX:-CompactStrings`]{#-XX__CompactStrings} : Disables the Compact Strings feature. By default, this option is enabled. When this option is enabled, Java Strings containing only single-byte characters are internally represented and stored as @@ -1107,7 +1107,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. In both of these scenarios, disabling Compact Strings makes sense. -`-XX:ErrorFile=`*filename* +[`-XX:ErrorFile=`]{#-XX_ErrorFile}*filename* : Specifies the path and file name to which error data is written when an irrecoverable error occurs. By default, this file is created in the current working directory and named `hs_err_pid`*pid*`.log` where *pid* is the @@ -1139,7 +1139,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. `TMP` environment variable; if that environment variable isn't defined, then the value of the `TEMP` environment variable is used. -`-XX:+ExtensiveErrorReports` +[`-XX:+ExtensiveErrorReports`]{#-XX__ExtensiveErrorReports} : Enables the reporting of more extensive error information in the `ErrorFile`. This option can be turned on in environments where maximal information is desired - even if the resulting logs may be quite large and/or contain @@ -1147,7 +1147,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. from release to release, and across different platforms. By default this option is disabled. -`-XX:FlightRecorderOptions=`*parameter*`=`*value* (or) `-XX:FlightRecorderOptions:`*parameter*`=`*value* +[`-XX:FlightRecorderOptions=`]{#-XX_FlightRecorderOptions}*parameter*`=`*value* (or) `-XX:FlightRecorderOptions:`*parameter*`=`*value* : Sets the parameters that control the behavior of JFR. Multiple parameters can be specified by separating them with a comma. @@ -1207,7 +1207,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. 4 kilobytes. Overriding this parameter could reduce performance and is not recommended. -`-XX:LargePageSizeInBytes=`*size* +[`-XX:LargePageSizeInBytes=`]{#-XX_LargePageSizeInBytes}*size* : Sets the maximum large page size (in bytes) used by the JVM. The *size* argument must be a valid page size supported by the environment to have any effect. Append the letter `k` or `K` to indicate kilobytes, @@ -1221,7 +1221,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. > `-XX:LargePageSizeInBytes=1g` -`-XX:MaxDirectMemorySize=`*size* +[`-XX:MaxDirectMemorySize=`]{#-XX_MaxDirectMemorySize}*size* : Sets the maximum total size (in bytes) of the `java.nio` package, direct-buffer allocations. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate @@ -1237,14 +1237,14 @@ These `java` options control the runtime behavior of the Java HotSpot VM. -XX:MaxDirectMemorySize=1048576 ``` -`-XX:-MaxFDLimit` +[`-XX:-MaxFDLimit`]{#-XX__MaxFDLimit} : Disables the attempt to set the soft limit for the number of open file descriptors to the hard limit. By default, this option is enabled on all platforms, but is ignored on Windows. The only time that you may need to disable this is on macOS, where its use imposes a maximum of 10240, which is lower than the actual system maximum. -`-XX:NativeMemoryTracking=`*mode* +[`-XX:NativeMemoryTracking=`]{#-XX_NativeMemoryTracking}*mode* : Specifies the mode for tracking JVM native memory usage. Possible *mode* arguments for this option include the following: @@ -1261,7 +1261,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. usage by individual `CallSite`, individual virtual memory region and its committed regions. -`-XX:TrimNativeHeapInterval=`*millis* +[`-XX:TrimNativeHeapInterval=`]{#-XX_TrimNativeHeapInterval}*millis* : Interval, in ms, at which the JVM will trim the native heap. Lower values will reclaim memory more eagerly at the cost of higher overhead. A value of 0 (default) disables native heap trimming. @@ -1269,7 +1269,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. This option is only supported on Linux with GNU C Library (glibc). -`-XX:ObjectAlignmentInBytes=`*alignment* +[`-XX:ObjectAlignmentInBytes=`]{#-XX_ObjectAlignmentInBytes}*alignment* : Sets the memory alignment of Java objects (in bytes). By default, the value is set to 8 bytes. The specified value should be a power of 2, and must be within the range of 8 and 256 (inclusive). This option makes it possible to @@ -1283,7 +1283,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. increases. As a result, you may not realize any benefits from using compressed pointers with large Java heap sizes. -`-XX:OnError=`*string* +[`-XX:OnError=`]{#-XX_OnError}*string* : Sets a custom command or a series of semicolon-separated commands to run when an irrecoverable error occurs. If the string contains spaces, then it must be enclosed in quotation marks. @@ -1304,7 +1304,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. > `-XX:OnError="userdump.exe %p"` -`-XX:OnOutOfMemoryError=`*string* +[`-XX:OnOutOfMemoryError=`]{#-XX_OnOutOfMemoryError}*string* : Sets a custom command or a series of semicolon-separated commands to run when an `OutOfMemoryError` exception is first thrown by the JVM. If the string @@ -1316,31 +1316,31 @@ These `java` options control the runtime behavior of the Java HotSpot VM. directly from Java code, nor by the JVM for other types of resource exhaustion (such as native thread creation errors). -`-XX:+PrintCommandLineFlags` +[`-XX:+PrintCommandLineFlags`]{#-XX__PrintCommandLineFlags} : Enables printing of ergonomically selected JVM flags that appeared on the command line. It can be useful to know the ergonomic values set by the JVM, such as the heap space size and the selected garbage collector. By default, this option is disabled and flags aren't printed. -`-XX:+PreserveFramePointer` +[`-XX:+PreserveFramePointer`]{#-XX__PreserveFramePointer} : Selects between using the RBP register as a general purpose register (`-XX:-PreserveFramePointer`) and using the RBP register to hold the frame pointer of the currently executing method (`-XX:+PreserveFramePointer`). If the frame pointer is available, then external profiling tools (for example, Linux perf) can construct more accurate stack traces. -`-XX:+PrintNMTStatistics` +[`-XX:+PrintNMTStatistics`]{#-XX__PrintNMTStatistics} : Enables printing of collected native memory tracking data at JVM exit when native memory tracking is enabled (see `-XX:NativeMemoryTracking`). By default, this option is disabled and native memory tracking data isn't printed. -`-XX:SharedArchiveFile=`*path* +[`-XX:SharedArchiveFile=`]{#-XX_SharedArchiveFile}*path* : Specifies the path and name of the class data sharing (CDS) archive file See [Application Class Data Sharing]. -`-XX:+VerifySharedSpaces` +[`-XX:+VerifySharedSpaces`]{#-XX__VerifySharedSpaces} : If this option is specified, the JVM will load a CDS archive file only if it passes an integrity check based on CRC32 checksums. The purpose of this flag is to check for unintentional damage to CDS archive files in transmission or storage. @@ -1348,10 +1348,10 @@ These `java` options control the runtime behavior of the Java HotSpot VM. ensure that the CDS archive files used by Java applications cannot be modified without proper authorization. -`-XX:SharedArchiveConfigFile=`*shared\_config\_file* +[`-XX:SharedArchiveConfigFile=`]{#-XX_SharedArchiveConfigFile}*shared\_config\_file* : Specifies additional shared data added to the archive file. -`-XX:SharedClassListFile=`*file\_name* +[`-XX:SharedClassListFile=`]{#-XX_SharedClassListFile}*file\_name* : Specifies the text file that contains the names of the classes to store in the class data sharing (CDS) archive. This file contains the full name of one class per line, except slashes (`/`) replace dots (`.`). For example, @@ -1369,7 +1369,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. See [Application Class Data Sharing]. -`-XX:+ShowCodeDetailsInExceptionMessages` +[`-XX:+ShowCodeDetailsInExceptionMessages`]{#-XX__ShowCodeDetailsInExceptionMessages} : Enables printing of improved `NullPointerException` messages. When an application throws a `NullPointerException`, the option enables the JVM to analyze the program's bytecode instructions to determine precisely which reference is `null`, @@ -1378,13 +1378,13 @@ These `java` options control the runtime behavior of the Java HotSpot VM. and will be printed as the exception message along with the method, filename, and line number. By default, this option is enabled. -`-XX:+ShowMessageBoxOnError` +[`-XX:+ShowMessageBoxOnError`]{#-XX__ShowMessageBoxOnError} : Enables the display of a dialog box when the JVM experiences an irrecoverable error. This prevents the JVM from exiting and keeps the process active so that you can attach a debugger to it to investigate the cause of the error. By default, this option is disabled. -`-XX:StartFlightRecording:`*parameter*`=`*value* +[`-XX:StartFlightRecording:`]{#-XX_StartFlightRecording_}*parameter*`=`*value* : Starts a JFR recording for the Java application. This option is equivalent to the `JFR.start` diagnostic command that starts a recording during runtime. `-XX:StartFlightRecording:help` prints available options and @@ -1503,7 +1503,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. To only see warnings and errors from JFR during startup set -Xlog:jfr+startup=warning. -`-XX:ThreadStackSize=`*size* +[`-XX:ThreadStackSize=`]{#-XX_ThreadStackSize}*size* : Sets the Java thread stack size (in kilobytes). Use of a scaling suffix, such as `k`, results in the scaling of the kilobytes value so that `-XX:ThreadStackSize=1k` sets the Java thread stack size to 1024\*1024 @@ -1529,7 +1529,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. This option is similar to `-Xss`. -`-XX:+UseCompactObjectHeaders` +[`-XX:+UseCompactObjectHeaders`]{#-XX__UseCompactObjectHeaders} : Enables compact object headers. By default, this option is disabled. Enabling this option reduces memory footprint in the Java heap by 4 bytes per object (on average) and often improves performance. @@ -1538,7 +1538,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. In a future release it is expected to be enabled by default, and eventually will be the only mode of operation. -`-XX:-UseCompressedOops` +[`-XX:-UseCompressedOops`]{#-XX__UseCompressedOops} : Disables the use of compressed pointers. By default, this option is enabled, and compressed pointers are used. This will automatically limit the maximum ergonomically determined Java heap size to the maximum amount @@ -1553,7 +1553,7 @@ These `java` options control the runtime behavior of the Java HotSpot VM. It's possible to use compressed pointers with Java heap sizes greater than 32 GB. See the `-XX:ObjectAlignmentInBytes` option. -`-XX:-UseContainerSupport` +[`-XX:-UseContainerSupport`]{#-XX__UseContainerSupport} : **Linux only:** The VM now provides automatic container detection support, which allows the VM to determine the amount of memory and number of processors that are available to a Java process running in docker containers. It uses this @@ -1568,28 +1568,28 @@ These `java` options control the runtime behavior of the Java HotSpot VM. information. See [Enable Logging with the JVM Unified Logging Framework] for a description of using Unified Logging. -`-XX:+UseLargePages` +[`-XX:+UseLargePages`]{#-XX__UseLargePages} : Enables the use of large page memory. By default, this option is disabled and large page memory isn't used. See [Large Pages]. -`-XX:+UseTransparentHugePages` +[`-XX:+UseTransparentHugePages`]{#-XX__UseTransparentHugePages} : **Linux only:** Enables the use of large pages that can dynamically grow or shrink. This option is disabled by default. You may encounter performance problems with transparent huge pages as the OS moves other pages around to create huge pages; this option is made available for experimentation. -`-XX:+AllowUserSignalHandlers` +[`-XX:+AllowUserSignalHandlers`]{#-XX__AllowUserSignalHandlers} : **Non-Windows:** Enables installation of signal handlers by the application. By default, this option is disabled and the application isn't allowed to install signal handlers. -`-XX:VMOptionsFile=`*filename* +[`-XX:VMOptionsFile=`]{#-XX_VMOptionsFile}*filename* : Allows user to specify VM options in a file, for example, `java -XX:VMOptionsFile=/var/my_vm_options HelloWorld`. -`-XX:UseBranchProtection=`*mode* +[`-XX:UseBranchProtection=`]{#-XX_UseBranchProtection}*mode* : **Linux AArch64 only:** Specifies the branch protection mode. All options other than `none` require the VM to have been built with branch protection @@ -1613,14 +1613,14 @@ These `java` options control the runtime behavior of the Java HotSpot VM. These `java` options control the dynamic just-in-time (JIT) compilation performed by the Java HotSpot VM. -`-XX:AllocateInstancePrefetchLines=`*lines* +[`-XX:AllocateInstancePrefetchLines=`]{#-XX_AllocateInstancePrefetchLines}*lines* : Sets the number of lines to prefetch ahead of the instance allocation pointer. By default, the number of lines to prefetch is set to 1: > `-XX:AllocateInstancePrefetchLines=1` -`-XX:AllocatePrefetchDistance=`*size* +[`-XX:AllocatePrefetchDistance=`]{#-XX_AllocatePrefetchDistance}*size* : Sets the size (in bytes) of the prefetch distance for object allocation. Memory about to be written with the value of new objects is prefetched up to this distance starting from the address of the last allocated object. @@ -1636,7 +1636,7 @@ performed by the Java HotSpot VM. > `-XX:AllocatePrefetchDistance=1024` -`-XX:AllocatePrefetchInstr=`*instruction* +[`-XX:AllocatePrefetchInstr=`]{#-XX_AllocatePrefetchInstr}*instruction* : Sets the prefetch instruction to prefetch ahead of the allocation pointer. Possible values are from 0 to 3. The actual instructions behind the values depend on the platform. By default, the prefetch instruction is set to 0: @@ -1644,7 +1644,7 @@ performed by the Java HotSpot VM. > `-XX:AllocatePrefetchInstr=0` -`-XX:AllocatePrefetchLines=`*lines* +[`-XX:AllocatePrefetchLines=`]{#-XX_AllocatePrefetchLines}*lines* : Sets the number of cache lines to load after the last object allocation by using the prefetch instructions generated in compiled code. The default value is 1 if the last allocated object was an instance, and 3 if it was an @@ -1656,7 +1656,7 @@ performed by the Java HotSpot VM. > `-XX:AllocatePrefetchLines=5` -`-XX:AllocatePrefetchStepSize=`*size* +[`-XX:AllocatePrefetchStepSize=`]{#-XX_AllocatePrefetchStepSize}*size* : Sets the step size (in bytes) for sequential prefetch instructions. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, `g` or `G` to indicate gigabytes. By default, the step size is @@ -1665,7 +1665,7 @@ performed by the Java HotSpot VM. > `-XX:AllocatePrefetchStepSize=16` -`-XX:AllocatePrefetchStyle=`*style* +[`-XX:AllocatePrefetchStyle=`]{#-XX_AllocatePrefetchStyle}*style* : Sets the generated code style for prefetch instructions. The *style* argument is an integer from 0 to 3: @@ -1684,12 +1684,12 @@ performed by the Java HotSpot VM. : Generate one prefetch instruction per cache line. -`-XX:+BackgroundCompilation` +[`-XX:+BackgroundCompilation`]{#-XX__BackgroundCompilation} : Enables background compilation. This option is enabled by default. To disable background compilation, specify `-XX:-BackgroundCompilation` (this is equivalent to specifying `-Xbatch`). -`-XX:CICompilerCount=`*threads* +[`-XX:CICompilerCount=`]{#-XX_CICompilerCount}*threads* : Sets the number of compiler threads to use for compilation. By default, the number of compiler threads is selected automatically depending on the number of CPUs and memory available for compiled code. @@ -1697,11 +1697,11 @@ performed by the Java HotSpot VM. > `-XX:CICompilerCount=2` -`-XX:+UseDynamicNumberOfCompilerThreads` +[`-XX:+UseDynamicNumberOfCompilerThreads`]{#-XX__UseDynamicNumberOfCompilerThreads} : Dynamically create compiler thread up to the limit specified by `-XX:CICompilerCount`. This option is enabled by default. -`-XX:CompileCommand=`*command*`,`*method*\[`,`*option*\] +[`-XX:CompileCommand=`]{#-XX_CompileCommand}*command*`,`*method*\[`,`*option*\] : Specifies a *command* to perform on a *method*. For example, to exclude the `indexOf()` method of the `String` class from being compiled, use the following: @@ -1800,7 +1800,7 @@ performed by the Java HotSpot VM. You can suppress this by specifying the `-XX:CompileCommand=quiet` option before other `-XX:CompileCommand` options. -`-XX:CompileCommandFile=`*filename* +[`-XX:CompileCommandFile=`]{#-XX_CompileCommandFile}*filename* : Sets the file from which JIT compiler commands are read. By default, the `.hotspot_compiler` file is used to store commands performed by the JIT compiler. @@ -1814,7 +1814,7 @@ performed by the Java HotSpot VM. If you're using commands for the JIT compiler to perform on methods, then see the `-XX:CompileCommand` option. -`-XX:CompilerDirectivesFile=`*file* +[`-XX:CompilerDirectivesFile=`]{#-XX_CompilerDirectivesFile}*file* : Adds directives from a file to the directives stack when a program starts. See [Compiler Control](https://docs.oracle.com/en/java/javase/12/vm/compiler-control1.html#GUID-94AD8194-786A-4F19-BFFF-278F8E237F3A). @@ -1822,14 +1822,14 @@ performed by the Java HotSpot VM. `-XX:UnlockDiagnosticVMOptions` option that unlocks diagnostic JVM options. -`-XX:+CompilerDirectivesPrint` +[`-XX:+CompilerDirectivesPrint`]{#-XX__CompilerDirectivesPrint} : Prints the directives stack when the program starts or when a new directive is added. The `-XX:+CompilerDirectivesPrint` option has to be used together with the `-XX:UnlockDiagnosticVMOptions` option that unlocks diagnostic JVM options. -`-XX:CompileOnly=`*methods* +[`-XX:CompileOnly=`]{#-XX_CompileOnly}*methods* : Sets the list of methods (separated by commas) to which compilation should be restricted. Only the specified methods are compiled. @@ -1841,7 +1841,7 @@ performed by the Java HotSpot VM. -XX:CompileCommand=compileonly,methodN ``` -`-XX:CompileThresholdScaling=`*scale* +[`-XX:CompileThresholdScaling=`]{#-XX_CompileThresholdScaling}*scale* : Provides unified control of first compilation. This option controls when methods are first compiled for both the tiered and the nontiered modes of operation. The `CompileThresholdScaling` option has a floating point value @@ -1851,11 +1851,11 @@ performed by the Java HotSpot VM. compilation while values greater than 1.0 delay compilation. Setting `CompileThresholdScaling` to 0 is equivalent to disabling compilation. -`-XX:+DoEscapeAnalysis` +[`-XX:+DoEscapeAnalysis`]{#-XX__DoEscapeAnalysis} : Enables the use of escape analysis. This option is enabled by default. To disable the use of escape analysis, specify `-XX:-DoEscapeAnalysis`. -`-XX:InitialCodeCacheSize=`*size* +[`-XX:InitialCodeCacheSize=`]{#-XX_InitialCodeCacheSize}*size* : Sets the initial code cache size (in bytes). Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate gigabytes. The default value depends on the platform. The initial code @@ -1865,11 +1865,11 @@ performed by the Java HotSpot VM. > `-XX:InitialCodeCacheSize=32k` -`-XX:+Inline` +[`-XX:+Inline`]{#-XX__Inline} : Enables method inlining. This option is enabled by default to increase performance. To disable method inlining, specify `-XX:-Inline`. -`-XX:InlineSmallCode=`*size* +[`-XX:InlineSmallCode=`]{#-XX_InlineSmallCode}*size* : Sets the maximum code size (in bytes) for already compiled methods that may be inlined. This flag only applies to the C2 compiler. Append the letter `k` or `K` to indicate kilobytes, @@ -1879,7 +1879,7 @@ performed by the Java HotSpot VM. > `-XX:InlineSmallCode=1000` -`-XX:+LogCompilation` +[`-XX:+LogCompilation`]{#-XX__LogCompilation} : Enables logging of compilation activity to a file named `hotspot.log` in the current working directory. You can specify a different log file path and name using the `-XX:LogFile` option. @@ -1893,7 +1893,7 @@ performed by the Java HotSpot VM. `-XX:+PrintCompilation` option. -`-XX:FreqInlineSize=`*size* +[`-XX:FreqInlineSize=`]{#-XX_FreqInlineSize}*size* : Sets the maximum bytecode size (in bytes) of a hot method to be inlined. This flag only applies to the C2 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate @@ -1903,7 +1903,7 @@ performed by the Java HotSpot VM. > `-XX:FreqInlineSize=325` -`-XX:MaxInlineSize=`*size* +[`-XX:MaxInlineSize=`]{#-XX_MaxInlineSize}*size* : Sets the maximum bytecode size (in bytes) of a cold method to be inlined. This flag only applies to the C2 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate @@ -1912,7 +1912,7 @@ performed by the Java HotSpot VM. > `-XX:MaxInlineSize=35` -`-XX:C1MaxInlineSize=`*size* +[`-XX:C1MaxInlineSize=`]{#-XX_C1MaxInlineSize}*size* : Sets the maximum bytecode size (in bytes) of a cold method to be inlined. This flag only applies to the C1 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate @@ -1921,7 +1921,7 @@ performed by the Java HotSpot VM. > `-XX:MaxInlineSize=35` -`-XX:MaxTrivialSize=`*size* +[`-XX:MaxTrivialSize=`]{#-XX_MaxTrivialSize}*size* : Sets the maximum bytecode size (in bytes) of a trivial method to be inlined. This flag only applies to the C2 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to @@ -1930,7 +1930,7 @@ performed by the Java HotSpot VM. > `-XX:MaxTrivialSize=6` -`-XX:C1MaxTrivialSize=`*size* +[`-XX:C1MaxTrivialSize=`]{#-XX_C1MaxTrivialSize}*size* : Sets the maximum bytecode size (in bytes) of a trivial method to be inlined. This flag only applies to the C1 compiler. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to @@ -1939,14 +1939,14 @@ performed by the Java HotSpot VM. > `-XX:MaxTrivialSize=6` -`-XX:MaxNodeLimit=`*nodes* +[`-XX:MaxNodeLimit=`]{#-XX_MaxNodeLimit}*nodes* : Sets the maximum number of nodes to be used during single method compilation. By default the value depends on the features enabled. In the following example the maximum number of nodes is set to 100,000: > `-XX:MaxNodeLimit=100000` -`-XX:NonNMethodCodeHeapSize=`*size* +[`-XX:NonNMethodCodeHeapSize=`]{#-XX_NonNMethodCodeHeapSize}*size* : Sets the size in bytes of the code segment containing nonmethod code. A nonmethod code segment containing nonmethod code, such as compiler @@ -1954,16 +1954,16 @@ performed by the Java HotSpot VM. cache forever. This flag is used only if `-XX:SegmentedCodeCache` is enabled. -`-XX:NonProfiledCodeHeapSize=`*size* +[`-XX:NonProfiledCodeHeapSize=`]{#-XX_NonProfiledCodeHeapSize}*size* : Sets the size in bytes of the code segment containing nonprofiled methods. This flag is used only if `-XX:SegmentedCodeCache` is enabled. -`-XX:+OptimizeStringConcat` +[`-XX:+OptimizeStringConcat`]{#-XX__OptimizeStringConcat} : Enables the optimization of `String` concatenation operations. This option is enabled by default. To disable the optimization of `String` concatenation operations, specify `-XX:-OptimizeStringConcat`. -`-XX:+PrintAssembly` +[`-XX:+PrintAssembly`]{#-XX__PrintAssembly} : Enables printing of assembly code for bytecoded and native methods by using the external `hsdis-.so` or `.dll` library. For 64-bit VM on Windows, it's `hsdis-amd64.dll`. This lets you to see the generated code, which may @@ -1973,11 +1973,11 @@ performed by the Java HotSpot VM. `-XX:+PrintAssembly` option has to be used together with the `-XX:UnlockDiagnosticVMOptions` option that unlocks diagnostic JVM options. -`-XX:ProfiledCodeHeapSize=`*size* +[`-XX:ProfiledCodeHeapSize=`]{#-XX_ProfiledCodeHeapSize}*size* : Sets the size in bytes of the code segment containing profiled methods. This flag is used only if `-XX:SegmentedCodeCache` is enabled. -`-XX:+PrintCompilation` +[`-XX:+PrintCompilation`]{#-XX__PrintCompilation} : Enables verbose diagnostic output from the JVM by printing a message to the console every time a method is compiled. This lets you to see which methods actually get compiled. By default, this option is disabled and diagnostic @@ -1986,7 +1986,7 @@ performed by the Java HotSpot VM. You can also log compilation activity to a file by using the `-XX:+LogCompilation` option. -`-XX:+PrintInlining` +[`-XX:+PrintInlining`]{#-XX__PrintInlining} : Enables printing of inlining decisions. This let's you see which methods are getting inlined. @@ -1995,7 +1995,7 @@ performed by the Java HotSpot VM. `-XX:+UnlockDiagnosticVMOptions` option that unlocks diagnostic JVM options. -`-XX:ReservedCodeCacheSize=`*size* +[`-XX:ReservedCodeCacheSize=`]{#-XX_ReservedCodeCacheSize}*size* : Sets the maximum code cache size (in bytes) for JIT-compiled code. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate gigabytes. The default maximum code @@ -2005,7 +2005,7 @@ performed by the Java HotSpot VM. size shouldn't be less than the initial code cache size; see the option `-XX:InitialCodeCacheSize`. -`-XX:+SegmentedCodeCache` +[`-XX:+SegmentedCodeCache`]{#-XX__SegmentedCodeCache} : Enables segmentation of the code cache, without which the code cache consists of one large segment. With `-XX:+SegmentedCodeCache`, separate segments will be used for non-method, profiled method, and non-profiled @@ -2018,29 +2018,29 @@ performed by the Java HotSpot VM. (`-XX:+TieredCompilation` ) and the reserved code cache size (`-XX:ReservedCodeCacheSize`) is at least 240 MB. -`-XX:StartAggressiveSweepingAt=`*percent* +[`-XX:StartAggressiveSweepingAt=`]{#-XX_StartAggressiveSweepingAt}*percent* : Forces stack scanning of active methods to aggressively remove unused code when only the given percentage of the code cache is free. The default value is 10%. -`-XX:-TieredCompilation` +[`-XX:-TieredCompilation`]{#-XX__TieredCompilation} : Disables the use of tiered compilation. By default, this option is enabled. -`-XX:UseSSE=`*version* +[`-XX:UseSSE=`]{#-XX_UseSSE}*version* : Enables the use of SSE instruction set of a specified version. Is set by default to the highest supported version available (x86 only). -`-XX:UseAVX=`*version* +[`-XX:UseAVX=`]{#-XX_UseAVX}*version* : Enables the use of AVX instruction set of a specified version. Is set by default to the highest supported version available (x86 only). -`-XX:+UseAES` +[`-XX:+UseAES`]{#-XX__UseAES} : Enables hardware-based AES intrinsics for hardware that supports it. This option is on by default on hardware that has the necessary instructions. The `-XX:+UseAES` is used in conjunction with `UseAESIntrinsics`. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseAESIntrinsics` +[`-XX:+UseAESIntrinsics`]{#-XX__UseAESIntrinsics} : Enables AES intrinsics. Specifying `-XX:+UseAESIntrinsics` is equivalent to also enabling `-XX:+UseAES`. To disable hardware-based AES intrinsics, specify `-XX:-UseAES -XX:-UseAESIntrinsics`. For example, to enable hardware @@ -2051,47 +2051,47 @@ performed by the Java HotSpot VM. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseAESCTRIntrinsics` +[`-XX:+UseAESCTRIntrinsics`]{#-XX__UseAESCTRIntrinsics} : Analogous to `-XX:+UseAESIntrinsics` enables AES/CTR intrinsics. -`-XX:+UseGHASHIntrinsics` +[`-XX:+UseGHASHIntrinsics`]{#-XX__UseGHASHIntrinsics} : Controls the use of GHASH intrinsics. Enabled by default on platforms that support the corresponding instructions. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseChaCha20Intrinsics` +[`-XX:+UseChaCha20Intrinsics`]{#-XX__UseChaCha20Intrinsics} : Enable ChaCha20 intrinsics. This option is on by default for supported platforms. To disable ChaCha20 intrinsics, specify `-XX:-UseChaCha20Intrinsics`. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UsePoly1305Intrinsics` +[`-XX:+UsePoly1305Intrinsics`]{#-XX__UsePoly1305Intrinsics} : Enable Poly1305 intrinsics. This option is on by default for supported platforms. To disable Poly1305 intrinsics, specify `-XX:-UsePoly1305Intrinsics`. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseBASE64Intrinsics` +[`-XX:+UseBASE64Intrinsics`]{#-XX__UseBASE64Intrinsics} : Controls the use of accelerated BASE64 encoding routines for `java.util.Base64`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseAdler32Intrinsics` +[`-XX:+UseAdler32Intrinsics`]{#-XX__UseAdler32Intrinsics} : Controls the use of Adler32 checksum algorithm intrinsic for `java.util.zip.Adler32`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseCRC32Intrinsics` +[`-XX:+UseCRC32Intrinsics`]{#-XX__UseCRC32Intrinsics} : Controls the use of CRC32 intrinsics for `java.util.zip.CRC32`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseCRC32CIntrinsics` +[`-XX:+UseCRC32CIntrinsics`]{#-XX__UseCRC32CIntrinsics} : Controls the use of CRC32C intrinsics for `java.util.zip.CRC32C`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseSHA` +[`-XX:+UseSHA`]{#-XX__UseSHA} : Enables hardware-based intrinsics for SHA crypto hash functions for some hardware. The `UseSHA` option is used in conjunction with the `UseSHA1Intrinsics`, `UseSHA256Intrinsics`, and `UseSHA512Intrinsics` @@ -2108,26 +2108,26 @@ performed by the Java HotSpot VM. disable only a particular SHA intrinsic, use the appropriate corresponding option. For example: `-XX:-UseSHA256Intrinsics`. -`-XX:+UseSHA1Intrinsics` +[`-XX:+UseSHA1Intrinsics`]{#-XX__UseSHA1Intrinsics} : Enables intrinsics for SHA-1 crypto hash function. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseSHA256Intrinsics` +[`-XX:+UseSHA256Intrinsics`]{#-XX__UseSHA256Intrinsics} : Enables intrinsics for SHA-224 and SHA-256 crypto hash functions. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseSHA512Intrinsics` +[`-XX:+UseSHA512Intrinsics`]{#-XX__UseSHA512Intrinsics} : Enables intrinsics for SHA-384 and SHA-512 crypto hash functions. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseMathExactIntrinsics` +[`-XX:+UseMathExactIntrinsics`]{#-XX__UseMathExactIntrinsics} : Enables intrinsification of various `java.lang.Math.*Exact()` functions. Enabled by default. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseMultiplyToLenIntrinsic` +[`-XX:+UseMultiplyToLenIntrinsic`]{#-XX__UseMultiplyToLenIntrinsic} : Enables intrinsification of `BigInteger.multiplyToLen()`. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. @@ -2152,44 +2152,44 @@ performed by the Java HotSpot VM. Enabled by default on platforms that support it. Flags that control intrinsics now require the option `-XX:+UnlockDiagnosticVMOptions`. -`-XX:+UseCMoveUnconditionally` +[`-XX:+UseCMoveUnconditionally`]{#-XX__UseCMoveUnconditionally} : Generates CMove (scalar and vector) instructions regardless of profitability analysis. -`-XX:+UseCodeCacheFlushing` +[`-XX:+UseCodeCacheFlushing`]{#-XX__UseCodeCacheFlushing} : Enables flushing of the code cache before shutting down the compiler. This option is enabled by default. To disable flushing of the code cache before shutting down the compiler, specify `-XX:-UseCodeCacheFlushing`. -`-XX:+UseCondCardMark` +[`-XX:+UseCondCardMark`]{#-XX__UseCondCardMark} : Enables checking if the card is already marked before updating the card table. This option is disabled by default. It should be used only on machines with multiple sockets, where it increases the performance of Java applications that rely on concurrent operations. -`-XX:+UseCountedLoopSafepoints` +[`-XX:+UseCountedLoopSafepoints`]{#-XX__UseCountedLoopSafepoints} : Keeps safepoints in counted loops. Its default value depends on whether the selected garbage collector requires low latency safepoints. -`-XX:LoopStripMiningIter=`*number_of_iterations* +[`-XX:LoopStripMiningIter=`]{#-XX_LoopStripMiningIter}*number_of_iterations* : Controls the number of iterations in the inner strip mined loop. Strip mining transforms counted loops into two level nested loops. Safepoints are kept in the outer loop while the inner loop can execute at full speed. This option controls the maximum number of iterations in the inner loop. The default value is 1,000. -`-XX:LoopStripMiningIterShortLoop=`*number_of_iterations* +[`-XX:LoopStripMiningIterShortLoop=`]{#-XX_LoopStripMiningIterShortLoop}*number_of_iterations* : Controls loop strip mining optimization. Loops with the number of iterations less than specified will not have safepoints in them. Default value is 1/10th of `-XX:LoopStripMiningIter`. -`-XX:+UseFMA` +[`-XX:+UseFMA`]{#-XX__UseFMA} : Enables hardware-based FMA intrinsics for hardware where FMA instructions are available (such as, Intel and ARM64). FMA intrinsics are generated for the `java.lang.Math.fma(`*a*`,` *b*`,` *c*`)` methods that calculate the value of `(` *a* `*` *b* `+` *c* `)` expressions. -`-XX:+UseSuperWord` +[`-XX:+UseSuperWord`]{#-XX__UseSuperWord} : Enables the transformation of scalar operations into superword operations. Superword is a vectorization optimization. This option is enabled by default. To disable the transformation of scalar operations into superword @@ -2200,7 +2200,7 @@ performed by the Java HotSpot VM. These `java` options provide the ability to gather system information and perform extensive debugging. -`-XX:+DisableAttachMechanism` +[`-XX:+DisableAttachMechanism`]{#-XX__DisableAttachMechanism} : Disables the mechanism that lets tools attach to the JVM. By default, this option is disabled, meaning that the attach mechanism is enabled and you can use diagnostics and troubleshooting tools such as `jcmd`, `jstack`, @@ -2211,17 +2211,17 @@ perform extensive debugging. supported when using the tools from one JDK version to troubleshoot a different JDK version. -`-XX:+DTraceAllocProbes` +[`-XX:+DTraceAllocProbes`]{#-XX__DTraceAllocProbes} : **Linux and macOS:** Enable `dtrace` tool probes for object allocation. -`-XX:+DTraceMethodProbes` +[`-XX:+DTraceMethodProbes`]{#-XX__DTraceMethodProbes} : **Linux and macOS:** Enable `dtrace` tool probes for method-entry and method-exit. -`-XX:+DTraceMonitorProbes` +[`-XX:+DTraceMonitorProbes`]{#-XX__DTraceMonitorProbes} : **Linux and macOS:** Enable `dtrace` tool probes for monitor events. -`-XX:+HeapDumpOnOutOfMemoryError` +[`-XX:+HeapDumpOnOutOfMemoryError`]{#-XX__HeapDumpOnOutOfMemoryError} : Enables the dumping of the Java heap to a file in the current directory by using the heap profiler (HPROF) when a `java.lang.OutOfMemoryError` exception is thrown by the JVM. You can explicitly set the heap dump file path and @@ -2233,7 +2233,7 @@ perform extensive debugging. directly from Java code, nor by the JVM for other types of resource exhaustion (such as native thread creation errors). -`-XX:HeapDumpPath=`*path* +[`-XX:HeapDumpPath=`]{#-XX_HeapDumpPath}*path* : Sets the path and file name for writing the heap dump provided by the heap profiler (HPROF) when the `-XX:+HeapDumpOnOutOfMemoryError` option is set. By default, the file is created in the current working directory, and it's @@ -2253,7 +2253,7 @@ perform extensive debugging. > `-XX:HeapDumpPath=C:/log/java/java_heapdump.log` -`-XX:LogFile=`*path* +[`-XX:LogFile=`]{#-XX_LogFile}*path* : Sets the path and file name to where log data is written. By default, the file is created in the current working directory, and it's named `hotspot.log`. @@ -2268,7 +2268,7 @@ perform extensive debugging. > `-XX:LogFile=C:/log/java/hotspot.log` -`-XX:+PrintClassHistogram` +[`-XX:+PrintClassHistogram`]{#-XX__PrintClassHistogram} : Enables printing of a class instance histogram after one of the following events: @@ -2282,7 +2282,7 @@ perform extensive debugging. the `jcmd` *pid* `GC.class_histogram` command, where *pid* is the current Java process identifier. -`-XX:+PrintConcurrentLocks` +[`-XX:+PrintConcurrentLocks`]{#-XX__PrintConcurrentLocks} : Enables printing of `java.util.concurrent` locks after one of the following events: @@ -2296,12 +2296,12 @@ perform extensive debugging. `jcmd` *pid* `Thread.print -l` command, where *pid* is the current Java process identifier. -`-XX:+PrintFlagsRanges` +[`-XX:+PrintFlagsRanges`]{#-XX__PrintFlagsRanges} : Prints the range specified and allows automatic testing of the values. See [Validate Java Virtual Machine Flag Arguments]. -`-XX:+PerfDataSaveToFile` +[`-XX:+PerfDataSaveToFile`]{#-XX__PerfDataSaveToFile} : If enabled, saves [jstat](jstat.html) binary data when the Java application exits. This binary data is saved in a file named `hsperfdata_`*pid*, where *pid* is the process identifier of the Java application that you ran. Use @@ -2312,7 +2312,7 @@ perform extensive debugging. > `jstat -gc file:///`*path*`/hsperfdata_`*pid* -`-XX:+UsePerfData` +[`-XX:+UsePerfData`]{#-XX__UsePerfData} : Enables the `perfdata` feature. This option is enabled by default to allow JVM monitoring and performance testing. Disabling it suppresses the creation of the `hsperfdata_userid` directories. To disable the `perfdata` @@ -2323,13 +2323,13 @@ perform extensive debugging. These `java` options control how garbage collection (GC) is performed by the Java HotSpot VM. -`-XX:+AlwaysPreTouch` +[`-XX:+AlwaysPreTouch`]{#-XX__AlwaysPreTouch} : Requests the VM to touch every page on the Java heap after requesting it from the operating system and before handing memory out to the application. By default, this option is disabled and all pages are committed as the application uses the heap space. -`-XX:ConcGCThreads=`*threads* +[`-XX:ConcGCThreads=`]{#-XX_ConcGCThreads}*threads* : Sets the number of threads used for concurrent GC. Sets *`threads`* to approximately 1/4 of the number of parallel garbage collection threads. The default value depends on the number of CPUs available to the JVM. @@ -2339,24 +2339,24 @@ Java HotSpot VM. > `-XX:ConcGCThreads=2` -`-XX:+DisableExplicitGC` +[`-XX:+DisableExplicitGC`]{#-XX__DisableExplicitGC} : Enables the option that disables processing of calls to the `System.gc()` method. This option is disabled by default, meaning that calls to `System.gc()` are processed. If processing of calls to `System.gc()` is disabled, then the JVM still performs GC when necessary. -`-XX:+ExplicitGCInvokesConcurrent` +[`-XX:+ExplicitGCInvokesConcurrent`]{#-XX__ExplicitGCInvokesConcurrent} : Enables invoking of concurrent GC by using the `System.gc()` request. This option is disabled by default and can be enabled only with the `-XX:+UseG1GC` option. -`-XX:G1AdaptiveIHOPNumInitialSamples=`*number* +[`-XX:G1AdaptiveIHOPNumInitialSamples=`]{#-XX_G1AdaptiveIHOPNumInitialSamples}*number* : When `-XX:UseAdaptiveIHOP` is enabled, this option sets the number of completed marking cycles used to gather samples until G1 adaptively determines the optimum value of `-XX:InitiatingHeapOccupancyPercent`. Before, G1 uses the value of `-XX:InitiatingHeapOccupancyPercent` directly for this purpose. The default value is 3. -`-XX:G1HeapRegionSize=`*size* +[`-XX:G1HeapRegionSize=`]{#-XX_G1HeapRegionSize}*size* : Sets the size of the regions into which the Java heap is subdivided when using the garbage-first (G1) collector. The value is a power of 2 and can range from 1 MB to 32 MB. The default region size is determined @@ -2367,44 +2367,44 @@ Java HotSpot VM. > `-XX:G1HeapRegionSize=16m` -`-XX:G1HeapWastePercent=`*percent* +[`-XX:G1HeapWastePercent=`]{#-XX_G1HeapWastePercent}*percent* : Sets the percentage of heap that you're willing to waste. The Java HotSpot VM doesn't initiate the mixed garbage collection cycle when the reclaimable percentage is less than the heap waste percentage. The default is 5 percent. -`-XX:G1MaxNewSizePercent=`*percent* +[`-XX:G1MaxNewSizePercent=`]{#-XX_G1MaxNewSizePercent}*percent* : Sets the percentage of the heap size to use as the maximum for the young generation size. The default value is 60 percent of your Java heap. This is an experimental flag. This setting replaces the `-XX:DefaultMaxNewGenPercent` setting. -`-XX:G1MixedGCCountTarget=`*number* +[`-XX:G1MixedGCCountTarget=`]{#-XX_G1MixedGCCountTarget}*number* : Sets the target number of mixed garbage collections after a marking cycle to collect old regions with at most `G1MixedGCLIveThresholdPercent` live data. The default is 8 mixed garbage collections. The goal for mixed collections is to be within this target number. -`-XX:G1MixedGCLiveThresholdPercent=`*percent* +[`-XX:G1MixedGCLiveThresholdPercent=`]{#-XX_G1MixedGCLiveThresholdPercent}*percent* : Sets the occupancy threshold for an old region to be included in a mixed garbage collection cycle. The default occupancy is 85 percent. This is an experimental flag. This setting replaces the `-XX:G1OldCSetRegionLiveThresholdPercent` setting. -`-XX:G1NewSizePercent=`*percent* +[`-XX:G1NewSizePercent=`]{#-XX_G1NewSizePercent}*percent* : Sets the percentage of the heap to use as the minimum for the young generation size. The default value is 5 percent of your Java heap. This is an experimental flag. This setting replaces the `-XX:DefaultMinNewGenPercent` setting. -`-XX:G1OldCSetRegionThresholdPercent=`*percent* +[`-XX:G1OldCSetRegionThresholdPercent=`]{#-XX_G1OldCSetRegionThresholdPercent}*percent* : Sets an upper limit on the number of old regions to be collected during a mixed garbage collection cycle. The default is 10 percent of the Java heap. -`-XX:G1ReservePercent=`*percent* +[`-XX:G1ReservePercent=`]{#-XX_G1ReservePercent}*percent* : Sets the percentage of the heap (0 to 50) that's reserved as a false ceiling to reduce the possibility of promotion failure for the G1 collector. When you increase or decrease the percentage, ensure that you @@ -2415,7 +2415,7 @@ Java HotSpot VM. > `-XX:G1ReservePercent=20` -`-XX:+G1UseAdaptiveIHOP` +[`-XX:+G1UseAdaptiveIHOP`]{#-XX__G1UseAdaptiveIHOP} : Controls adaptive calculation of the old generation occupancy to start background work preparing for an old generation collection. If enabled, G1 uses `-XX:InitiatingHeapOccupancyPercent` for the first few times as @@ -2428,7 +2428,7 @@ Java HotSpot VM. The default is enabled. -`-XX:InitialHeapSize=`*size* +[`-XX:InitialHeapSize=`]{#-XX_InitialHeapSize}*size* : Sets the initial size (in bytes) of the memory allocation pool. This value must be either 0, or a multiple of 1024 and greater than 1 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, @@ -2452,7 +2452,7 @@ Java HotSpot VM. command line, then the initial heap size gets set to the value specified with `-Xms`. -`-XX:InitialRAMPercentage=`*percent* +[`-XX:InitialRAMPercentage=`]{#-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. @@ -2462,7 +2462,7 @@ Java HotSpot VM. > `-XX:InitialRAMPercentage=5` -`-XX:InitialSurvivorRatio=`*ratio* +[`-XX:InitialSurvivorRatio=`]{#-XX_InitialSurvivorRatio}*ratio* : Sets the initial survivor space ratio used by the throughput garbage collector (which is enabled by the `-XX:+UseParallelGC` option). Adaptive sizing is enabled by default with the throughput garbage collector by @@ -2491,7 +2491,7 @@ Java HotSpot VM. > `-XX:InitialSurvivorRatio=4` -`-XX:InitiatingHeapOccupancyPercent=`*percent* +[`-XX:InitiatingHeapOccupancyPercent=`]{#-XX_InitiatingHeapOccupancyPercent}*percent* : Sets the percentage of the old generation occupancy (0 to 100) at which to start the first few concurrent marking cycles for the G1 garbage collector. @@ -2506,7 +2506,7 @@ Java HotSpot VM. > `-XX:InitiatingHeapOccupancyPercent=75` -`-XX:MaxGCPauseMillis=`*time* +[`-XX:MaxGCPauseMillis=`]{#-XX_MaxGCPauseMillis}*time* : Sets a target for the maximum GC pause time (in milliseconds). This is a soft goal, and the JVM will make its best effort to achieve it. Only G1 and Parallel support a maximum GC pause time target. For G1, the default @@ -2517,7 +2517,7 @@ Java HotSpot VM. > `-XX:MaxGCPauseMillis=500` -`-XX:MaxHeapSize=`*size* +[`-XX:MaxHeapSize=`]{#-XX_MaxHeapSize}*size* : Sets the maximum size (in byes) of the memory allocation pool. This value must be a multiple of 1024 and greater than 2 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` @@ -2537,7 +2537,7 @@ Java HotSpot VM. The `-XX:MaxHeapSize` option is equivalent to `-Xmx`. -`-XX:MaxHeapFreeRatio=`*percent* +[`-XX:MaxHeapFreeRatio=`]{#-XX_MaxHeapFreeRatio}*percent* : Sets the maximum allowed percentage of free heap space (0 to 100) after a GC event. If free heap space expands above this value, then the heap is shrunk. By default, this value is set to 70%. @@ -2558,7 +2558,7 @@ Java HotSpot VM. description of using this option to keep the Java heap small by reducing the dynamic footprint for embedded applications. -`-XX:MaxMetaspaceSize=`*size* +[`-XX:MaxMetaspaceSize=`]{#-XX_MaxMetaspaceSize}*size* : Sets the maximum amount of native memory that can be allocated for class metadata. By default, the size isn't limited. The amount of metadata for an application depends on the application itself, other running applications, @@ -2569,11 +2569,11 @@ Java HotSpot VM. > `-XX:MaxMetaspaceSize=256m` -`-XX:MaxNewSize=`*size* +[`-XX:MaxNewSize=`]{#-XX_MaxNewSize}*size* : Sets the maximum size (in bytes) of the heap for the young generation (nursery). The default value is set ergonomically. -`-XX:MaxRAMPercentage=`*percent* +[`-XX:MaxRAMPercentage=`]{#-XX_MaxRAMPercentage}*percent* : Sets the maximum amount of memory that the JVM may 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 25 @@ -2589,7 +2589,7 @@ Java HotSpot VM. > `-XX:MaxRAMPercentage=75` -`-XX:MinRAMPercentage=`*percent* +[`-XX:MinRAMPercentage=`]{#-XX_MinRAMPercentage}*percent* : Sets the maximum amount of memory that the JVM may use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount determined as described in the `-XX:MaxRAM` option for small heaps. A small @@ -2600,7 +2600,7 @@ Java HotSpot VM. > `-XX:MinRAMPercentage=75` -`-XX:MaxTenuringThreshold=`*threshold* +[`-XX:MaxTenuringThreshold=`]{#-XX_MaxTenuringThreshold}*threshold* : Sets the maximum tenuring threshold for use in adaptive GC sizing. The largest value is 15. The default value is 15 for the parallel (throughput) collector. @@ -2610,13 +2610,13 @@ Java HotSpot VM. > `-XX:MaxTenuringThreshold=10` -`-XX:MetaspaceSize=`*size* +[`-XX:MetaspaceSize=`]{#-XX_MetaspaceSize}*size* : Sets the size of the allocated class metadata space that triggers a garbage collection the first time it's exceeded. This threshold for a garbage collection is increased or decreased depending on the amount of metadata used. The default size depends on the platform. -`-XX:MinHeapFreeRatio=`*percent* +[`-XX:MinHeapFreeRatio=`]{#-XX_MinHeapFreeRatio}*percent* : Sets the minimum allowed percentage of free heap space (0 to 100) after a GC event. If free heap space falls below this value, then the heap is expanded. By default, this value is set to 40%. @@ -2637,7 +2637,7 @@ Java HotSpot VM. description of using this option to keep the Java heap small by reducing the dynamic footprint for embedded applications. -`-XX:MinHeapSize=`*size* +[`-XX:MinHeapSize=`]{#-XX_MinHeapSize}*size* : Sets the minimum size (in bytes) of the memory allocation pool. This value must be either 0, or a multiple of 1024 and greater than 1 MB. Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, @@ -2656,14 +2656,14 @@ Java HotSpot VM. If you set this option to 0, then the minimum size is set to the same value as the initial size. -`-XX:NewRatio=`*ratio* +[`-XX:NewRatio=`]{#-XX_NewRatio}*ratio* : Sets the ratio between young and old generation sizes. By default, this option is set to 2. The following example shows how to set the young-to-old ratio to 1: > `-XX:NewRatio=1` -`-XX:NewSize=`*size* +[`-XX:NewSize=`]{#-XX_NewSize}*size* : Sets the initial size (in bytes) of the heap for the young generation (nursery). Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate gigabytes. @@ -2687,7 +2687,7 @@ Java HotSpot VM. The `-XX:NewSize` option is equivalent to `-Xmn`. -`-XX:ParallelGCThreads=`*threads* +[`-XX:ParallelGCThreads=`]{#-XX_ParallelGCThreads}*threads* : Sets the number of the stop-the-world (STW) worker threads. The default value depends on the number of CPUs available to the JVM and the garbage collector selected. @@ -2697,11 +2697,11 @@ Java HotSpot VM. > `-XX:ParallelGCThreads=2` -`-XX:+PrintAdaptiveSizePolicy` +[`-XX:+PrintAdaptiveSizePolicy`]{#-XX__PrintAdaptiveSizePolicy} : Enables printing of information about adaptive-generation sizing. By default, this option is disabled. -`-XX:SoftRefLRUPolicyMSPerMB=`*time* +[`-XX:SoftRefLRUPolicyMSPerMB=`]{#-XX_SoftRefLRUPolicyMSPerMB}*time* : Sets the amount of time (in milliseconds) a softly reachable object is kept active on the heap after the last time it was referenced. The default value is one second of lifetime per free megabyte in the heap. The @@ -2718,7 +2718,7 @@ Java HotSpot VM. `-XX:SoftRefLRUPolicyMSPerMB=2500` -`-XX:-ShrinkHeapInSteps` +[`-XX:-ShrinkHeapInSteps`]{#-XX__ShrinkHeapInSteps} : Incrementally reduces the Java heap to the target size, specified by the option `-XX:MaxHeapFreeRatio`. This option is enabled by default. If disabled, then it immediately reduces the Java heap to the target size @@ -2730,7 +2730,7 @@ Java HotSpot VM. `MaxHeapFreeRatio` option to keep the Java heap small by reducing the dynamic footprint for embedded applications. -`-XX:StringDeduplicationAgeThreshold=`*threshold* +[`-XX:StringDeduplicationAgeThreshold=`]{#-XX_StringDeduplicationAgeThreshold}*threshold* : Identifies `String` objects reaching the specified age that are considered candidates for deduplication. An object's age is a measure of how many times it has survived garbage collection. This is sometimes referred to as @@ -2741,14 +2741,14 @@ Java HotSpot VM. default value for this option is `3`. See the `-XX:+UseStringDeduplication` option. -`-XX:SurvivorRatio=`*ratio* +[`-XX:SurvivorRatio=`]{#-XX_SurvivorRatio}*ratio* : Sets the ratio between eden space size and survivor space size. By default, this option is set to 8. The following example shows how to set the eden/survivor space ratio to 4: > `-XX:SurvivorRatio=4` -`-XX:TargetSurvivorRatio=`*percent* +[`-XX:TargetSurvivorRatio=`]{#-XX_TargetSurvivorRatio}*percent* : Sets the desired percentage of survivor space (0 to 100) used after young garbage collection. By default, this option is set to 50%. @@ -2757,7 +2757,7 @@ Java HotSpot VM. > `-XX:TargetSurvivorRatio=30` -`-XX:TLABSize=`*size* +[`-XX:TLABSize=`]{#-XX_TLABSize}*size* : Sets the initial size (in bytes) of a thread-local allocation buffer (TLAB). Append the letter `k` or `K` to indicate kilobytes, `m` or `M` to indicate megabytes, or `g` or `G` to indicate gigabytes. If this option is @@ -2767,13 +2767,13 @@ Java HotSpot VM. > `-XX:TLABSize=512k` -`-XX:+UseAdaptiveSizePolicy` +[`-XX:+UseAdaptiveSizePolicy`]{#-XX__UseAdaptiveSizePolicy} : Enables the use of adaptive generation sizing. This option is enabled by default. To disable adaptive generation sizing, specify `-XX:-UseAdaptiveSizePolicy` and set the size of the memory allocation pool explicitly. See the `-XX:SurvivorRatio` option. -`-XX:+UseG1GC` +[`-XX:+UseG1GC`]{#-XX__UseG1GC} : Enables the use of the garbage-first (G1) garbage collector. It's a server-style garbage collector, targeted for multiprocessor machines with a large amount of RAM. This option meets GC pause time goals with high @@ -2783,7 +2783,7 @@ Java HotSpot VM. pause time below 0.5 seconds). By default, this option is enabled and G1 is used as the default garbage collector. -`-XX:+UseGCOverheadLimit` +[`-XX:+UseGCOverheadLimit`]{#-XX__UseGCOverheadLimit} : Enables the use of a policy that limits the proportion of time spent by the JVM on GC before an `OutOfMemoryError` exception is thrown. This option is enabled, by default, and the parallel GC will throw an `OutOfMemoryError` @@ -2793,26 +2793,26 @@ Java HotSpot VM. little or no progress. To disable this option, specify the option `-XX:-UseGCOverheadLimit`. -`-XX:+UseNUMA` +[`-XX:+UseNUMA`]{#-XX__UseNUMA} : Enables performance optimization of an application on a machine with nonuniform memory architecture (NUMA) by increasing the application's use of lower latency memory. The default value for this option depends on the garbage collector. -`-XX:+UseParallelGC` +[`-XX:+UseParallelGC`]{#-XX__UseParallelGC} : Enables the use of the parallel scavenge garbage collector (also known as the throughput collector) to improve the performance of your application by leveraging multiple processors. By default, this option is disabled and the default collector is used. -`-XX:+UseSerialGC` +[`-XX:+UseSerialGC`]{#-XX__UseSerialGC} : Enables the use of the serial garbage collector. This is generally the best choice for small and simple applications that don't require any special functionality from garbage collection. By default, this option is disabled and the default collector is used. -`-XX:+UseStringDeduplication` +[`-XX:+UseStringDeduplication`]{#-XX__UseStringDeduplication} : Enables string deduplication. By default, this option is disabled. To use this option, you must enable the garbage-first (G1) garbage collector. @@ -2822,34 +2822,34 @@ Java HotSpot VM. character array, identical `String` objects can point to and share the same character array. -`-XX:+UseTLAB` +[`-XX:+UseTLAB`]{#-XX__UseTLAB} : Enables the use of thread-local allocation blocks (TLABs) in the young generation space. This option is enabled by default. To disable the use of TLABs, specify the option `-XX:-UseTLAB`. -`-XX:+UseZGC` +[`-XX:+UseZGC`]{#-XX__UseZGC} : Enables the use of the Z garbage collector (ZGC). This is a low latency garbage collector, providing max pause times of a few milliseconds, at some throughput cost. Pause times are independent of what heap size is used. Supports heap sizes from 8MB to 16TB. -`-XX:ZAllocationSpikeTolerance=`*factor* +[`-XX:ZAllocationSpikeTolerance=`]{#-XX_ZAllocationSpikeTolerance}*factor* : Sets the allocation spike tolerance for ZGC. By default, this option is set to 2.0. This factor describes the level of allocation spikes to expect. For example, using a factor of 3.0 means the current allocation rate can be expected to triple at any time. -`-XX:ZCollectionInterval=`*seconds* +[`-XX:ZCollectionInterval=`]{#-XX_ZCollectionInterval}*seconds* : Sets the maximum interval (in seconds) between two GC cycles when using ZGC. By default, this option is set to 0 (disabled). -`-XX:ZFragmentationLimit=`*percent* +[`-XX:ZFragmentationLimit=`]{#-XX_ZFragmentationLimit}*percent* : Sets the maximum acceptable heap fragmentation (in percent) for ZGC. By default, this option is set to 25. Using a lower value will cause the heap to be compacted more aggressively, to reclaim more memory at the cost of using more CPU time. -`-XX:+ZProactive` +[`-XX:+ZProactive`]{#-XX__ZProactive} : Enables proactive GC cycles when using ZGC. By default, this option is enabled. ZGC will start a proactive GC cycle if doing so is expected to have minimal impact on the running application. This is useful if the @@ -2857,27 +2857,27 @@ Java HotSpot VM. want to keep the heap size down and allow reference processing to happen even when there are a lot of free space on the heap. -`-XX:+ZUncommit` +[`-XX:+ZUncommit`]{#-XX__ZUncommit} : Enables uncommitting of unused heap memory when using ZGC. By default, this option is enabled. Uncommitting unused heap memory will lower the memory footprint of the JVM, and make that memory available for other processes to use. -`-XX:ZUncommitDelay=`*seconds* +[`-XX:ZUncommitDelay=`]{#-XX_ZUncommitDelay}*seconds* : Sets the amount of time (in seconds) that heap memory must have been unused before being uncommitted. By default, this option is set to 300 (5 minutes). Committing and uncommitting memory are relatively expensive operations. Using a lower value will cause heap memory to be uncommitted earlier, at the risk of soon having to commit it again. -`-XX:+UseShenandoahGC` +[`-XX:+UseShenandoahGC`]{#-XX__UseShenandoahGC} : Enables the use of the Shenandoah garbage collector. This is a low pause time, concurrent garbage collector. Its pause times are not proportional to the size of the heap. Shenandoah garbage collector can work with compressed pointers. See `-XX:UseCompressedOops` for further information about compressed pointers. -`-XX:ShenandoahGCMode=`*mode* +[`-XX:ShenandoahGCMode=`]{#-XX_ShenandoahGCMode}*mode* : Sets the GC mode for Shenandoah GC to use. By default, this option is set to `satb`. Among other things, this defines which barriers are in use. Possible mode values include the following: @@ -2891,7 +2891,7 @@ Java HotSpot VM. generational. Please see [JEP 404](https://openjdk.org/jeps/404) and [JEP 521](https://openjdk.org/jeps/521) for its advantages and risks. -`-XX:ShenandoahGCHeuristics=`*heuristics* +[`-XX:ShenandoahGCHeuristics=`]{#-XX_ShenandoahGCHeuristics}*heuristics* : Sets the heuristics for Shenandoah GC to use. By default, this option is set to `adaptive`. This fine-tunes the GC mode selected, by choosing when to start the GC, how much to process on each cycle, and what other features @@ -2916,7 +2916,7 @@ These `java` options are deprecated and might be removed in a future JDK release. They're still accepted and acted upon, but a warning is issued when they're used. -`-Xloggc:`*filename* +[`-Xloggc:`]{#-Xloggc_}*filename* : Sets the file to which verbose GC events information should be redirected for logging. The `-Xloggc` option overrides `-verbose:gc` if both are given with the same java command. `-Xloggc:`*filename* is replaced by @@ -2927,11 +2927,11 @@ they're used. `-Xlog:gc:garbage-collection.log` -`-XX:+FlightRecorder` +[`-XX:+FlightRecorder`]{#-XX__FlightRecorder} : Enables the use of Java Flight Recorder (JFR) during the runtime of the application. Since JDK 8u40 this option has not been required to use JFR. -`-XX:+ParallelRefProcEnabled` +[`-XX:+ParallelRefProcEnabled`]{#-XX__ParallelRefProcEnabled} : Enables parallel reference processing. By default, collectors employing multiple threads perform parallel reference processing if the number of parallel threads to use is larger than one. @@ -2939,7 +2939,7 @@ they're used. (`-XX:+UseParallelGC` or `-XX:+UseG1GC`). Other collectors employing multiple threads always perform reference processing in parallel. -`-XX:MaxRAM=`*size* +[`-XX:MaxRAM=`]{#-XX_MaxRAM}*size* : Sets the maximum amount of memory that the JVM may use for the Java heap before applying ergonomics heuristics. The default value is the amount of available memory to the JVM process. @@ -2958,13 +2958,13 @@ they're used. > `-XX:MaxRAM=2G` -`-XX:+AggressiveHeap` +[`-XX:+AggressiveHeap`]{#-XX__AggressiveHeap} : Enables Java heap optimization. This sets various parameters to be optimal for long-running jobs with intensive memory allocation, based on the configuration of the computer (RAM and CPU). By default, the option is disabled and the heap sizes are configured less aggressively. -`-XX:+NeverActAsServerClassMachine` +[`-XX:+NeverActAsServerClassMachine`]{#-XX__NeverActAsServerClassMachine} : Enable the "Client VM emulation" mode which only uses the C1 JIT compiler, a 32Mb CodeCache and the Serial GC. The maximum amount of memory that the JVM may use (controlled by the `-XX:MaxRAM=n` flag) is set to 1GB by default. @@ -2989,7 +2989,7 @@ they're used. These `java` options are still accepted but ignored, and a warning is issued when they're used. -`--illegal-access=`*parameter* +[`--illegal-access=`]{#--illegal-access}*parameter* : Controlled _relaxed strong encapsulation_, as defined in [JEP 261](https://openjdk.org/jeps/261#Relaxed-strong-encapsulation). This option was deprecated in JDK 16 by [JEP @@ -3570,7 +3570,7 @@ Legacy Runtime Flag Xlog Configuration Comment The following are `-Xlog` examples. -`-Xlog` +[`-Xlog`]{#-Xlog} : Logs all messages by using the `info` level to `stdout` with `uptime`, `levels`, and `tags` decorations. This is equivalent to using: @@ -4075,7 +4075,7 @@ The deployment of the AOT cache is divided into three phases: The AOT cache can be used with the following command-line options: -`-XX:AOTCache=`*cachefile* +[`-XX:AOTCache=`]{#-XX_AOTCache}*cachefile* : Specifies the location of the AOT cache. The standard extension for *cachefile* is `.aot`. This option cannot be used together with `-XX:AOTCacheOutput`. @@ -4084,13 +4084,13 @@ The AOT cache can be used with the following command-line options: The *cachefile* is written by AOT mode `create`. In that case, this option is equivalent to `-XX:AOTCacheOutput=`*cachefile*. -`-XX:AOTCacheOutput=`*cachefile* +[`-XX:AOTCacheOutput=`]{#-XX_AOTCacheOutput}*cachefile* : Specifies the location of the AOT cache to write. The standard extension for *cachefile* is `.aot`. This option cannot be used together with `-XX:AOTCache`. This option is compatible with `AOTMode` settings of `record`, `create`, or `auto` (the default). -`-XX:AOTConfiguration=`*configfile* +[`-XX:AOTConfiguration=`]{#-XX_AOTConfiguration}*configfile* : Specifies the AOT Configuration file for the JVM to write to or read from. The standard extension for *configfile* is `.aotconfig`. @@ -4098,7 +4098,7 @@ The AOT cache can be used with the following command-line options: The *configfile* is read by AOT mode `create`, and written by the other applicable modes. If the AOT mode is `auto`, then `AOTCacheOutput` must also be present. -`-XX:AOTMode=`*mode* +[`-XX:AOTMode=`]{#-XX_AOTMode}*mode* : Specifies the AOT Mode for this run. *mode* must be one of the following: `auto`, `off`, `record`, `create`, or `on`. @@ -4170,7 +4170,7 @@ The AOT cache can be used with the following command-line options: options are compatible with the AOT cache. An alternative is to run your application with `-XX:AOTMode=auto -Xlog:aot` to see if the AOT cache can be used or not. -`-XX:+AOTClassLinking` +[`-XX:+AOTClassLinking`]{#-XX__AOTClassLinking} : If this option is enabled, the JVM will perform more advanced optimizations (such as ahead-of-time resolution of invokedynamic instructions) when creating the AOT cache. As a result, the application will see further improvements diff --git a/src/java.base/unix/native/libjava/ProcessImpl_md.c b/src/java.base/unix/native/libjava/ProcessImpl_md.c index f7531ad5abe..12597fbb650 100644 --- a/src/java.base/unix/native/libjava/ProcessImpl_md.c +++ b/src/java.base/unix/native/libjava/ProcessImpl_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -729,12 +729,13 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, if ((fds[0] == -1 && pipe(in) < 0) || (fds[1] == -1 && pipe(out) < 0) || - (fds[2] == -1 && pipe(err) < 0) || + (fds[2] == -1 && !redirectErrorStream && pipe(err) < 0) || // if not redirecting create the pipe (pipe(childenv) < 0) || (pipe(fail) < 0)) { throwInternalIOException(env, errno, "Bad file descriptor", mode); goto Catch; } + c->fds[0] = fds[0]; c->fds[1] = fds[1]; c->fds[2] = fds[2]; @@ -764,17 +765,19 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, assert(resultPid != 0); if (resultPid < 0) { + char * failMessage = "unknown"; switch (c->mode) { case MODE_VFORK: - throwInternalIOException(env, errno, "vfork failed", c->mode); + failMessage = "vfork failed"; break; case MODE_FORK: - throwInternalIOException(env, errno, "fork failed", c->mode); + failMessage = "fork failed"; break; case MODE_POSIX_SPAWN: - throwInternalIOException(env, errno, "posix_spawn failed", c->mode); + failMessage = "posix_spawn failed"; break; } + throwInternalIOException(env, errno, failMessage, c->mode); goto Catch; } close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */ diff --git a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp index 441a71f5c50..bae16cb0a9c 100644 --- a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp +++ b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +162,7 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre sampleRate, // sample rate DAUDIO_PCM, // only accept PCM bits == 8 ? FALSE : TRUE, // signed - bits == 8 ? FALSE // little-endian for 8bit - : UTIL_IsBigEndianPlatform()); + FALSE); // all supported macOS versions run on LE } } // add default format @@ -175,7 +174,7 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre defSampleRate, // sample rate DAUDIO_PCM, // PCM TRUE, // signed - UTIL_IsBigEndianPlatform()); // native endianness + FALSE); // native endianness; all supported macOS versions run on LE } TRACE0("<drawTitleBar, drawLeftBorder, drawRightBorder and * drawBottomBorder. */ + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { if (isActiveFrame()) { @@ -487,6 +499,7 @@ public class MotifBorders { /** Draws the InternalFrameBorder's top border. */ + @Override protected boolean drawTopBorder(Component c, Graphics g, int x, int y, int width, int height) { if (super.drawTopBorder(c, g, x, y, width, height) && @@ -506,6 +519,7 @@ public class MotifBorders { /** Draws the InternalFrameBorder's left border. */ + @Override protected boolean drawLeftBorder(Component c, Graphics g, int x, int y, int width, int height) { if (super.drawLeftBorder(c, g, x, y, width, height) && @@ -525,6 +539,7 @@ public class MotifBorders { /** Draws the InternalFrameBorder's right border. */ + @Override protected boolean drawRightBorder(Component c, Graphics g, int x, int y, int width, int height) { if (super.drawRightBorder(c, g, x, y, width, height) && @@ -545,6 +560,7 @@ public class MotifBorders { /** Draws the InternalFrameBorder's bottom border. */ + @Override protected boolean drawBottomBorder(Component c, Graphics g, int x, int y, int width, int height) { if (super.drawBottomBorder(c, g, x, y, width, height) && @@ -567,6 +583,7 @@ public class MotifBorders { } // Returns true if the associated internal frame has focus. + @Override protected boolean isActiveFrame() { return frame.isSelected(); } @@ -667,6 +684,7 @@ public class MotifBorders { * @param width the width of the painted border * @param height the height of the painted border */ + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { if (!(c instanceof JPopupMenu)) { return; @@ -713,6 +731,7 @@ public class MotifBorders { * @param c the component for which this border insets value applies * @param insets the object to be reinitialized */ + @Override public Insets getBorderInsets(Component c, Insets insets) { if (!(c instanceof JPopupMenu)) { return insets; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonListener.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonListener.java index a1a74f1230f..65754efed0d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonListener.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class MotifButtonListener extends BasicButtonListener { super(b); } + @Override protected void checkOpacity(AbstractButton b) { b.setOpaque( false ); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java index 08017a0b2c8..0e4c2e526ac 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 MotifButtonUI extends BasicButtonUI { // ******************************** // Create Listeners // ******************************** + @Override protected BasicButtonListener createButtonListener(AbstractButton b){ return new MotifButtonListener(b); } @@ -81,6 +82,7 @@ public class MotifButtonUI extends BasicButtonUI { // ******************************** // Install Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -90,6 +92,7 @@ public class MotifButtonUI extends BasicButtonUI { LookAndFeel.installProperty(b, "opaque", Boolean.FALSE); } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; @@ -106,12 +109,14 @@ public class MotifButtonUI extends BasicButtonUI { // ******************************** // Paint Methods // ******************************** + @Override public void paint(Graphics g, JComponent c) { fillContentArea( g, (AbstractButton)c , c.getBackground() ); super.paint(g,c); } // Overridden to ensure we don't paint icon over button borders. + @Override protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect) { Shape oldClip = g.getClip(); Rectangle newClip = @@ -127,10 +132,12 @@ public class MotifButtonUI extends BasicButtonUI { g.setClip(oldClip); } + @Override protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect){ // focus painting is handled by the border } + @Override protected void paintButtonPressed(Graphics g, AbstractButton b) { fillContentArea( g, b , selectColor ); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxMenuItemUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxMenuItemUI.java index bcaf72cbe26..17d66a74bad 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxMenuItemUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +50,14 @@ public class MotifCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI return new MotifCheckBoxMenuItemUI(); } + @Override protected void installListeners() { super.installListeners(); changeListener = createChangeListener(menuItem); menuItem.addChangeListener(changeListener); } + @Override protected void uninstallListeners() { super.uninstallListeners(); menuItem.removeChangeListener(changeListener); @@ -66,23 +68,28 @@ public class MotifCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI } protected class ChangeHandler implements ChangeListener { + @Override public void stateChanged(ChangeEvent e) { JMenuItem c = (JMenuItem)e.getSource(); LookAndFeel.installProperty(c, "borderPainted", c.isArmed()); } } + @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new MouseInputHandler(); } protected class MouseInputHandler implements MouseInputListener { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); manager.setSelectedPath(getPath()); } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); @@ -99,11 +106,15 @@ public class MotifCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI manager.processMouseEvent(e); } } + @Override public void mouseEntered(MouseEvent e) {} + @Override public void mouseExited(MouseEvent e) {} + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java index fa06aa6bd02..9e9f0008b07 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 MotifCheckBoxUI extends MotifRadioButtonUI { return motifCheckBoxUI; } + @Override public String getPropertyPrefix() { return propertyPrefix; } @@ -67,6 +68,7 @@ public class MotifCheckBoxUI extends MotifRadioButtonUI { // ******************************** // Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -75,6 +77,7 @@ public class MotifCheckBoxUI extends MotifRadioButtonUI { } } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java index d0cea2ec35b..8a6cb918ae4 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +65,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { return new MotifComboBoxUI(); } + @Override public void installUI(JComponent c) { super.installUI(c); arrowIcon = new MotifComboBoxArrowIcon(UIManager.getColor("controlHighlight"), @@ -72,6 +73,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { UIManager.getColor("control")); } + @Override public Dimension getMinimumSize( JComponent c ) { if ( !isMinimumSizeDirty ) { return new Dimension( cachedMinimumSize ); @@ -89,6 +91,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { return size; } + @Override protected ComboPopup createPopup() { return new MotifComboPopup( comboBox ); } @@ -106,10 +109,12 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { /** * Motif combo popup should not track the mouse in the list. */ + @Override public MouseMotionListener createListMouseMotionListener() { return new MouseMotionAdapter() {}; } + @Override public KeyListener createKeyListener() { return super.createKeyListener(); } @@ -121,6 +126,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { } } + @Override protected void installComponents() { if ( comboBox.isEditable() ) { addEditor(); @@ -129,11 +135,13 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { comboBox.add( currentValuePane ); } + @Override protected void uninstallComponents() { removeEditor(); comboBox.removeAll(); } + @Override public void paint(Graphics g, JComponent c) { boolean hasFocus = comboBox.hasFocus(); Rectangle r; @@ -180,6 +188,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { currentValuePane.removeAll(); } + @Override public void paintCurrentValue(Graphics g,Rectangle bounds,boolean hasFocus) { ListCellRenderer renderer = comboBox.getRenderer(); Component c; @@ -226,6 +235,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { return b; } + @Override protected Rectangle rectangleForCurrentValue() { int width = comboBox.getWidth(); int height = comboBox.getHeight(); @@ -251,11 +261,13 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { return arrowIcon.getIconWidth() + (3 * HORIZ_MARGIN) + 2; } + @Override public void configureEditor() { super.configureEditor(); editor.setBackground( UIManager.getColor( "text" ) ); } + @Override protected LayoutManager createLayoutManager() { return new ComboBoxLayoutManager(); } @@ -273,6 +285,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { public ComboBoxLayoutManager() { MotifComboBoxUI.this.super(); } + @Override public void layoutContainer(Container parent) { if ( motifGetEditor() != null ) { Rectangle cvb = rectangleForCurrentValue(); @@ -298,6 +311,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { } + @Override public void paintIcon(Component c, Graphics g, int xo, int yo) { int w = getIconWidth(); int h = getIconHeight(); @@ -322,10 +336,12 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { } + @Override public int getIconWidth() { return 11; } + @Override public int getIconHeight() { return 11; } @@ -336,6 +352,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { * * @since 1.6 */ + @Override protected PropertyChangeListener createPropertyChangeListener() { return new MotifPropertyChangeListener(); } @@ -345,6 +362,7 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { */ private class MotifPropertyChangeListener extends BasicComboBoxUI.PropertyChangeHandler { + @Override public void propertyChange(PropertyChangeEvent e) { super.propertyChange(e); String propertyName = e.getPropertyName(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopIconUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopIconUI.java index b71363d1c0e..872d4992d91 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopIconUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopIconUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 MotifDesktopIconUI extends BasicDesktopIconUI public MotifDesktopIconUI() { } + @Override protected void installDefaults(){ super.installDefaults(); setDefaultIcon(UIManager.getIcon("DesktopIcon.icon")); @@ -94,12 +95,15 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI JLayeredPane.putLayer(desktopIcon, JLayeredPane.getLayer(frame)); } + @Override protected void installComponents(){ } + @Override protected void uninstallComponents(){ } + @Override protected void installListeners(){ super.installListeners(); desktopIconActionListener = createDesktopIconActionListener(); @@ -149,6 +153,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI return new DesktopIconMouseListener(); } + @Override protected void uninstallDefaults(){ super.uninstallDefaults(); desktopIcon.setLayout(null); @@ -156,6 +161,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI desktopIcon.remove(iconLabel); } + @Override protected void uninstallListeners(){ super.uninstallListeners(); iconButton.removeActionListener(desktopIconActionListener); @@ -163,6 +169,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI sysMenuTitlePane.uninstallListeners(); } + @Override public Dimension getMinimumSize(JComponent c) { JInternalFrame iframe = desktopIcon.getInternalFrame(); @@ -180,10 +187,12 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI return new Dimension(w, h); } + @Override public Dimension getPreferredSize(JComponent c) { return getMinimumSize(c); } + @Override public Dimension getMaximumSize(JComponent c){ return getMinimumSize(c); } @@ -213,26 +222,33 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI // Forward mouse events to titlebar for moves. addMouseMotionListener(new MouseMotionListener() { + @Override public void mouseDragged(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseMoved(MouseEvent e) { forwardEventToParent(e); } }); addMouseListener(new MouseListener() { + @Override public void mouseClicked(MouseEvent e) { forwardEventToParent(e); } + @Override public void mousePressed(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseReleased(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseEntered(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseExited(MouseEvent e) { forwardEventToParent(e); } @@ -251,16 +267,19 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI getParent().dispatchEvent(newEvent); } + @Override @SuppressWarnings("deprecation") public boolean isFocusTraversable() { return false; } + @Override public Dimension getMinimumSize() { return new Dimension(defaultIcon.getIconWidth() + 1, LABEL_HEIGHT + LABEL_DIVIDER); } + @Override public Dimension getPreferredSize() { String title = frame.getTitle(); FontMetrics fm = frame.getFontMetrics(defaultTitleFont); @@ -271,6 +290,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI return new Dimension(w, LABEL_HEIGHT + LABEL_DIVIDER); } + @Override public void paint(Graphics g) { super.paint(g); @@ -308,28 +328,35 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI this.icon = icon; // Forward mouse events to titlebar for moves. addMouseMotionListener(new MouseMotionListener() { + @Override public void mouseDragged(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseMoved(MouseEvent e) { forwardEventToParent(e); } }); addMouseListener(new MouseListener() { + @Override public void mouseClicked(MouseEvent e) { forwardEventToParent(e); } + @Override public void mousePressed(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseReleased(MouseEvent e) { if (!systemMenu.isShowing()) { forwardEventToParent(e); } } + @Override public void mouseEntered(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseExited(MouseEvent e) { forwardEventToParent(e); } @@ -347,6 +374,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI getParent().dispatchEvent(newEvent); } + @Override @SuppressWarnings("deprecation") public boolean isFocusTraversable() { return false; @@ -355,6 +383,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI protected class DesktopIconActionListener implements ActionListener { + @Override public void actionPerformed(ActionEvent e){ systemMenu.show(iconButton, 0, getDesktopIcon().getHeight()); } @@ -362,6 +391,7 @@ public class MotifDesktopIconUI extends BasicDesktopIconUI protected class DesktopIconMouseListener extends MouseAdapter { // if we drag or move we should deengage the popup + @Override public void mousePressed(MouseEvent e){ if (e.getClickCount() > 1) { try { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java index 50563a971da..66f253be8c1 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +59,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU public MotifDesktopPaneUI() { } + @Override protected void installDesktopManager() { desktopManager = desktop.getDesktopManager(); if(desktopManager == null) { @@ -75,6 +76,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU //////////////////////////////////////////////////////////////////////////////////// @SuppressWarnings("serial") // Superclass is not serializable across versions private static class DragPane extends JComponent { + @Override public void paint(Graphics g) { g.setColor(Color.darkGray); g.drawRect(0, 0, getWidth()-1, getHeight()-1); @@ -92,6 +94,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU int iconWidth, iconHeight; // PENDING(klobad) this should be optimized + @Override public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) { if(!usingDragPane) { @@ -112,6 +115,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void beginDraggingFrame(JComponent f) { usingDragPane = false; if(f.getParent() instanceof JLayeredPane) { @@ -125,10 +129,12 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void dragFrame(JComponent f, int newX, int newY) { setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight()); } + @Override public void endDraggingFrame(JComponent f) { if(usingDragPane) { layeredPaneForDragPane.remove(dragPane); @@ -143,6 +149,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void beginResizingFrame(JComponent f, int direction) { usingDragPane = false; if(f.getParent() instanceof JLayeredPane) { @@ -157,11 +164,13 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) { setBoundsForFrame(f, newX, newY, newWidth, newHeight); } + @Override public void endResizingFrame(JComponent f) { if(usingDragPane) { JLayeredPane p = (JLayeredPane)f.getParent(); @@ -172,6 +181,7 @@ public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneU } } + @Override public void iconifyFrame(JInternalFrame f) { JInternalFrame.JDesktopIcon icon = f.getDesktopIcon(); Point p = icon.getLocation(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java index 3367b36f0fd..e0be55c9be7 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,7 @@ public class MotifEditorPaneUI extends BasicEditorPaneUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java index 7d820930415..10a193b1271 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifFileChooserUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,6 +141,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { super(filechooser); } + @Override public String getFileName() { if(filenameTextField != null) { return filenameTextField.getText(); @@ -149,30 +150,37 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public void setFileName(String filename) { if(filenameTextField != null) { filenameTextField.setText(filename); } } + @Override public String getDirectoryName() { return pathField.getText(); } + @Override public void setDirectoryName(String dirname) { pathField.setText(dirname); } + @Override public void ensureFileIsVisible(JFileChooser fc, File f) { // PENDING(jeff) } + @Override public void rescanCurrentDirectory(JFileChooser fc) { getModel().validateFileCache(); } + @Override public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) { return new PropertyChangeListener() { + @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if(prop.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) { @@ -266,10 +274,12 @@ public class MotifFileChooserUI extends BasicFileChooserUI { return new MotifFileChooserUI((JFileChooser)c); } + @Override public void installUI(JComponent c) { super.installUI(c); } + @Override public void uninstallUI(JComponent c) { c.removePropertyChangeListener(filterComboBoxModel); approveButton.removeActionListener(getApproveSelectionAction()); @@ -277,11 +287,13 @@ public class MotifFileChooserUI extends BasicFileChooserUI { super.uninstallUI(c); } + @Override public void installComponents(JFileChooser fc) { fc.setLayout(new BorderLayout(10, 10)); fc.setAlignmentX(JComponent.CENTER_ALIGNMENT); JPanel interior = new JPanel() { + @Override public Insets getInsets() { return insets; } @@ -305,6 +317,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } JTextField tmp1 = new JTextField(curDirName, 35) { + @Override public Dimension getMaximumSize() { Dimension d = super.getMaximumSize(); d.height = getPreferredSize().height; @@ -340,6 +353,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { leftPanel.add(l); JComboBox tmp2 = new JComboBox() { + @Override public Dimension getMaximumSize() { Dimension d = super.getMaximumSize(); d.height = getPreferredSize().height; @@ -417,6 +431,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { interior.add(fileNameLabel); JTextField tmp3 = new JTextField(35) { + @Override public Dimension getMaximumSize() { Dimension d = super.getMaximumSize(); d.height = getPreferredSize().height; @@ -441,6 +456,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { buttonPanel.add(Box.createGlue()); JButton tmp4 = new JButton(getApproveButtonText(fc)) { + @Override public Dimension getMaximumSize() { return new Dimension(MAX_SIZE.width, this.getPreferredSize().height); } @@ -456,6 +472,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { buttonPanel.add(Box.createGlue()); JButton updateButton = new JButton(updateButtonText) { + @Override public Dimension getMaximumSize() { return new Dimension(MAX_SIZE.width, this.getPreferredSize().height); } @@ -470,6 +487,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { buttonPanel.add(Box.createGlue()); JButton cancelButton = new JButton(cancelButtonText) { + @Override public Dimension getMaximumSize() { return new Dimension(MAX_SIZE.width, this.getPreferredSize().height); } @@ -484,6 +502,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { buttonPanel.add(Box.createGlue()); JButton helpButton = new JButton(helpButtonText) { + @Override public Dimension getMaximumSize() { return new Dimension(MAX_SIZE.width, this.getPreferredSize().height); } @@ -520,6 +539,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public void uninstallComponents(JFileChooser fc) { fc.removeAll(); bottomPanel = null; @@ -528,6 +548,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override protected void installStrings(JFileChooser fc) { super.installStrings(fc); @@ -555,11 +576,13 @@ public class MotifFileChooserUI extends BasicFileChooserUI { return SwingUtilities2.getUIDefaultsInt(key, l); } + @Override protected void installIcons(JFileChooser fc) { // Since motif doesn't have button icons, leave this empty // which overrides the supertype icon loading } + @Override protected void uninstallIcons(JFileChooser fc) { // Since motif doesn't have button icons, leave this empty // which overrides the supertype icon loading @@ -580,6 +603,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { fileList.addListSelectionListener(createListSelectionListener(getFileChooser())); fileList.addMouseListener(createDoubleClickListener(getFileChooser(), fileList)); fileList.addMouseListener(new MouseAdapter() { + @Override public void mouseClicked(MouseEvent e) { JFileChooser chooser = getFileChooser(); if (SwingUtilities.isLeftMouseButton(e) && !chooser.isMultiSelectionEnabled()) { @@ -650,6 +674,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { @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) { @@ -665,6 +690,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { @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) { @@ -684,18 +710,22 @@ public class MotifFileChooserUI extends BasicFileChooserUI { getModel().addListDataListener(this); } + @Override public int getSize() { return getModel().getDirectories().size(); } + @Override public File getElementAt(int index) { return getModel().getDirectories().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()); } @@ -709,6 +739,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { // PENDING(jeff) - fire the correct interval changed - currently sending // out that everything has changed + @Override public void contentsChanged(ListDataEvent e) { fireContentsChanged(); } @@ -721,6 +752,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { getModel().addListDataListener(this); } + @Override public int getSize() { return getModel().getFiles().size(); } @@ -733,14 +765,17 @@ public class MotifFileChooserUI extends BasicFileChooserUI { return getModel().getFiles().indexOf(o); } + @Override public File getElementAt(int index) { 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()); } @@ -753,6 +788,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } // PENDING(jeff) - fire the interval changed + @Override public void contentsChanged(ListDataEvent e) { fireContentsChanged(); } @@ -779,6 +815,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { */ @SuppressWarnings("serial") // Superclass is not serializable across versions public class FilterComboBoxRenderer extends DefaultListCellRenderer { + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -805,6 +842,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { filters = getFileChooser().getChoosableFileFilters(); } + @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if(prop.equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY)) { @@ -815,6 +853,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public void setSelectedItem(Object filter) { if(filter != null) { getFileChooser().setFileFilter((FileFilter) filter); @@ -822,6 +861,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public Object getSelectedItem() { // Ensure that the current filter is in the list. // NOTE: we shouldn't have to do this, since JFileChooser adds @@ -843,6 +883,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { return getFileChooser().getFileFilter(); } + @Override public int getSize() { if(filters != null) { return filters.length; @@ -851,6 +892,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override public FileFilter getElementAt(int index) { if(index > getSize() - 1) { // This shouldn't happen. Try to recover gracefully. @@ -864,6 +906,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { } } + @Override protected JButton getApproveButton(JFileChooser fc) { return approveButton; } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java index dac6514f0c4..748c4dc6155 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 MotifIconFactory implements Serializable private Color highlight = UIManager.getColor("controlHighlight"); private Color lightShadow = UIManager.getColor("controlLightShadow"); + @Override public void paintIcon(Component c, Graphics g, int x, int y) { AbstractButton b = (AbstractButton) c; ButtonModel model = b.getModel(); @@ -158,10 +159,12 @@ public class MotifIconFactory implements Serializable } } + @Override public int getIconWidth() { return csize; } + @Override public int getIconHeight() { return csize; } @@ -258,6 +261,7 @@ public class MotifIconFactory implements Serializable private Color highlight = UIManager.getColor("controlHighlight"); private Color shadow = UIManager.getColor("controlShadow"); + @Override public void paintIcon(Component c, Graphics g, int x, int y) { // fill interior AbstractButton b = (AbstractButton) c; @@ -303,10 +307,12 @@ public class MotifIconFactory implements Serializable } } + @Override public int getIconWidth() { return 14; } + @Override public int getIconHeight() { return 14; } @@ -315,10 +321,13 @@ public class MotifIconFactory implements Serializable @SuppressWarnings("serial") // Same-version serialization only private static class MenuItemCheckIcon implements Icon, UIResource, Serializable { + @Override public void paintIcon(Component c,Graphics g, int x, int y) { } + @Override public int getIconWidth() { return 0; } + @Override public int getIconHeight() { return 0; } } // end class MenuItemCheckIcon @@ -326,10 +335,13 @@ public class MotifIconFactory implements Serializable @SuppressWarnings("serial") // Same-version serialization only private static class MenuItemArrowIcon implements Icon, UIResource, Serializable { + @Override public void paintIcon(Component c,Graphics g, int x, int y) { } + @Override public int getIconWidth() { return 0; } + @Override public int getIconHeight() { return 0; } } // end class MenuItemArrowIcon @@ -340,6 +352,7 @@ public class MotifIconFactory implements Serializable private Color shadow = UIManager.getColor("controlShadow"); private Color highlight = UIManager.getColor("controlHighlight"); + @Override public void paintIcon(Component c, Graphics g, int x, int y) { AbstractButton b = (AbstractButton) c; ButtonModel model = b.getModel(); @@ -414,7 +427,9 @@ public class MotifIconFactory implements Serializable } } + @Override public int getIconWidth() { return 10; } + @Override public int getIconHeight() { return 10; } } // End class MenuArrowIcon } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameTitlePane.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameTitlePane.java index b68200c1924..474bd707ce4 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameTitlePane.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameTitlePane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,20 +66,24 @@ public class MotifInternalFrameTitlePane super(frame); } + @Override protected void installDefaults() { setFont(UIManager.getFont("InternalFrame.titleFont")); setPreferredSize(new Dimension(100, BUTTON_SIZE)); } + @Override protected void uninstallListeners() { // Get around protected method in superclass super.uninstallListeners(); } + @Override protected PropertyChangeListener createPropertyChangeListener() { return this; } + @Override protected LayoutManager createLayout() { return this; } @@ -88,6 +92,7 @@ public class MotifInternalFrameTitlePane return systemMenu; } + @Override protected void assembleSystemMenu() { systemMenu = new JPopupMenu(); JMenuItem mi = systemMenu.add(restoreAction); @@ -106,12 +111,14 @@ public class MotifInternalFrameTitlePane systemButton = new SystemButton(); systemButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { systemMenu.show(systemButton, 0, BUTTON_SIZE); } }); systemButton.addMouseListener(new MouseAdapter() { + @Override public void mousePressed(MouseEvent evt) { try { frame.setSelected(true); @@ -137,6 +144,7 @@ public class MotifInternalFrameTitlePane } } + @Override protected void createButtons() { minimizeButton = new MinimizeButton(); minimizeButton.addActionListener(iconifyAction); @@ -146,6 +154,7 @@ public class MotifInternalFrameTitlePane } + @Override protected void addSubComponents() { title = new Title(frame.getTitle()); title.setFont(getFont()); @@ -156,6 +165,7 @@ public class MotifInternalFrameTitlePane add(maximizeButton); } + @Override public void paintComponent(Graphics g) { } @@ -165,9 +175,11 @@ public class MotifInternalFrameTitlePane shadow = s; } + @Override public void actionPerformed(ActionEvent e) { } + @Override public void propertyChange(PropertyChangeEvent evt) { String prop = evt.getPropertyName(); JInternalFrame f = (JInternalFrame)evt.getSource(); @@ -194,16 +206,21 @@ public class MotifInternalFrameTitlePane enableActions(); } + @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) { return new Dimension(100, BUTTON_SIZE); } + @Override public void layoutContainer(Container c) { int w = getWidth(); systemButton.setBounds(0, 0, BUTTON_SIZE, BUTTON_SIZE); @@ -226,6 +243,7 @@ public class MotifInternalFrameTitlePane title.setBounds(BUTTON_SIZE, 0, x, BUTTON_SIZE); } + @Override protected void showSystemMenu(){ systemMenu.show(systemButton, 0, BUTTON_SIZE); } @@ -245,23 +263,28 @@ public class MotifInternalFrameTitlePane setBorderPainted(false); } + @Override @SuppressWarnings("deprecation") public boolean isFocusTraversable() { return false; } + @Override public void requestFocus() { // ignore request. } + @Override public Dimension getMinimumSize() { return buttonDimension; } + @Override public Dimension getPreferredSize() { return buttonDimension; } + @Override public void paintComponent(Graphics g) { Dimension d = getSize(); int maxX = d.width - 1; @@ -284,6 +307,7 @@ public class MotifInternalFrameTitlePane @SuppressWarnings("serial") // Superclass is not serializable across versions private class MinimizeButton extends FrameButton { + @Override public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(highlight); @@ -297,6 +321,7 @@ public class MotifInternalFrameTitlePane @SuppressWarnings("serial") // Superclass is not serializable across versions private class MaximizeButton extends FrameButton { + @Override public void paintComponent(Graphics g) { super.paintComponent(g); int max = BUTTON_SIZE - 5; @@ -312,9 +337,12 @@ public class MotifInternalFrameTitlePane @SuppressWarnings("serial") // Superclass is not serializable across versions private class SystemButton extends FrameButton { + @Override public boolean isFocusTraversable() { return false; } + @Override public void requestFocus() {} + @Override public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(highlight); @@ -339,26 +367,33 @@ public class MotifInternalFrameTitlePane // Forward mouse events to titlebar for moves. addMouseMotionListener(new MouseMotionListener() { + @Override public void mouseDragged(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseMoved(MouseEvent e) { forwardEventToParent(e); } }); addMouseListener(new MouseListener() { + @Override public void mouseClicked(MouseEvent e) { forwardEventToParent(e); } + @Override public void mousePressed(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseReleased(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseEntered(MouseEvent e) { forwardEventToParent(e); } + @Override public void mouseExited(MouseEvent e) { forwardEventToParent(e); } @@ -377,6 +412,7 @@ public class MotifInternalFrameTitlePane getParent().dispatchEvent(newEvent); } + @Override public void paintComponent(Graphics g) { super.paintComponent(g); if (frame.isSelected()) { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java index 1179df181ab..678686a9b17 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,11 +81,13 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { super(w); } + @Override public void installUI(JComponent c) { super.installUI(c); setColors((JInternalFrame)c); } + @Override protected void installDefaults() { Border frameBorder = frame.getBorder(); frame.setLayout(internalFrameLayout = createLayoutManager()); @@ -95,6 +97,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { } + @Override protected void installKeyboardActions(){ super.installKeyboardActions(); // We replace the @@ -103,6 +106,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { } + @Override protected void uninstallDefaults() { LookAndFeel.uninstallBorder(frame); frame.setLayout(null); @@ -113,15 +117,18 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { return frame; } + @Override public JComponent createNorthPane(JInternalFrame w) { titlePane = new MotifInternalFrameTitlePane(w); return titlePane; } + @Override public Dimension getMaximumSize(JComponent x) { return Toolkit.getDefaultToolkit().getScreenSize(); } + @Override protected void uninstallKeyboardActions(){ super.uninstallKeyboardActions(); if (isKeyBindingRegistered()){ @@ -132,6 +139,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { } } + @Override protected void setupMenuOpenKey(){ super.setupMenuOpenKey(); ActionMap map = SwingUtilities.getUIActionMap(frame); @@ -141,9 +149,11 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { // titlePane ivar in BasicInternalFrameUI, making supers action throw // an NPE for us. map.put("showSystemMenu", new AbstractAction(){ + @Override public void actionPerformed(ActionEvent e){ titlePane.showSystemMenu(); } + @Override public boolean isEnabled(){ return isKeyBindingActive(); } @@ -151,13 +161,16 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { } } + @Override protected void setupMenuCloseKey(){ ActionMap map = SwingUtilities.getUIActionMap(frame); if (map != null) { map.put("hideSystemMenu", new AbstractAction(){ + @Override public void actionPerformed(ActionEvent e){ titlePane.hideSystemMenu(); } + @Override public boolean isEnabled(){ return isKeyBindingActive(); } @@ -184,6 +197,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { if (diActionMap == null) { diActionMap = new ActionMapUIResource(); diActionMap.put("hideSystemMenu", new AbstractAction(){ + @Override public void actionPerformed(ActionEvent e){ JInternalFrame.JDesktopIcon icon = getFrame(). getDesktopIcon(); @@ -191,6 +205,7 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { getUI(); micon.hideSystemMenu(); } + @Override public boolean isEnabled(){ return isKeyBindingActive(); } @@ -201,12 +216,14 @@ public class MotifInternalFrameUI extends BasicInternalFrameUI { /** This method is called when the frame becomes selected. */ + @Override protected void activateFrame(JInternalFrame f) { super.activateFrame(f); setColors(f); } /** This method is called when the frame is no longer selected. */ + @Override protected void deactivateFrame(JInternalFrame f) { setColors(f); super.deactivateFrame(f); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java index aaeb0243ce7..d254443b8d1 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,24 +56,29 @@ import sun.swing.SwingUtilities2; @Deprecated(since="13", forRemoval=true) public class MotifLookAndFeel extends BasicLookAndFeel { + @Override public String getName() { return "CDE/Motif"; } + @Override public String getID() { return "Motif"; } + @Override public String getDescription() { return "The CDE/Motif Look and Feel"; } + @Override public boolean isNativeLookAndFeel() { return false; } + @Override public boolean isSupportedLookAndFeel() { return true; } @@ -87,6 +92,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel * values, otherwise we create color objects whose values match * the default CDE/Motif colors. */ + @Override protected void initSystemColorDefaults(UIDefaults table) { String[] defaultSystemColors = { @@ -123,6 +129,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel } + @Override protected void initClassDefaults(UIDefaults table) { super.initClassDefaults(table); @@ -178,6 +185,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel } + @Override protected void initComponentDefaults(UIDefaults table) { super.initComponentDefaults(table); @@ -255,36 +263,42 @@ public class MotifLookAndFeel extends BasicLookAndFeel )); Object menuItemCheckIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getMenuItemCheckIcon(); } }; Object menuItemArrowIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getMenuItemArrowIcon(); } }; Object menuArrowIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getMenuArrowIcon(); } }; Object checkBoxIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getCheckBoxIcon(); } }; Object radioButtonIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifIconFactory.getRadioButtonIcon(); } }; Object unselectedTabBackground = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { Color c = table.getColor("control"); return new ColorUIResource(Math.max((int)(c.getRed()*.85),0), @@ -294,6 +308,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel }; Object unselectedTabForeground = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { Color c = table.getColor("controlText"); return new ColorUIResource(Math.max((int)(c.getRed()*.85),0), @@ -303,6 +318,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel }; Object unselectedTabShadow = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { Color c = table.getColor("control"); Color base = new Color(Math.max((int)(c.getRed()*.85),0), @@ -313,6 +329,7 @@ public class MotifLookAndFeel extends BasicLookAndFeel }; Object unselectedTabHighlight = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { Color c = table.getColor("control"); Color base = new Color(Math.max((int)(c.getRed()*.85),0), @@ -462,18 +479,21 @@ public class MotifLookAndFeel extends BasicLookAndFeel "icons/TreeClosed.gif"); Object treeLeafIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifTreeCellRenderer.loadLeafIcon(); } }; Object treeExpandedIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifTreeUI.MotifExpandedIcon.createExpandedIcon(); } }; Object treeCollapsedIcon = new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return MotifTreeUI.MotifCollapsedIcon.createCollapsedIcon(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuItemUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuItemUI.java index 52116aaf588..50ea704c73a 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuItemUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +50,14 @@ public class MotifMenuItemUI extends BasicMenuItemUI return new MotifMenuItemUI(); } + @Override protected void installListeners() { super.installListeners(); changeListener = createChangeListener(menuItem); menuItem.addChangeListener(changeListener); } + @Override protected void uninstallListeners() { super.uninstallListeners(); menuItem.removeChangeListener(changeListener); @@ -65,12 +67,14 @@ public class MotifMenuItemUI extends BasicMenuItemUI return new ChangeHandler(); } + @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new MouseInputHandler(); } protected class ChangeHandler implements ChangeListener { + @Override public void stateChanged(ChangeEvent e) { JMenuItem c = (JMenuItem)e.getSource(); LookAndFeel.installProperty(c, "borderPainted", @@ -79,11 +83,14 @@ public class MotifMenuItemUI extends BasicMenuItemUI } protected class MouseInputHandler implements MouseInputListener { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); manager.setSelectedPath(getPath()); } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); @@ -97,11 +104,15 @@ public class MotifMenuItemUI extends BasicMenuItemUI manager.processMouseEvent(e); } } + @Override public void mouseEntered(MouseEvent e) {} + @Override public void mouseExited(MouseEvent e) {} + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseListener.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseListener.java index 93f4d2c731c..c3f8e7c9ece 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseListener.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +33,19 @@ import javax.swing.MenuSelectionManager; * @author Arnaud Weber */ class MotifMenuMouseListener extends MouseAdapter { + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseEntered(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseExited(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseMotionListener.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseMotionListener.java index 22fcd908a11..8171ad8934d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseMotionListener.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuMouseMotionListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +33,12 @@ import javax.swing.MenuSelectionManager; * @author Arnaud Weber */ class MotifMenuMouseMotionListener implements MouseMotionListener { + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java index bcee2e666fa..5bf2b1e0503 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 MotifMenuUI extends BasicMenuUI // menuItem.removeChangeListener(changeListener); // } + @Override protected ChangeListener createChangeListener(JComponent c) { return new MotifChangeHandler((JMenu)c, this); } @@ -76,6 +77,7 @@ public class MotifMenuUI extends BasicMenuUI return false; } + @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new MouseInputHandler(); } @@ -86,6 +88,7 @@ public class MotifMenuUI extends BasicMenuUI } + @Override public void stateChanged(ChangeEvent e) { JMenuItem c = (JMenuItem)e.getSource(); if (c.isArmed() || c.isSelected()) { @@ -100,7 +103,9 @@ public class MotifMenuUI extends BasicMenuUI } protected class MouseInputHandler implements MouseInputListener { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); JMenu menu = (JMenu)e.getComponent(); @@ -129,6 +134,7 @@ public class MotifMenuUI extends BasicMenuUI } } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); @@ -139,11 +145,15 @@ public class MotifMenuUI extends BasicMenuUI manager.processMouseEvent(e); } } + @Override public void mouseEntered(MouseEvent e) {} + @Override public void mouseExited(MouseEvent e) {} + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { } } 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 21e8c0f6747..641d5ec1b99 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, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +57,7 @@ public class MotifOptionPaneUI extends BasicOptionPaneUI * Creates and returns a Container containing the buttons. The buttons * are created by calling getButtons. */ + @Override protected Container createButtonArea() { Container b = super.createButtonArea(); @@ -69,17 +70,21 @@ public class MotifOptionPaneUI extends BasicOptionPaneUI /** * Returns null, CDE/Motif does not impose a minimum size. */ + @Override public Dimension getMinimumOptionPaneSize() { return null; } + @Override protected Container createSeparator() { return new JPanel() { + @Override public Dimension getPreferredSize() { return new Dimension(10, 2); } + @Override public void paint(Graphics g) { int width = getWidth(); g.setColor(Color.darkGray); @@ -95,6 +100,7 @@ public class MotifOptionPaneUI extends BasicOptionPaneUI * getIcon to top. This is messaged from * createMessageArea */ + @Override protected void addIcon(Container top) { /* Create the icon. */ Icon sideIcon = getIcon(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java index 8e1369d7e96..b906329d353 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,7 @@ public class MotifPasswordFieldUI extends BasicPasswordFieldUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuSeparatorUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuSeparatorUI.java index 164b3227034..5556695429e 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuSeparatorUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuSeparatorUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class MotifPopupMenuSeparatorUI extends MotifSeparatorUI return new MotifPopupMenuSeparatorUI(); } + @Override public void paint( Graphics g, JComponent c ) { Dimension s = c.getSize(); @@ -58,6 +59,7 @@ public class MotifPopupMenuSeparatorUI extends MotifSeparatorUI g.drawLine( 0, 1, s.width, 1 ); } + @Override public Dimension getPreferredSize( JComponent c ) { return new Dimension( 0, 2 ); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java index 0986f81f0ff..6012152905a 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 MotifPopupMenuUI extends BasicPopupMenuUI { /* This has to deal with the fact that the title may be wider than the widest child component. */ + @Override public Dimension getPreferredSize(JComponent c) { LayoutManager layout = c.getLayout(); Dimension d = layout.preferredLayoutSize(c); @@ -94,10 +95,12 @@ public class MotifPopupMenuUI extends BasicPopupMenuUI { protected ChangeListener createChangeListener(JPopupMenu m) { return new ChangeListener() { + @Override public void stateChanged(ChangeEvent e) {} }; } + @Override @SuppressWarnings("deprecation") public boolean isPopupTrigger(MouseEvent e) { return ((e.getID()==MouseEvent.MOUSE_PRESSED) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java index 1a9d7fa1e91..914c305fa08 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +55,14 @@ public class MotifRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI return new MotifRadioButtonMenuItemUI(); } + @Override protected void installListeners() { super.installListeners(); changeListener = createChangeListener(menuItem); menuItem.addChangeListener(changeListener); } + @Override protected void uninstallListeners() { super.uninstallListeners(); menuItem.removeChangeListener(changeListener); @@ -72,23 +74,28 @@ public class MotifRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI @SuppressWarnings("serial") // Same-version serialization only protected class ChangeHandler implements ChangeListener, Serializable { + @Override public void stateChanged(ChangeEvent e) { JMenuItem c = (JMenuItem)e.getSource(); LookAndFeel.installProperty(c, "borderPainted", c.isArmed()); } } + @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new MouseInputHandler(); } protected class MouseInputHandler implements MouseInputListener { + @Override public void mouseClicked(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); manager.setSelectedPath(getPath()); } + @Override public void mouseReleased(MouseEvent e) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); @@ -105,11 +112,15 @@ public class MotifRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI manager.processMouseEvent(e); } } + @Override public void mouseEntered(MouseEvent e) {} + @Override public void mouseExited(MouseEvent e) {} + @Override public void mouseDragged(MouseEvent e) { MenuSelectionManager.defaultManager().processMouseEvent(e); } + @Override public void mouseMoved(MouseEvent e) { } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java index 58619280493..f9a1dd7bb50 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +68,7 @@ public class MotifRadioButtonUI extends BasicRadioButtonUI { // ******************************** // Install Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -76,6 +77,7 @@ public class MotifRadioButtonUI extends BasicRadioButtonUI { } } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; @@ -92,6 +94,7 @@ public class MotifRadioButtonUI extends BasicRadioButtonUI { // ******************************** // Paint Methods // ******************************** + @Override protected void paintFocus(Graphics g, Rectangle t, Dimension d){ g.setColor(getFocusColor()); g.drawRect(0,0,d.width-1,d.height-1); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java index 5b812ca4c8c..2f5eb9708b3 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +64,7 @@ public class MotifScrollBarButton extends BasicArrowButton } + @Override public Dimension getPreferredSize() { switch (direction) { case NORTH: @@ -76,18 +77,22 @@ public class MotifScrollBarButton extends BasicArrowButton } } + @Override public Dimension getMinimumSize() { return getPreferredSize(); } + @Override public Dimension getMaximumSize() { return getPreferredSize(); } + @Override public boolean isFocusTraversable() { return false; } + @Override public void paint(Graphics g) { int w = getWidth(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java index 08a283f5e52..48cee86636b 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 MotifScrollBarUI extends BasicScrollBarUI return new MotifScrollBarUI(); } + @Override public Dimension getPreferredSize(JComponent c) { Insets insets = c.getInsets(); int dx = insets.left + insets.right; @@ -61,19 +62,23 @@ public class MotifScrollBarUI extends BasicScrollBarUI : new Dimension(dx + 33, dy + 11); } + @Override protected JButton createDecreaseButton(int orientation) { return new MotifScrollBarButton(orientation); } + @Override protected JButton createIncreaseButton(int orientation) { return new MotifScrollBarButton(orientation); } + @Override public void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) { g.setColor(trackColor); g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height); } + @Override public void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) { if (thumbBounds.isEmpty() || !scrollbar.isEnabled()) { return; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java index c8820de17c4..c6afd5ce953 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,22 +64,27 @@ public class MotifSliderUI extends BasicSliderUI { return new MotifSliderUI((JSlider)b); } + @Override public Dimension getPreferredHorizontalSize() { return PREFERRED_HORIZONTAL_SIZE; } + @Override public Dimension getPreferredVerticalSize() { return PREFERRED_VERTICAL_SIZE; } + @Override public Dimension getMinimumHorizontalSize() { return MINIMUM_HORIZONTAL_SIZE; } + @Override public Dimension getMinimumVerticalSize() { return MINIMUM_VERTICAL_SIZE; } + @Override protected Dimension getThumbSize() { if ( slider.getOrientation() == JSlider.HORIZONTAL ) { return new Dimension( 30, 15 ); @@ -89,12 +94,15 @@ public class MotifSliderUI extends BasicSliderUI { } } + @Override public void paintFocus(Graphics g) { } + @Override public void paintTrack(Graphics g) { } + @Override public void paintThumb(Graphics g) { Rectangle knobBounds = thumbRect; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java index ba8f0efde4d..21cc1f7c38b 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,6 +84,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider * overrides to hardcode the size of the divider * PENDING(jeff) - rewrite JSplitPane so that this isn't needed */ + @Override public void setDividerSize(int newSize) { Insets insets = getInsets(); int borderSize = 0; @@ -109,6 +110,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider */ // PENDING(jeff) - the thumb's location and size is currently hard coded. // It should be dynamic. + @Override public void paint(Graphics g) { Color bgColor = getBackground(); Dimension size = getSize(); @@ -179,6 +181,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider /** * The minimums size is the same as the preferredSize */ + @Override public Dimension getMinimumSize() { return getPreferredSize(); } @@ -187,6 +190,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider * Sets the SplitPaneUI that is using the receiver. This is completely * overridden from super to create a different MouseHandler. */ + @Override public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) { if (splitPane != null) { splitPane.removePropertyChangeListener(this); @@ -268,6 +272,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider * in. */ private class MotifMouseHandler extends MouseHandler { + @Override public void mousePressed(MouseEvent e) { // Constrain the mouse pressed to the thumb. if (e.getSource() == MotifSplitPaneDivider.this && @@ -277,6 +282,7 @@ public class MotifSplitPaneDivider extends BasicSplitPaneDivider } } + @Override public void mouseMoved(MouseEvent e) { if (getDragger() != null) { return; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java index c61a1713c9b..90ce672f5c9 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +51,7 @@ public class MotifSplitPaneUI extends BasicSplitPaneUI /** * Creates the default divider. */ + @Override public BasicSplitPaneDivider createDefaultDivider() { return new MotifSplitPaneDivider(this); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java index 1c53fc4a179..2b1e9482f9d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 MotifTabbedPaneUI extends BasicTabbedPaneUI // UI Installation/De-installation + @Override protected void installDefaults() { super.installDefaults(); @@ -70,6 +71,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI unselectedTabHighlight = UIManager.getColor("TabbedPane.unselectedTabHighlight"); } + @Override protected void uninstallDefaults() { super.uninstallDefaults(); @@ -81,6 +83,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI // UI Rendering + @Override protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { @@ -104,6 +107,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } } + @Override protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { @@ -126,6 +130,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } } + @Override protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { @@ -148,6 +153,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } } + @Override protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, @@ -174,6 +180,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } + @Override protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, @@ -225,6 +232,7 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } + @Override protected void paintFocusIndicator(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect, @@ -263,10 +271,12 @@ public class MotifTabbedPaneUI extends BasicTabbedPaneUI } } + @Override protected int getTabRunIndent(int tabPlacement, int run) { return run*3; } + @Override protected int getTabRunOverlay(int tabPlacement) { tabRunOverlay = (tabPlacement == LEFT || tabPlacement == RIGHT)? (int)Math.round((float)maxTabWidth * .10) : diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java index baddbf3a75d..f71dfe3c30d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +57,7 @@ public class MotifTextAreaUI extends BasicTextAreaUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java index 08437687ebc..8e64aa02a63 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,7 @@ public class MotifTextFieldUI extends BasicTextFieldUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java index e47ad4c60bf..fabbbb204d0 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,7 @@ public class MotifTextPaneUI extends BasicTextPaneUI { * * @return the caret object */ + @Override protected Caret createCaret() { return MotifTextUI.createCaret(); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java index b79ef19df8e..6e2e1059176 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 MotifTextUI { * @param e the focus event * @see FocusListener#focusGained */ + @Override public void focusGained(FocusEvent e) { super.focusGained(e); getComponent().repaint(); @@ -88,6 +89,7 @@ public class MotifTextUI { * @param e the focus event * @see FocusListener#focusLost */ + @Override public void focusLost(FocusEvent e) { super.focusLost(e); getComponent().repaint(); @@ -101,6 +103,7 @@ public class MotifTextUI { * @param r the current location of the caret, does nothing if null * @see #paint */ + @Override protected void damage(Rectangle r) { if (r != null) { x = r.x - IBeamOverhang - 1; @@ -121,6 +124,7 @@ public class MotifTextUI { * @param g the graphics context * @see #damage */ + @Override @SuppressWarnings("deprecation") public void paint(Graphics g) { if(isVisible()) { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java index eef60ade9c9..7997145e648 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +71,7 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI // ******************************** // Install Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -80,6 +81,7 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI LookAndFeel.installProperty(b, "opaque", Boolean.FALSE); } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; @@ -96,6 +98,7 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI // ******************************** // Paint Methods // ******************************** + @Override protected void paintButtonPressed(Graphics g, AbstractButton b) { if (b.isContentAreaFilled()) { Color oldColor = g.getColor(); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java index 78ec251f05d..b060c62f24b 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +70,7 @@ public class MotifTreeCellRenderer extends DefaultTreeCellRenderer highlight = UIManager.getColor("Tree.iconHighlight"); } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(bg); @@ -90,10 +91,12 @@ public class MotifTreeCellRenderer extends DefaultTreeCellRenderer g.drawLine(x + 9, y + 8, x + 7, y + 6); } + @Override public int getIconWidth() { return LEAF_SIZE; } + @Override public int getIconHeight() { return LEAF_SIZE; } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java index 468ef4eb565..11313b9ad12 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +54,14 @@ public class MotifTreeUI extends BasicTreeUI super(); } + @Override public void installUI(JComponent c) { super.installUI(c); } // BasicTreeUI overrides + @Override protected void paintVerticalLine( Graphics g, JComponent c, int x, int top, int bottom ) { if (tree.getComponentOrientation().isLeftToRight()) { @@ -69,6 +71,7 @@ public class MotifTreeUI extends BasicTreeUI } } + @Override protected void paintHorizontalLine( Graphics g, JComponent c, int y, int left, int right ) { g.fillRect( left, y, right - left + 1, 2 ); @@ -96,6 +99,7 @@ public class MotifTreeUI extends BasicTreeUI return new MotifExpandedIcon(); } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(highlight); g.drawLine(x, y, x+SIZE-1, y); @@ -113,7 +117,9 @@ public class MotifTreeUI extends BasicTreeUI g.drawLine(x+3, y+HALF_SIZE, x+SIZE-4, y+HALF_SIZE); } + @Override public int getIconWidth() { return SIZE; } + @Override public int getIconHeight() { return SIZE; } } @@ -126,6 +132,7 @@ public class MotifTreeUI extends BasicTreeUI return new MotifCollapsedIcon(); } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { super.paintIcon(c, g, x, y); g.drawLine(x + HALF_SIZE-1, y + 3, x + HALF_SIZE-1, y + (SIZE - 4)); @@ -141,6 +148,7 @@ public class MotifTreeUI extends BasicTreeUI * Returns the default cell renderer that is used to do the * stamping of each node. */ + @Override public TreeCellRenderer createDefaultCellRenderer() { return new MotifTreeCellRenderer(); } diff --git a/src/java.desktop/share/classes/com/sun/media/sound/Platform.java b/src/java.desktop/share/classes/com/sun/media/sound/Platform.java index ba03798f1fb..a0db2a421d1 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/Platform.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * 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.media.sound; +import java.nio.ByteOrder; import java.util.StringTokenizer; /** @@ -40,12 +41,6 @@ final class Platform { private static boolean isNativeLibLoaded; - // SYSTEM CHARACTERISTICS - // vary according to hardware architecture - - // intel is little-endian. sparc is big-endian. - private static boolean bigEndian; - static { loadLibraries(); } @@ -66,7 +61,7 @@ final class Platform { * Determine whether the system is big-endian. */ static boolean isBigEndian() { - return bigEndian; + return ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN); } /** @@ -82,9 +77,6 @@ final class Platform { if (Printer.err) Printer.err("Couldn't load library "+libName+": "+t.toString()); isNativeLibLoaded = false; } - if (isNativeLibLoaded) { - bigEndian = nIsBigEndian(); - } } static boolean isMidiIOEnabled() { @@ -98,7 +90,4 @@ final class Platform { static boolean isDirectAudioEnabled() { return isNativeLibLoaded; } - - // the following native method is implemented in Platform.c - private static native boolean nIsBigEndian(); } diff --git a/src/java.desktop/share/classes/javax/imageio/ImageIO.java b/src/java.desktop/share/classes/javax/imageio/ImageIO.java index 8180145a8ea..5d3526df917 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageIO.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageIO.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,6 @@ import javax.imageio.spi.ImageTranscoderSpi; import javax.imageio.spi.ServiceRegistry; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; -import sun.awt.AppContext; /** * A class containing static convenience methods for locating @@ -108,9 +107,7 @@ public final class ImageIO { // ImageInputStreams /** - * A class to hold information about caching. Each - * {@code ThreadGroup} will have its own copy - * via the {@code AppContext} mechanism. + * A class to hold information about caching. */ static class CacheInfo { boolean useCache = true; @@ -144,17 +141,12 @@ public final class ImageIO { } } + private static final CacheInfo info = new CacheInfo(); + /** - * Returns the {@code CacheInfo} object associated with this - * {@code ThreadGroup}. + * Returns the {@code CacheInfo} object. */ private static synchronized CacheInfo getCacheInfo() { - AppContext context = AppContext.getAppContext(); - CacheInfo info = (CacheInfo)context.get(CacheInfo.class); - if (info == null) { - info = new CacheInfo(); - context.put(CacheInfo.class, info); - } return info; } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java index 5ff68f78d38..270181f4600 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1405,7 +1405,7 @@ public class BasicSplitPaneUI extends SplitPaneUI // If the splitpane has a zero size then no op out of here. // If we execute this function now, we're going to cause ourselves // much grief. - if (containerSize.height <= 0 || containerSize.width <= 0 ) { + if (containerSize.height <= 0 && containerSize.width <= 0 ) { lastSplitPaneSize = 0; return; } diff --git a/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java b/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java index cac9f8baab2..bc025b87f3c 100644 --- a/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java +++ b/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +92,8 @@ public class XbmImageDecoder extends ImageDecoder { byte[] raster = null; IndexColorModel model = null; - String matchRegex = "(0[xX])?[0-9a-fA-F]+[\\s+]?[,|};]"; - String replaceRegex = "(0[xX])|,|[\\s+]|[};]"; + String matchRegex = "\\s*(0[xX])?((?:(?!,|\\};).)+)(,|\\};)"; + String replaceRegex = "0[xX]|,|\\s+|\\};"; String line; int lineNum = 0; @@ -111,11 +111,19 @@ public class XbmImageDecoder extends ImageDecoder { } try { if (!token[2].isBlank() && state == 0) { - W = Integer.parseInt(token[2]); - state = 1; // after width is set + if (token[1].endsWith("th")) { + W = Integer.parseInt(token[2]); + } else if (token[1].endsWith("t")) { + H = Integer.parseInt(token[2]); + } + state = 1; // after first dimension is set } else if (!token[2].isBlank() && state == 1) { - H = Integer.parseInt(token[2]); - state = 2; // after height is set + if (token[1].endsWith("th")) { + W = Integer.parseInt(token[2]); + } else if (token[1].endsWith("t")) { + H = Integer.parseInt(token[2]); + } + state = 2; // after second dimension is set } } catch (NumberFormatException nfe) { // parseInt() can throw NFE @@ -147,59 +155,81 @@ public class XbmImageDecoder extends ImageDecoder { error("Width or Height of XBM file not defined"); } + boolean contFlag = false; + StringBuilder sb = new StringBuilder(); + // loop to process image data while (!aborted && (line = br.readLine()) != null) { lineNum++; - if (line.contains("[]")) { - Matcher matcher = Pattern.compile(matchRegex).matcher(line); - while (matcher.find()) { - if (y >= H) { - error("Scan size of XBM file exceeds" - + " the defined width x height"); - } - - int startIndex = matcher.start(); - int endIndex = matcher.end(); - String hexByte = line.substring(startIndex, endIndex); - - if (!(hexByte.startsWith("0x") - || hexByte.startsWith("0X"))) { - error("Invalid hexadecimal number at Ln#:" + lineNum - + " Col#:" + (startIndex + 1)); - } - hexByte = hexByte.replaceAll(replaceRegex, ""); - if (hexByte.length() != 2) { - error("Invalid hexadecimal number at Ln#:" + lineNum - + " Col#:" + (startIndex + 1)); - } - - try { - n = Integer.parseInt(hexByte, 16); - } catch (NumberFormatException nfe) { - error("Error parsing hexadecimal at Ln#:" + lineNum - + " Col#:" + (startIndex + 1)); - } - for (int mask = 1; mask <= 0x80; mask <<= 1) { - if (x < W) { - if ((n & mask) != 0) - raster[x] = 1; - else - raster[x] = 0; - } - x++; - } - - if (x >= W) { - int result = setPixels(0, y, W, 1, model, raster, 0, W); - if (result <= 0) { - error("Unexpected error occurred during setPixel()"); - } - x = 0; - y++; - } + if (!contFlag) { + if (line.contains("[]")) { + contFlag = true; + } else { + continue; } } + + int end = line.indexOf(';'); + if (end >= 0) { + sb.append(line, 0, end + 1); + break; + } else { + sb.append(line).append(System.lineSeparator()); + } + } + + String resultLine = sb.toString(); + int cutOffIndex = resultLine.indexOf('{'); + resultLine = resultLine.substring(cutOffIndex + 1); + + Matcher matcher = Pattern.compile(matchRegex).matcher(resultLine); + while (matcher.find()) { + if (y >= H) { + error("Scan size of XBM file exceeds" + + " the defined width x height"); + } + + int startIndex = matcher.start(); + int endIndex = matcher.end(); + String hexByte = resultLine.substring(startIndex, endIndex); + hexByte = hexByte.replaceAll("^\\s+", ""); + + if (!(hexByte.startsWith("0x") + || hexByte.startsWith("0X"))) { + error("Invalid hexadecimal number at Ln#:" + lineNum + + " Col#:" + (startIndex + 1)); + } + hexByte = hexByte.replaceAll(replaceRegex, ""); + if (hexByte.length() != 2) { + error("Invalid hexadecimal number at Ln#:" + lineNum + + " Col#:" + (startIndex + 1)); + } + + try { + n = Integer.parseInt(hexByte, 16); + } catch (NumberFormatException nfe) { + error("Error parsing hexadecimal at Ln#:" + lineNum + + " Col#:" + (startIndex + 1)); + } + for (int mask = 1; mask <= 0x80; mask <<= 1) { + if (x < W) { + if ((n & mask) != 0) + raster[x] = 1; + else + raster[x] = 0; + } + x++; + } + + if (x >= W) { + int result = setPixels(0, y, W, 1, model, raster, 0, W); + if (result <= 0) { + error("Unexpected error occurred during setPixel()"); + } + x = 0; + y++; + } } imageComplete(ImageConsumer.STATICIMAGEDONE, true); } diff --git a/src/java.desktop/share/native/libjsound/Utilities.c b/src/java.desktop/share/native/libjsound/Utilities.c index 6e92813d53c..50ca18c0259 100644 --- a/src/java.desktop/share/native/libjsound/Utilities.c +++ b/src/java.desktop/share/native/libjsound/Utilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +26,6 @@ #include "Utilities.h" - -int UTIL_IsBigEndianPlatform() { -#ifdef _LITTLE_ENDIAN - return 0; -#else - return 1; -#endif -} - void ThrowJavaMessageException(JNIEnv *e, const char *exClass, const char *msg) { jclass newExcCls; diff --git a/src/java.desktop/share/native/libjsound/Utilities.h b/src/java.desktop/share/native/libjsound/Utilities.h index fbecab1e005..7cb0dcbdd4c 100644 --- a/src/java.desktop/share/native/libjsound/Utilities.h +++ b/src/java.desktop/share/native/libjsound/Utilities.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +28,6 @@ #include "SoundDefs.h" #include "Configure.h" // put flags for debug msgs etc. here -// return 1 if this platform is big endian, or 0 for little endian -int UTIL_IsBigEndianPlatform(); - - // ERROR PRINTS #ifdef USE_ERROR #define ERROR0(string) { fprintf(stdout, (string)); fflush(stdout); } diff --git a/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c b/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c index 0ea86e3e9b3..ebb3e32890e 100644 --- a/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c +++ b/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +339,7 @@ Java_sun_java2d_xr_XRBackendNative_createPixmap(JNIEnv *env, jobject this, JNIEXPORT jint JNICALL Java_sun_java2d_xr_XRBackendNative_createPictureNative (JNIEnv *env, jclass cls, jint drawable, jlong formatPtr) { - XRenderPictureAttributes pict_attr; + XRenderPictureAttributes pict_attr = {0}; return XRenderCreatePicture(awt_display, (Drawable) drawable, (XRenderPictFormat *) jlong_to_ptr(formatPtr), 0, &pict_attr); diff --git a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java index af8870ecf64..998e8d037b4 100644 --- a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import java.util.regex.Pattern; import static java.nio.charset.StandardCharsets.UTF_8; +import sun.jvmstat.monitor.MonitoredHost; + /* * Linux implementation of HotSpotVirtualMachine */ @@ -228,7 +230,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // Return the socket file for the given process. private File findSocketFile(long pid, long ns_pid) throws AttachNotSupportedException, IOException { - return new File(findTargetProcessTmpDirectory(pid, ns_pid), ".java_pid" + ns_pid); + return new File(findTargetProcessTmpDirectory(pid), ".java_pid" + ns_pid); } // On Linux a simple handshake is used to start the attach mechanism @@ -243,14 +245,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // Do not canonicalize the file path, or we will fail to attach to a VM in a container. f.createNewFile(); } catch (IOException _) { - f = new File(findTargetProcessTmpDirectory(pid, ns_pid), fn.toString()); + f = new File(findTargetProcessTmpDirectory(pid), fn.toString()); f.createNewFile(); } return f; } - private String findTargetProcessTmpDirectory(long pid, long ns_pid) throws AttachNotSupportedException, IOException { - final var procPidRoot = PROC.resolve(Long.toString(pid)).resolve(ROOT_TMP); + private String findTargetProcessTmpDirectory(long pid) throws AttachNotSupportedException { + final var tmpOnProcPidRoot = PROC.resolve(Long.toString(pid)).resolve(ROOT_TMP); /* We need to handle at least 4 different cases: * 1. Caller and target processes share PID namespace and root filesystem (host to host or container to @@ -261,21 +263,44 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { * 4. Caller and target processes share neither PID namespace nor root filesystem (host to container) * * if target is elevated, we cant use /proc//... so we have to fallback to /tmp, but that may not be shared - * with the target/attachee process, we can try, except in the case where the ns_pid also exists in this pid ns - * which is ambiguous, if we share /tmp with the intended target, the attach will succeed, if we do not, - * then we will potentially attempt to attach to some arbitrary process with the same pid (in this pid ns) - * as that of the intended target (in its * pid ns). + * with the target/attachee process, so we should check whether /tmp on both is same. This method would throw + * AttachNotSupportedException if they are different because we cannot make a connection with target VM. * - * so in that case we should prehaps throw - or risk sending SIGQUIT to some arbitrary process... which could kill it - * - * however we can also check the target pid's signal masks to see if it catches SIGQUIT and only do so if in + * In addition, we can also check the target pid's signal masks to see if it catches SIGQUIT and only do so if in * fact it does ... this reduces the risk of killing an innocent process in the current ns as opposed to * attaching to the actual target JVM ... c.f: checkCatchesAndSendQuitTo() below. - * - * note that if pid == ns_pid we are in a shared pid ns with the target and may (potentially) share /tmp */ - return (Files.isWritable(procPidRoot) ? procPidRoot : TMPDIR).toString(); + try { + if (Files.isWritable(tmpOnProcPidRoot)) { + return tmpOnProcPidRoot.toString(); + } else if (Files.isSameFile(tmpOnProcPidRoot, TMPDIR)) { + return TMPDIR.toString(); + } else { + throw new AttachNotSupportedException("Unable to access the filesystem of the target process"); + } + } catch (IOException ioe) { + try { + boolean found = MonitoredHost.getMonitoredHost("//localhost") + .activeVms() + .stream() + .anyMatch(i -> pid == i.intValue()); + if (found) { + // We can use /tmp because target process is on same host + // even if we cannot access /proc//root. + // The process with capsh/setcap would fall this pattern. + return TMPDIR.toString(); + } else { + throw new AttachNotSupportedException("Unable to access the filesystem of the target process", ioe); + } + } catch (AttachNotSupportedException e) { + // AttachNotSupportedException happened in above should go through + throw e; + } catch (Exception e) { + // Other exceptions would be wrapped with AttachNotSupportedException + throw new AttachNotSupportedException("Unable to access the filesystem of the target process", e); + } + } } // Return the inner most namespaced PID if there is one, diff --git a/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java b/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java index 382c8a57b26..725db3e7732 100644 --- a/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java +++ b/src/jdk.attach/share/classes/com/sun/tools/attach/AttachNotSupportedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * 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,4 +62,17 @@ public class AttachNotSupportedException extends Exception { super(s); } + /** + * Constructs an AttachNotSupportedException with + * the specified cause. + * + * @param message the detail message. + * @param cause the cause of this exception. + * + * @since 27 + */ + public AttachNotSupportedException(String message, Throwable cause) { + super(message, cause); + } + } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index 6aae8eb855d..86319f20c73 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1403,6 +1403,7 @@ public class TypeAnnotations { break; } } + scan(tree.dims); scan(tree.elems); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java index f5fdc1578b8..f865afe11fb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1107,6 +1107,7 @@ public class Annotate { for (List dimAnnos : tree.dimAnnotations) enterTypeAnnotations(dimAnnos, env, sym, false); scan(tree.elemtype); + scan(tree.dims); scan(tree.elems); } diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_general.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_general.c index e9bcf597a03..f61b8a5fb49 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_general.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_general.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -100,6 +100,12 @@ Java_sun_security_pkcs11_wrapper_PKCS11_initializeLibrary #ifndef NO_CALLBACKS if (notifyListLock == NULL) { notifyListLock = createLockObject(env); + + /* Return immediately if lock creation failed or an exception is pending. */ + if (notifyListLock == NULL || (*env)->ExceptionCheck(env)) { + TRACE0("DEBUG: createLockObject failed, aborting initialization\n"); + return; + } } #endif diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c index f2e1a46565d..e540f3b5ed9 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -929,6 +929,11 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DeriveKey rv = (*ckpFunctions->C_DeriveKey)(ckSessionHandle, ckpMechanism, ckBaseKeyHandle, ckpAttributes, ckAttributesLength, phKey); + /* If derivation failed, do not attempt copy-back */ + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + goto cleanup; + } + jKeyHandle = ckLongToJLong(ckKeyHandle); switch (ckpMechanism->mechanism) { @@ -956,8 +961,9 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1DeriveKey // empty break; } - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { - jKeyHandle =0L; + /* Do not continue if any copy-back operation raised an exception */ + if ((*env)->ExceptionCheck(env)) { + goto cleanup; } cleanup: diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index 08406fef518..02e15d5f8dd 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2873,9 +2873,9 @@ public abstract class ByteVector extends AbstractVector { case VECTOR_OP_MAX: return (v, m) -> toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (byte) Math.max(a, b))); case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> (byte) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> (byte) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (byte) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> (byte) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp((byte)0, m, (i, a, b) -> (byte) VectorMath.addSaturatingUnsigned(a, b))); case VECTOR_OP_AND: return (v, m) -> @@ -2890,6 +2890,8 @@ public abstract class ByteVector extends AbstractVector { private static final byte MIN_OR_INF = Byte.MIN_VALUE; private static final byte MAX_OR_INF = Byte.MAX_VALUE; + private static final byte UMIN_VALUE = (byte)0; // Minimum unsigned value + private static final byte UMAX_VALUE = (byte)-1; // Maximum unsigned value public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index 786cd089ebe..08fda9c96e6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index b481d5a51d7..0f70a2b81c8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index 43356b9ea6c..23e703dcada 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2858,9 +2858,9 @@ public abstract class IntVector extends AbstractVector { case VECTOR_OP_MAX: return (v, m) -> toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (int) Math.max(a, b))); case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> (int) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> (int) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (int) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> (int) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp((int)0, m, (i, a, b) -> (int) VectorMath.addSaturatingUnsigned(a, b))); case VECTOR_OP_AND: return (v, m) -> @@ -2875,6 +2875,8 @@ public abstract class IntVector extends AbstractVector { private static final int MIN_OR_INF = Integer.MIN_VALUE; private static final int MAX_OR_INF = Integer.MAX_VALUE; + private static final int UMIN_VALUE = (int)0; // Minimum unsigned value + private static final int UMAX_VALUE = (int)-1; // Maximum unsigned value public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 8947343ff30..58bfd4d7772 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2724,9 +2724,9 @@ public abstract class LongVector extends AbstractVector { case VECTOR_OP_MAX: return (v, m) -> toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (long) Math.max(a, b))); case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> (long) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> (long) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (long) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> (long) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp((long)0, m, (i, a, b) -> (long) VectorMath.addSaturatingUnsigned(a, b))); case VECTOR_OP_AND: return (v, m) -> @@ -2741,6 +2741,8 @@ public abstract class LongVector extends AbstractVector { private static final long MIN_OR_INF = Long.MIN_VALUE; private static final long MAX_OR_INF = Long.MAX_VALUE; + private static final long UMIN_VALUE = (long)0; // Minimum unsigned value + private static final long UMAX_VALUE = (long)-1; // Maximum unsigned value public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index e222c6d25f3..7ab7e7c4417 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2874,9 +2874,9 @@ public abstract class ShortVector extends AbstractVector { case VECTOR_OP_MAX: return (v, m) -> toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (short) Math.max(a, b))); case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> (short) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> (short) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> (short) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> (short) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp((short)0, m, (i, a, b) -> (short) VectorMath.addSaturatingUnsigned(a, b))); case VECTOR_OP_AND: return (v, m) -> @@ -2891,6 +2891,8 @@ public abstract class ShortVector extends AbstractVector { private static final short MIN_OR_INF = Short.MIN_VALUE; private static final short MAX_OR_INF = Short.MAX_VALUE; + private static final short UMIN_VALUE = (short)0; // Minimum unsigned value + private static final short UMAX_VALUE = (short)-1; // Maximum unsigned value public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index f7d987fd280..ce3b7512c93 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3448,9 +3448,9 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> ($type$) Math.max(a, b))); #if[!FP] case VECTOR_OP_UMIN: return (v, m) -> - toBits(v.rOp(MAX_OR_INF, m, (i, a, b) -> ($type$) VectorMath.minUnsigned(a, b))); + toBits(v.rOp(UMAX_VALUE, m, (i, a, b) -> ($type$) VectorMath.minUnsigned(a, b))); case VECTOR_OP_UMAX: return (v, m) -> - toBits(v.rOp(MIN_OR_INF, m, (i, a, b) -> ($type$) VectorMath.maxUnsigned(a, b))); + toBits(v.rOp(UMIN_VALUE, m, (i, a, b) -> ($type$) VectorMath.maxUnsigned(a, b))); case VECTOR_OP_SUADD: return (v, m) -> toBits(v.rOp(($type$)0, m, (i, a, b) -> ($type$) VectorMath.addSaturatingUnsigned(a, b))); #end[!FP] @@ -3472,6 +3472,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { #else[FP] private static final $type$ MIN_OR_INF = $Boxtype$.MIN_VALUE; private static final $type$ MAX_OR_INF = $Boxtype$.MAX_VALUE; + private static final $type$ UMIN_VALUE = ($type$)0; // Minimum unsigned value + private static final $type$ UMAX_VALUE = ($type$)-1; // Maximum unsigned value #end[FP] public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java index 0ec6a77e683..7c1f06f54a3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java @@ -147,8 +147,6 @@ final class LinuxDebPackager extends LinuxPackager { Path debFile = outputPackageFile(); - Log.verbose(I18N.format("message.outputting-to-location", debFile.toAbsolutePath())); - List cmdline = new ArrayList<>(); Stream.of(sysEnv.fakeroot(), sysEnv.dpkgdeb()).map(Path::toString).forEach(cmdline::add); if (Log.isVerbose()) { @@ -159,8 +157,6 @@ final class LinuxDebPackager extends LinuxPackager { // run dpkg Executor.of(cmdline).retryOnKnownErrorMessage( "semop(1): encountered an error: Invalid argument").execute(); - - Log.verbose(I18N.format("message.output-to-location", debFile.toAbsolutePath())); } @Override diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java index af7f5288cc5..551e1ab1af6 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +61,7 @@ abstract class LinuxPackager implements Consumer { Path rpmFile = outputPackageFile(); - Log.verbose(I18N.format("message.outputting-bundle-location", rpmFile.getParent())); - //run rpmbuild Executor.of(sysEnv.rpmbuild().toString(), "-bb", specFile().toAbsolutePath().toString(), @@ -147,8 +145,6 @@ final class LinuxRpmPackager extends LinuxPackager { env.buildRoot().toAbsolutePath()), "--define", String.format("%%_rpmfilename %s", rpmFile.getFileName()) ).executeExpectSuccess(); - - Log.verbose(I18N.format("message.output-bundle-location", rpmFile.getParent())); } private Path installPrefix() { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties index 3aabe1f4ba5..3aa0e0e92a0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. # 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,11 +49,7 @@ error.rpm-arch-not-detected="Failed to detect RPM arch" message.icon-not-png=The specified icon "{0}" is not a PNG file and will not be used. The default icon will be used in it's place. message.test-for-tool=Test for [{0}]. Result: {1} -message.outputting-to-location=Generating DEB for installer to: {0}. -message.output-to-location=Package (.deb) saved to: {0}. message.debs-like-licenses=Debian packages should specify a license. The absence of a license will cause some linux distributions to complain about the quality of the application. -message.outputting-bundle-location=Generating RPM for installer to: {0}. -message.output-bundle-location=Package (.rpm) saved to: {0}. message.ldd-not-available=ldd command not found. Package dependencies will not be generated. message.deb-ldd-not-available.advice=Install "libc-bin" DEB package to get ldd. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java index 81e04ad7ed1..19ff78f174e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -47,6 +47,7 @@ import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.Result; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -170,7 +171,7 @@ final class AppImageSigner { // In addition add possible reason for failure. For example // "--app-content" can fail "codesign". - if (!app.contentDirs().isEmpty()) { + if (!app.contentDirSources().isEmpty()) { Log.info(I18N.getString("message.codesign.failed.reason.app.content")); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index 5f126305aed..2023b425da9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ import java.nio.file.Path; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import jdk.jpackage.internal.util.RootedPath; +import java.util.stream.Stream; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.AppImageSigningConfig; import jdk.jpackage.internal.model.Application; @@ -143,15 +146,17 @@ final class MacApplicationBuilder { } private static void validateAppContentDirs(Application app) { - for (var contentDir : app.contentDirs()) { + app.contentDirSources().stream().filter(rootedPath -> { + return rootedPath.branch().getNameCount() == 1; + }).map(RootedPath::fullPath).forEach(contentDir -> { if (!Files.isDirectory(contentDir)) { Log.info(I18N.format("warning.app.content.is.not.dir", contentDir)); - } else if (!CONTENTS_SUB_DIRS.contains(contentDir.getFileName().toString())) { + } else if (!CONTENTS_SUB_DIRS.contains(contentDir.getFileName())) { Log.info(I18N.format("warning.non.standard.contents.sub.dir", contentDir)); } - } + }); } private MacApplicationBuilder createCopyForExternalInfoPlistFile() { @@ -258,6 +263,11 @@ final class MacApplicationBuilder { private static final int MAX_BUNDLE_NAME_LENGTH = 16; // List of standard subdirectories of the "Contents" directory - private static final Set CONTENTS_SUB_DIRS = Set.of("MacOS", - "Resources", "Frameworks", "PlugIns", "SharedSupport"); + private static final Set CONTENTS_SUB_DIRS = Stream.of( + "MacOS", + "Resources", + "Frameworks", + "PlugIns", + "SharedSupport" + ).map(Path::of).collect(Collectors.toUnmodifiableSet()); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java index 0531559e052..224ea20f249 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java @@ -54,7 +54,6 @@ public class MacBundlingEnvironment extends DefaultBundlingEnvironment { buildEnv()::create, MacBundlingEnvironment::buildPipeline, (env, pkg, outputDir) -> { - Log.verbose(I18N.format("message.building-dmg", pkg.app().name())); return new MacDmgPackager(env, pkg, outputDir, sysEnv); }); } @@ -64,10 +63,7 @@ public class MacBundlingEnvironment extends DefaultBundlingEnvironment { MacFromOptions.createMacPkgPackage(options), buildEnv()::create, MacBundlingEnvironment::buildPipeline, - (env, pkg, outputDir) -> { - Log.verbose(I18N.format("message.building-pkg", pkg.app().name())); - return new MacPkgPackager(env, pkg, outputDir); - }); + MacPkgPackager::new); } private static void signAppImage(Options options) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgLicense.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgLicense.java new file mode 100644 index 00000000000..eea09b80929 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgLicense.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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.jpackage.internal; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Base64; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +import jdk.jpackage.internal.resources.ResourceLocator; + +final class MacDmgLicense { + + public static void prepareLicensePListFile(Path licenseFile, Path licensePListFile) + throws IOException { + byte[] licenseContentOriginal = + Files.readAllBytes(licenseFile); + String licenseInBase64 = + Base64.getEncoder().encodeToString(licenseContentOriginal); + + Map data = new HashMap<>(); + data.put("APPLICATION_LICENSE_TEXT", licenseInBase64); + data.put("STR_DATA_ENGLISH", + getSTRData("English", Locale.ENGLISH, "MacRoman")); + data.put("STR_DATA_GERMAN", + getSTRData("German", Locale.GERMAN, "MacRoman")); + data.put("STR_DATA_JAPANESE", + getSTRData("Japanese", Locale.JAPANESE, "Shift_JIS")); + data.put("STR_DATA_SIMPLIFIED_CHINESE", + getSTRData("Simplified Chinese", Locale.SIMPLIFIED_CHINESE, "GB2312")); + + new OverridableResource(DEFAULT_LICENSE_PLIST, ResourceLocator.class) + .setCategory(I18N.getString("resource.license-setup")) + .setSubstitutionData(data) + .saveToFile(licensePListFile); + } + + private static void writeSTRDataString(ByteArrayOutputStream bos, + String str, String charset) { + byte [] bytes = str.getBytes(Charset.forName(charset)); + byte [] bytesLength = {(byte)bytes.length}; + bos.writeBytes(bytesLength); + bos.writeBytes(bytes); + } + + // Returns base64 decoded STR section data. + // Strings should be in following order: + // Language, message.dmg.license.button.agree, + // message.dmg.license.button.disagree, message.dmg.license.button.print + // message.dmg.license.button.save, message.dmg.license.message + // STR section data encoded: + // Number of strings in the list (unsigned 16-bit integer, big endian): 6 + // A sequence of strings prefixed with string length (unsigned 8-bit integer) + // Note: Language should not be translated. + private static String getSTRData(String language, Locale locale, String charset) { + ResourceBundle bundle = ResourceBundle.getBundle( + "jdk.jpackage.internal.resources.MacResources", locale); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + byte [] numberOfStrings = {0x00, 0x06}; // Always 6 + bos.writeBytes(numberOfStrings); + + writeSTRDataString(bos, language, charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.button.agree"), charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.button.disagree"), charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.button.print"), charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.button.save"), charset); + writeSTRDataString(bos, bundle.getString("message.dmg.license.message"), charset); + + return Base64.getEncoder().encodeToString(bos.toByteArray()); + } + + private static final String DEFAULT_LICENSE_PLIST = "lic_template.plist"; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java index 10754b1f1b6..b9e407b4a47 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 @@ package jdk.jpackage.internal; import java.nio.file.Path; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacDmgPackageMixin; +import jdk.jpackage.internal.util.RootedPath; final class MacDmgPackageBuilder { @@ -37,8 +39,8 @@ final class MacDmgPackageBuilder { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } - MacDmgPackageBuilder dmgContent(List v) { - dmgContent = v; + MacDmgPackageBuilder dmgRootDirSources(Collection v) { + dmgRootDirSources = v; return this; } @@ -47,8 +49,8 @@ final class MacDmgPackageBuilder { return this; } - List validatedDmgContent() { - return Optional.ofNullable(dmgContent).orElseGet(List::of); + private Collection validatedDmgRootDirSources() { + return Optional.ofNullable(dmgRootDirSources).orElseGet(List::of); } MacDmgPackage create() { @@ -56,10 +58,10 @@ final class MacDmgPackageBuilder { return MacDmgPackage.create(pkg, new MacDmgPackageMixin.Stub( Optional.ofNullable(icon).or((pkg.app())::icon), - validatedDmgContent())); + validatedDmgRootDirSources())); } private Path icon; - private List dmgContent; + private Collection dmgRootDirSources; private final MacPackageBuilder pkgBuilder; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index 20a687487ef..24474c88162 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -34,7 +34,6 @@ import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -47,6 +46,7 @@ import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.PathGroup; +import jdk.jpackage.internal.util.RootedPath; record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, MacDmgSystemEnvironment sysEnv) implements Consumer { @@ -61,7 +61,6 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, @Override public void accept(PackagingPipeline.Builder pipelineBuilder) { pipelineBuilder - .excludeDirFromCopying(outputDir) .task(DmgPackageTaskID.COPY_DMG_CONTENT) .action(this::copyDmgContent) .addDependent(PackageTaskID.CREATE_PACKAGE_FILE) @@ -105,7 +104,7 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, return env.configDir().resolve(pkg.app().name() + "-volume.icns"); } - Path licenseFile() { + Path licensePListFile() { return env.configDir().resolve(pkg.app().name() + "-license.plist"); } @@ -131,9 +130,7 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, private void copyDmgContent() throws IOException { final var srcFolder = env.appImageDir(); - for (Path path : pkg.content()) { - FileUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); - } + RootedPath.copy(pkg.dmgRootDirSources().stream(), srcFolder); } private Executor hdiutil(String... args) { @@ -175,26 +172,6 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, .saveToFile(dmgSetup); } - private void prepareLicense() throws IOException { - final var licFile = pkg.licenseFile(); - if (licFile.isEmpty()) { - return; - } - - byte[] licenseContentOriginal = - Files.readAllBytes(licFile.orElseThrow()); - String licenseInBase64 = - Base64.getEncoder().encodeToString(licenseContentOriginal); - - Map data = new HashMap<>(); - data.put("APPLICATION_LICENSE_TEXT", licenseInBase64); - - env.createResource(DEFAULT_LICENSE_PLIST) - .setCategory(I18N.getString("resource.license-setup")) - .setSubstitutionData(data) - .saveToFile(licenseFile()); - } - private void prepareConfigFiles() throws IOException { env.createResource(DEFAULT_BACKGROUND_IMAGE) @@ -206,7 +183,9 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, .setExternal(pkg.icon().orElse(null)) .saveToFile(volumeIcon()); - prepareLicense(); + if (pkg.licenseFile().isPresent()) { + MacDmgLicense.prepareLicensePListFile(pkg.licenseFile().get(), licensePListFile()); + } prepareDMGSetupScript(); } @@ -235,17 +214,6 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, final Path srcFolder = env.appImageDir(); - Log.verbose(MessageFormat.format(I18N.getString( - "message.creating-dmg-file"), finalDMG.toAbsolutePath())); - - try { - Files.deleteIfExists(finalDMG); - } catch (IOException ex) { - throw new IOException(MessageFormat.format(I18N.getString( - "message.dmg-cannot-be-overwritten"), - finalDMG.toAbsolutePath())); - } - Files.createDirectories(protoDMG.getParent()); Files.createDirectories(finalDMG.getParent()); @@ -370,7 +338,7 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, "udifrez", normalizedAbsolutePathString(finalDMG), "-xml", - normalizedAbsolutePathString(licenseFile()) + normalizedAbsolutePathString(licensePListFile()) ).retry() .setMaxAttemptsCount(10) .setAttemptTimeout(3, TimeUnit.SECONDS) @@ -383,11 +351,6 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, } catch (IOException ex) { // Don't care if fails } - - Log.verbose(MessageFormat.format(I18N.getString( - "message.output-to-location"), - pkg.app().name(), normalizedAbsolutePathString(finalDMG))); - } private void detachVolume() throws IOException { @@ -457,6 +420,4 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, private static final String DEFAULT_BACKGROUND_IMAGE = "background_dmg.tiff"; private static final String DEFAULT_DMG_SETUP_SCRIPT = "DMGsetup.scpt"; private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns"; - - private static final String DEFAULT_LICENSE_PLIST="lic_template.plist"; } 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 b1094331740..f3c1765210f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 +30,8 @@ import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasJliLib; import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasNoBinDir; import static jdk.jpackage.internal.cli.StandardBundlingOperation.SIGN_MAC_APP_IMAGE; -import static jdk.jpackage.internal.cli.StandardOption.ICON; import static jdk.jpackage.internal.cli.StandardOption.APPCLASS; +import static jdk.jpackage.internal.cli.StandardOption.ICON; import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_CATEGORY; import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_STORE; @@ -52,11 +52,14 @@ import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import java.nio.file.Path; +import java.util.Collection; +import java.util.List; import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo; import jdk.jpackage.internal.SigningIdentityBuilder.ExpiredCertificateException; import jdk.jpackage.internal.SigningIdentityBuilder.StandardCertificateSelector; +import jdk.jpackage.internal.cli.OptionValue; import jdk.jpackage.internal.cli.Options; import jdk.jpackage.internal.cli.StandardFaOption; import jdk.jpackage.internal.model.ApplicationLaunchers; @@ -71,7 +74,9 @@ import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.Result; +import jdk.jpackage.internal.util.RootedPath; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -89,7 +94,14 @@ final class MacFromOptions { final var pkgBuilder = new MacDmgPackageBuilder(superPkgBuilder); - MAC_DMG_CONTENT.ifPresentIn(options, pkgBuilder::dmgContent); + MAC_DMG_CONTENT.findIn(options).map((List> v) -> { + // Reverse the order of content sources. + // If there are multiple source files for the same + // destination file, only the first will be used. + // Reversing the order of content sources makes it use the last file + // from the original list of source files for the given destination file. + return v.reversed().stream().flatMap(Collection::stream).toList(); + }).ifPresent(pkgBuilder::dmgRootDirSources); return pkgBuilder.create(); } @@ -276,16 +288,12 @@ final class MacFromOptions { final var builder = new MacPackageBuilder(createPackageBuilder(options, app.app(), type)); - app.externalApp() - .map(ExternalApplication::extra) - .flatMap(MAC_SIGN::findIn) - .ifPresent(builder::predefinedAppImageSigned); - - PREDEFINED_RUNTIME_IMAGE.findIn(options) - .map(MacBundle::new) - .filter(MacBundle::isValid) - .map(MacBundle::isSigned) - .ifPresent(builder::predefinedAppImageSigned); + for (OptionValue ov : List.of(PREDEFINED_APP_IMAGE, PREDEFINED_RUNTIME_IMAGE)) { + ov.findIn(options) + .flatMap(MacBundle::fromPath) + .map(MacPackagingPipeline::isSigned) + .ifPresent(builder::predefinedAppImageSigned); + } return builder; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 53f297282ba..4e63f6db178 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.MacBundle; +import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; @@ -178,13 +180,10 @@ final class MacPackagingPipeline { builder.task(MacCopyAppImageTaskID.COPY_RUNTIME_JLILIB) .appImageAction(MacPackagingPipeline::copyJliLib).add(); - final var predefinedRuntimeBundle = Optional.of( - new MacBundle(p.predefinedAppImage().orElseThrow())).filter(MacBundle::isValid); - // Don't create ".package" file. disabledTasks.add(MacCopyAppImageTaskID.COPY_PACKAGE_FILE); - if (predefinedRuntimeBundle.isPresent()) { + if (MacBundle.fromPath(p.predefinedAppImage().orElseThrow()).isPresent()) { // The input runtime image is a macOS bundle. // Disable all alterations of the input bundle, but keep the signing enabled. disabledTasks.addAll(List.of(MacCopyAppImageTaskID.values())); @@ -195,7 +194,7 @@ final class MacPackagingPipeline { .appImageAction(MacPackagingPipeline::writeRuntimeInfoPlist).add(); } - if (predefinedRuntimeBundle.map(MacBundle::isSigned).orElse(false) && !((MacPackage)p).app().sign()) { + if (((MacPackage)p).predefinedAppImageSigned().orElse(false) && !((MacPackage)p).app().sign()) { // The input runtime is a signed bundle; explicit signing is not requested for the package. // Disable the signing, i.e. don't re-sign the input bundle. disabledTasks.add(MacCopyAppImageTaskID.COPY_SIGN); @@ -218,6 +217,11 @@ final class MacPackagingPipeline { enum SignAppImagePackageType implements PackageType { VALUE; + + @Override + public String label() { + throw new UnsupportedOperationException(); + } } static Package createSignAppImagePackage(MacApplication app, BuildEnv env) { @@ -279,6 +283,30 @@ final class MacPackagingPipeline { } } + static boolean isSigned(MacBundle bundle) { + + var result = toSupplier(Executor.of( + "/usr/sbin/spctl", + "-vv", + "--raw", + "--assess", + "--type", "exec", + bundle.root().toString()).setQuiet(true).saveOutput(true).binaryOutput()::execute).get(); + + switch (result.getExitCode()) { + case 0, 3 -> { + // These exit codes are accompanied with valid plist xml. + return toSupplier(() -> { + return new PListReader(result.byteStdout()).findValue("assessment:originator").isPresent(); + }).get(); + } + default -> { + // Likely to be an "a sealed resource is missing or invalid" error. + return false; + } + } + } + private static void copyAppImage(MacPackage pkg, AppImageLayout srcAppImage, AppImageLayout dstAppImage) throws IOException { @@ -286,7 +314,7 @@ final class MacPackagingPipeline { final Optional srcMacBundle; if (pkg.isRuntimeInstaller()) { - srcMacBundle = MacBundle.fromAppImageLayout(srcAppImage); + srcMacBundle = macBundleFromAppImageLayout(srcAppImage); } else { srcMacBundle = Optional.empty(); } @@ -297,7 +325,7 @@ final class MacPackagingPipeline { try { FileUtils.copyRecursive( inputBundle.root(), - MacBundle.fromAppImageLayout(dstAppImage).orElseThrow().root(), + macBundleFromAppImageLayout(dstAppImage).orElseThrow().root(), LinkOption.NOFOLLOW_LINKS); } catch (IOException ex) { throw new UncheckedIOException(ex); @@ -415,7 +443,7 @@ final class MacPackagingPipeline { final var app = env.app(); - final var infoPlistFile = MacBundle.fromAppImageLayout(env.resolvedLayout()).orElseThrow().infoPlistFile(); + final var infoPlistFile = macBundleFromAppImageLayout(env.resolvedLayout()).orElseThrow().infoPlistFile(); Log.verbose(I18N.format("message.preparing-info-plist", PathUtils.normalizedAbsolutePathString(infoPlistFile))); @@ -468,7 +496,7 @@ final class MacPackagingPipeline { } final Runnable signAction = () -> { - AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(MacBundle.fromAppImageLayout(env.resolvedLayout()).orElseThrow()); + AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(macBundleFromAppImageLayout(env.resolvedLayout()).orElseThrow()); }; app.signingConfig().flatMap(AppImageSigningConfig::keychain).map(Keychain::new).ifPresentOrElse(keychain -> { @@ -550,7 +578,7 @@ final class MacPackagingPipeline { private static MacBundle runtimeBundle(AppImageBuildEnv env) { if (env.app().isRuntime()) { - return MacBundle.fromAppImageLayout(env.resolvedLayout()).orElseThrow(); + return macBundleFromAppImageLayout(env.resolvedLayout()).orElseThrow(); } else { return new MacBundle(((MacApplicationLayout)env.resolvedLayout()).runtimeRootDirectory()); } @@ -595,6 +623,22 @@ final class MacPackagingPipeline { }; } + private static Optional macBundleFromAppImageLayout(AppImageLayout layout) { + final var root = layout.rootDirectory(); + final var bundleSubdir = root.relativize(layout.runtimeDirectory()); + final var contentsDirname = Path.of("Contents"); + var bundleRoot = root; + for (int i = 0; i != bundleSubdir.getNameCount(); i++) { + var nameComponent = bundleSubdir.getName(i); + if (contentsDirname.equals(nameComponent)) { + return Optional.of(new MacBundle(bundleRoot)); + } else { + bundleRoot = bundleRoot.resolve(nameComponent); + } + } + return Optional.empty(); + } + private record TaskContextProxy(TaskContext delegate, boolean forApp, boolean copyAppImage) implements TaskContext { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index 126248e2330..fc5c85c699c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -215,7 +215,6 @@ record MacPkgPackager(BuildEnv env, MacPkgPackage pkg, Optional servic @Override public void accept(PackagingPipeline.Builder pipelineBuilder) { pipelineBuilder - .excludeDirFromCopying(outputDir) .task(PkgPackageTaskID.PREPARE_MAIN_SCRIPTS) .action(this::prepareMainScripts) .addDependent(PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java index cfe10e8a012..e2b3d30b7ae 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toUnmodifiableMap; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_APP_STORE; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_MAIN_CLASS; -import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_SIGNED; import java.nio.file.Path; import java.util.Map; @@ -96,9 +95,6 @@ public interface MacApplication extends Application, MacApplicationMixin { } public enum ExtraAppImageFileField { - SIGNED(MAC_SIGNED, app -> { - return Optional.of(Boolean.toString(app.sign())); - }), APP_STORE(MAC_APP_STORE, app -> { return Optional.of(Boolean.toString(app.appStore())); }), diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java index 0b502e7ce7e..08797b11509 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,23 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import java.util.List; +import java.util.Collection; import java.util.Optional; +import jdk.jpackage.internal.util.RootedPath; public interface MacDmgPackageMixin { Optional icon(); /** - * Returns additional top=level content for DMG package. + * Returns the source paths that should be copied into the top-level directory of a DMG package. *

* Each item in the list can be a directory or a file. * - * @return the additional top=level content for DMG package + * @return the source paths of additional top-level content for DMG package */ - List content(); + Collection dmgRootDirSources(); - record Stub(Optional icon, List content) implements MacDmgPackageMixin { + record Stub(Optional icon, Collection dmgRootDirSources) implements MacDmgPackageMixin { } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index 240e82dcc9b..0237d49f399 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -57,18 +57,18 @@ message.version-string-first-number-not-zero=The first number in an app-version message.keychain.error=Unable to get keychain list. message.invalid-identifier=Invalid mac bundle identifier [{0}]. message.invalid-identifier.advice=specify identifier with "--mac-package-identifier". -message.building-dmg=Building DMG package for {0}. message.preparing-dmg-setup=Preparing dmg setup: {0}. -message.creating-dmg-file=Creating DMG file: {0}. -message.dmg-cannot-be-overwritten=Dmg file exists [{0}] and can not be removed. -message.output-to-location=Result DMG installer for {0}: {1}. -message.building-pkg=Building PKG package for {0}. message.preparing-scripts=Preparing package scripts. message.preparing-distribution-dist=Preparing distribution.dist: {0}. message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trust" for your certificate using "Keychain Access" tool. message.setfile.dmg=Setting custom icon on DMG file skipped because 'SetFile' utility was not found. Installing Xcode with Command Line Tools should resolve this issue. message.codesign.failed.reason.app.content="codesign" failed and additional application content was supplied via the "--app-content" parameter. Probably the additional content broke the integrity of the application bundle and caused the failure. Ensure content supplied via the "--app-content" parameter does not break the integrity of the application bundle, or add it in the post-processing step. message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem. +message.dmg.license.button.agree=Agree +message.dmg.license.button.disagree=Disagree +message.dmg.license.button.print=Print +message.dmg.license.button.save=Save... +message.dmg.license.message=If you agree with the terms of this license, press "Agree" to install the software. If you do not agree, press "Disagree". warning.unsigned.app.image=Warning: Using unsigned app-image to build signed {0}. warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image. warning.non.standard.contents.sub.dir=Warning: The file name of the directory "{0}" specified for the --app-content option is not a standard subdirectory name in the "Contents" directory of the application bundle. The result application bundle may fail code signing and/or notarization. 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 3cc56bb6cdf..367f3216f85 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 @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. # 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,6 +71,11 @@ message.signing.pkg=Warnung: Zum Signieren von PKG mรผssen Sie mรถglicherweise m message.setfile.dmg=Das Festlegen des benutzerdefinierten Symbols fรผr die DMG-Datei wurde รผbersprungen, weil das Utility "SetFile" nicht gefunden wurde. Durch Installieren von Xcode mit Befehlszeilentools sollte dieses Problem behoben werden. message.codesign.failed.reason.app.content="codesign" war nicht erfolgreich, und zusรคtzlicher Anwendungsinhalt wurde รผber den Parameter "--app-content" angegeben. Wahrscheinlich hat der zusรคtzliche Inhalt die Integritรคt des Anwendungs-Bundles beeintrรคchtigt und den Fehler verursacht. Stellen Sie sicher, das der รผber den Parameter "--app-content" angegebene Inhalt nicht die Integritรคt des Anwendungs-Bundles beeintrรคchtigt, oder fรผgen Sie ihn im Nachverarbeitungsschritt hinzu. 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. +message.dmg.license.button.agree=Akzeptieren +message.dmg.license.button.disagree=Ablehnen +message.dmg.license.button.print=Drucken +message.dmg.license.button.save=Sichern... +message.dmg.license.message=Klicken Sie in โ€œAkzeptierenโ€, wenn Sie mit den Bestimmungen des Software-Lizenzvertrags einverstanden sind. Falls nicht, bitte โ€œAblehnenโ€ anklicken. Sie kรถnnen die Software nur installieren, wenn Sie โ€œAkzeptierenโ€ angeklickt haben. 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. 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 d3150a34a86..ba2497d30dd 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 @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. # 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,6 +71,11 @@ message.signing.pkg=่ญฆๅ‘Š: PKGใธใฎ็ฝฒๅใฎๅ ดๅˆใ€ใ€Œใ‚ญใƒผใƒใ‚งใƒผใƒณใƒป message.setfile.dmg='SetFile'ใƒฆใƒผใƒ†ใ‚ฃใƒชใƒ†ใ‚ฃใŒ่ฆ‹ใคใ‹ใ‚‰ใชใ„ใŸใ‚ใ€DMGใƒ•ใ‚กใ‚คใƒซใงใฎใ‚ซใ‚นใ‚ฟใƒ ใƒปใ‚ขใ‚คใ‚ณใƒณใฎ่จญๅฎšใŒใ‚นใ‚ญใƒƒใƒ—ใ•ใ‚Œใพใ—ใŸใ€‚Xcodeใจใ‚ณใƒžใƒณใƒ‰ใƒปใƒฉใ‚คใƒณใƒปใƒ„ใƒผใƒซใ‚’ใ‚คใƒณใ‚นใƒˆใƒผใƒซใ™ใ‚‹ใจใ€ใ“ใฎๅ•้กŒใฏ่งฃๆฑบใ•ใ‚Œใพใ™ใ€‚ message.codesign.failed.reason.app.content="codesign"ใŒๅคฑๆ•—ใ—ใŸใŸใ‚ใ€่ฟฝๅŠ ใฎใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใƒปใ‚ณใƒณใƒ†ใƒณใƒ„ใŒใ€"--app-content"ใƒ‘ใƒฉใƒกใƒผใ‚ฟใ‚’ไป‹ใ—ใฆๆไพ›ใ•ใ‚Œใพใ—ใŸใ€‚่ฟฝๅŠ ใฎใ‚ณใƒณใƒ†ใƒณใƒ„ใซใ‚ˆใ‚Šใ€ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใƒปใƒใƒณใƒ‰ใƒซใฎๆ•ดๅˆๆ€งใŒๆใ‚ใ‚Œใ€ๅคฑๆ•—ใฎๅŽŸๅ› ใซใชใฃใŸๅฏ่ƒฝๆ€งใŒใ‚ใ‚Šใพใ™ใ€‚"--app-content"ใƒ‘ใƒฉใƒกใƒผใ‚ฟใ‚’ไป‹ใ—ใฆๆไพ›ใ•ใ‚ŒใŸใ‚ณใƒณใƒ†ใƒณใƒ„ใซใ‚ˆใฃใฆใ€ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใƒปใƒใƒณใƒ‰ใƒซใฎๆ•ดๅˆๆ€งใŒๆใ‚ใ‚Œใฆใ„ใชใ„ใ“ใจใ‚’็ขบ่ชใ™ใ‚‹ใ‹ใ€ๅ‡ฆ็†ๅพŒใฎใ‚นใƒ†ใƒƒใƒ—ใง่ฟฝๅŠ ใ—ใฆใใ ใ•ใ„ใ€‚ message.codesign.failed.reason.xcode.tools="codesign"ๅคฑๆ•—ใฎ่€ƒใˆใ‚‰ใ‚Œใ‚‹็†็”ฑใฏใ€Xcodeใจใ‚ณใƒžใƒณใƒ‰ใƒฉใ‚คใƒณใƒปใƒ‡ใƒ™ใƒญใƒƒใƒ‘ใƒปใƒ„ใƒผใƒซใฎๆฌ ่ฝใงใ™ใ€‚Xcodeใจใ‚ณใƒžใƒณใƒ‰ใƒฉใ‚คใƒณใƒปใƒ‡ใƒ™ใƒญใƒƒใƒ‘ใƒปใƒ„ใƒผใƒซใ‚’ใ‚คใƒณใ‚นใƒˆใƒผใƒซใ—ใฆใ€ๅ•้กŒใŒ่งฃๆฑบใ•ใ‚Œใ‚‹ใ‹ใ‚’็ขบ่ชใ—ใฆใใ ใ•ใ„ใ€‚ +message.dmg.license.button.agree=ๅŒๆ„ใ—ใพใ™ +message.dmg.license.button.disagree=ๅŒๆ„ใ—ใพใ›ใ‚“ +message.dmg.license.button.print=ๅฐๅˆทใ™ใ‚‹ +message.dmg.license.button.save=ไฟๅญ˜... +message.dmg.license.message=ๆœฌใ‚ฝใƒ•ใƒˆใ‚ฆใ‚จใ‚ขไฝฟ็”จ่จฑ่ซพๅฅ‘็ด„ใฎๆกไปถใซๅŒๆ„ใ•ใ‚Œใ‚‹ๅ ดๅˆใซใฏใ€ใ‚ฝใƒ•ใƒˆใ‚ฆใ‚จใ‚ขใ‚’ใ‚คใƒณใ‚นใƒˆใƒผใƒซใ™ใ‚‹ใŸใ‚ใซใ€ŒๅŒๆ„ใ—ใพใ™ใ€ใ‚’ๆŠผใ—ใฆใใ ใ•ใ„ใ€‚ใ€€ๅŒๆ„ใ•ใ‚Œใชใ„ๅ ดๅˆใซใฏใ€ใ€ŒๅŒๆ„ใ—ใพใ›ใ‚“ใ€ใ‚’ๆŠผใ—ใฆใใ ใ•ใ„ใ€‚ warning.unsigned.app.image=่ญฆๅ‘Š: ็ฝฒๅใ•ใ‚Œใฆใ„ใชใ„app-imageใ‚’ไฝฟ็”จใ—ใฆ็ฝฒๅใ•ใ‚ŒใŸ{0}ใ‚’ไฝœๆˆใ—ใพใ™ใ€‚ warning.per.user.app.image.signed=่ญฆๅ‘Š: ไบ‹ๅ‰ๅฎš็พฉๆธˆใฎ็ฝฒๅไป˜ใใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใƒปใ‚คใƒกใƒผใ‚ธใซ"{0}"ใŒใชใ„ใŸใ‚ใ€ใ‚คใƒณใ‚นใƒˆใƒผใƒซๆธˆใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใฎใƒฆใƒผใ‚ถใƒผใ”ใจใฎๆง‹ๆˆใฏใ‚ตใƒใƒผใƒˆใ•ใ‚Œใพใ›ใ‚“ใ€‚ warning.non.standard.contents.sub.dir=่ญฆๅ‘Š: --app-contentใ‚ชใƒ—ใ‚ทใƒงใƒณใซๆŒ‡ๅฎšใ•ใ‚ŒใŸใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒช"{0}"ใฎใƒ•ใ‚กใ‚คใƒซๅใŒใ€ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใƒปใƒใƒณใƒ‰ใƒซใฎ"Contents"ใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒชๅ†…ใฎๆจ™ๆบ–ใ‚ตใƒ–ใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒชๅใงใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚็ตๆžœใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใƒปใƒใƒณใƒ‰ใƒซใฏใ€ใ‚ณใƒผใƒ‰็ฝฒๅใŠใ‚ˆใณ/ใพใŸใฏๅ…ฌ่จผใซๅคฑๆ•—ใ™ใ‚‹ใ“ใจใŒใ‚ใ‚Šใพใ™ใ€‚ 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 8ca2219b72f..f855a31caae 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 @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. # 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,6 +71,11 @@ message.signing.pkg=่ญฆๅ‘Š๏ผš่ฆๅฏน PKG ่ฟ›่กŒ็ญพๅ๏ผŒๅฏ่ƒฝ้œ€่ฆไฝฟ็”จโ€œๅฏ† message.setfile.dmg=็”ฑไบŽๆœชๆ‰พๅˆฐ 'SetFile' ๅฎž็”จ็จ‹ๅบ๏ผŒ่ทณ่ฟ‡ไบ†้’ˆๅฏน DMG ๆ–‡ไปถ่ฎพ็ฝฎๅฎšๅˆถๅ›พๆ ‡็š„ๆ“ไฝœใ€‚ๅฎ‰่ฃ…ๅธฆๅ‘ฝไปค่กŒๅทฅๅ…ท็š„ Xcode ๅบ”่ƒฝ่งฃๅ†ณๆญค้—ฎ้ข˜ใ€‚ message.codesign.failed.reason.app.content="codesign" ๅคฑ่ดฅ๏ผŒๅนถ้€š่ฟ‡ "--app-content" ๅ‚ๆ•ฐๆไพ›ไบ†้™„ๅŠ ๅบ”็”จ็จ‹ๅบๅ†…ๅฎนใ€‚ๅฏ่ƒฝๆ˜ฏ้™„ๅŠ ๅ†…ๅฎน็ ดๅไบ†ๅบ”็”จ็จ‹ๅบๅŒ…็š„ๅฎŒๆ•ดๆ€ง๏ผŒๅฏผ่‡ดไบ†ๆ•…้šœใ€‚่ฏท็กฎไฟ้€š่ฟ‡ "--app-content" ๅ‚ๆ•ฐๆไพ›็š„ๅ†…ๅฎนไธไผš็ ดๅๅบ”็”จ็จ‹ๅบๅŒ…็š„ๅฎŒๆ•ดๆ€ง๏ผŒๆˆ–่€…ๅœจๅŽๅค„็†ๆญฅ้ชคไธญๆทปๅŠ ่ฏฅๅ†…ๅฎนใ€‚ message.codesign.failed.reason.xcode.tools="codesign" ๅคฑ่ดฅๅฏ่ƒฝๆ˜ฏๅ› ไธบ็ผบๅฐ‘ๅธฆๅ‘ฝไปค่กŒๅผ€ๅ‘ไบบๅ‘˜ๅทฅๅ…ท็š„ Xcodeใ€‚่ฏทๅฎ‰่ฃ…ๅธฆๅ‘ฝไปค่กŒๅผ€ๅ‘ไบบๅ‘˜ๅทฅๅ…ท็š„ Xcode๏ผŒ็œ‹็œ‹ๆ˜ฏๅฆๅฏไปฅ่งฃๅ†ณ้—ฎ้ข˜ใ€‚ +message.dmg.license.button.agree=ๅŒๆ„ +message.dmg.license.button.disagree=ไธๅŒๆ„ +message.dmg.license.button.print=ๆ‰“ๅฐ +message.dmg.license.button.save=ๅญ˜ๅ‚จ... +message.dmg.license.message=ๅฆ‚ๆžœๆ‚จๅŒๆ„ๆœฌ่ฎธๅฏๅ่ฎฎ็š„ๆกๆฌพ๏ผŒ่ฏทๆŒ‰โ€œๅŒๆ„โ€ๆฅๅฎ‰่ฃ…ๆญค่ฝฏไปถใ€‚ๅฆ‚ๆžœๆ‚จไธๅŒๆ„๏ผŒ่ฏทๆŒ‰โ€œไธๅŒๆ„โ€ใ€‚ warning.unsigned.app.image=่ญฆๅ‘Š๏ผšไฝฟ็”จๆœช็ญพๅ็š„ app-image ็”Ÿๆˆๅทฒ็ญพๅ็š„ {0}ใ€‚ warning.per.user.app.image.signed=่ญฆๅ‘Š๏ผš็”ฑไบŽ้ข„ๅฎšไน‰็š„ๅทฒ็ญพๅๅบ”็”จ็จ‹ๅบๆ˜ ๅƒไธญ็ผบๅฐ‘ "{0}"๏ผŒไธๆ”ฏๆŒๅฏนๅทฒๅฎ‰่ฃ…ๅบ”็”จ็จ‹ๅบ็š„ๆฏ็”จๆˆท้…็ฝฎๆไพ›ๆ”ฏๆŒใ€‚ warning.non.standard.contents.sub.dir=่ญฆๅ‘Š๏ผšไธบ --app-content ้€‰้กนๆŒ‡ๅฎš็š„็›ฎๅฝ• "{0}" ็š„ๆ–‡ไปถๅไธๆ˜ฏๅบ”็”จ็จ‹ๅบๅŒ…็š„ "Contents" ็›ฎๅฝ•ไธญ็š„ๆ ‡ๅ‡†ๅญ็›ฎๅฝ•ๅ็งฐใ€‚็ป“ๆžœๅบ”็”จ็จ‹ๅบๅŒ…ๅฏ่ƒฝไผšไฝฟไปฃ็ ็ญพๅๅ’Œ/ๆˆ–ๅ…ฌ่ฏๅคฑ่ดฅใ€‚ diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/lic_template.plist b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/lic_template.plist index 072e7168fb7..ac1b32325e8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/lic_template.plist +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/lic_template.plist @@ -8,7 +8,9 @@ Attributes 0x0000 Data - AAAAAgAAAAAAAAAAAAQAAA== + + AAAABAAAAAAAAAADAAEAAAAOAAIAAQA0AAMAAQ== + ID 5000 Name @@ -21,17 +23,22 @@ Attributes 0x0000 Data - AAYPRW5nbGlzaCBkZWZhdWx0BUFncmVlCERpc2FncmVlBVByaW50B1NhdmUuLi56SWYgeW91IGFncmVlIHdpdGggdGhlIHRlcm1zIG9mIHRoaXMgbGljZW5zZSwgY2xpY2sgIkFncmVlIiB0byBhY2Nlc3MgdGhlIHNvZnR3YXJlLiAgSWYgeW91IGRvIG5vdCBhZ3JlZSwgcHJlc3MgIkRpc2FncmVlLiI= + + STR_DATA_ENGLISH + ID 5000 + Name - English buttons + English (United States) Attributes 0x0000 Data - AAYHRGV1dHNjaAtBa3plcHRpZXJlbghBYmxlaG5lbgdEcnVja2VuClNpY2hlcm4uLi7nS2xpY2tlbiBTaWUgaW4g0kFremVwdGllcmVu0ywgd2VubiBTaWUgbWl0IGRlbiBCZXN0aW1tdW5nZW4gZGVzIFNvZnR3YXJlLUxpemVuenZlcnRyYWdzIGVpbnZlcnN0YW5kZW4gc2luZC4gRmFsbHMgbmljaHQsIGJpdHRlINJBYmxlaG5lbtMgYW5rbGlja2VuLiBTaWUga5pubmVuIGRpZSBTb2Z0d2FyZSBudXIgaW5zdGFsbGllcmVuLCB3ZW5uIFNpZSDSQWt6ZXB0aWVyZW7TIGFuZ2VrbGlja3QgaGFiZW4u + + STR_DATA_GERMAN + ID 5001 Name @@ -41,151 +48,25 @@ Attributes 0x0000 Data - AAYHRW5nbGlzaAVBZ3JlZQhEaXNhZ3JlZQVQcmludAdTYXZlLi4ue0lmIHlvdSBhZ3JlZSB3aXRoIHRoZSB0ZXJtcyBvZiB0aGlzIGxpY2Vuc2UsIHByZXNzICJBZ3JlZSIgdG8gaW5zdGFsbCB0aGUgc29mdHdhcmUuICBJZiB5b3UgZG8gbm90IGFncmVlLCBwcmVzcyAiRGlzYWdyZWUiLg== + + STR_DATA_JAPANESE + ID 5002 Name - English - - - Attributes - 0x0000 - Data - AAYHRXNwYZZvbAdBY2VwdGFyCk5vIGFjZXB0YXIISW1wcmltaXIKR3VhcmRhci4uLsBTaSBlc3SHIGRlIGFjdWVyZG8gY29uIGxvcyB0jnJtaW5vcyBkZSBlc3RhIGxpY2VuY2lhLCBwdWxzZSAiQWNlcHRhciIgcGFyYSBpbnN0YWxhciBlbCBzb2Z0d2FyZS4gRW4gZWwgc3VwdWVzdG8gZGUgcXVlIG5vIGVzdI4gZGUgYWN1ZXJkbyBjb24gbG9zIHSOcm1pbm9zIGRlIGVzdGEgbGljZW5jaWEsIHB1bHNlICJObyBhY2VwdGFyLiI= - ID - 5003 - Name - Spanish - - - Attributes - 0x0000 - Data - AAYIRnJhbo1haXMIQWNjZXB0ZXIHUmVmdXNlcghJbXByaW1lcg5FbnJlZ2lzdHJlci4uLrpTaSB2b3VzIGFjY2VwdGV6IGxlcyB0ZXJtZXMgZGUgbGEgcHKOc2VudGUgbGljZW5jZSwgY2xpcXVleiBzdXIgIkFjY2VwdGVyIiBhZmluIGQnaW5zdGFsbGVyIGxlIGxvZ2ljaWVsLiBTaSB2b3VzIG4nkHRlcyBwYXMgZCdhY2NvcmQgYXZlYyBsZXMgdGVybWVzIGRlIGxhIGxpY2VuY2UsIGNsaXF1ZXogc3VyICJSZWZ1c2VyIi4= - ID - 5004 - Name - French - - - Attributes - 0x0000 - Data - AAYISXRhbGlhbm8HQWNjZXR0bwdSaWZpdXRvBlN0YW1wYQtSZWdpc3RyYS4uLn9TZSBhY2NldHRpIGxlIGNvbmRpemlvbmkgZGkgcXVlc3RhIGxpY2VuemEsIGZhaSBjbGljIHN1ICJBY2NldHRvIiBwZXIgaW5zdGFsbGFyZSBpbCBzb2Z0d2FyZS4gQWx0cmltZW50aSBmYWkgY2xpYyBzdSAiUmlmaXV0byIu - ID - 5005 - Name - Italian - - - Attributes - 0x0000 - Data - AAYISmFwYW5lc2UKk6+I04K1gtyCtwyTr4jTgrWC3IK5gvEIiPON/IK3gukHlduRti4uLrSWe4Ncg3SDZ4NFg0eDQY5nl3CLlpH4jF+W8YLMj/CMj4LJk6+I04KzguqC6Y/qjYeCyYLNgUGDXIN0g2eDRYNHg0GC8INDg5ODWINngVuDi4K3gumCvYLfgsmBdZOviNOCtYLcgreBdoLwiZ+CtYLEgq2CvoKzgqKBQoFAk6+I04KzguqCyIKij+qNh4LJgs2BQYF1k6+I04K1gtyCuYLxgXaC8ImfgrWCxIKtgr6Cs4KigUI= - ID - 5006 - Name Japanese Attributes 0x0000 Data - AAYKTmVkZXJsYW5kcwJKYQNOZWUFUHJpbnQJQmV3YWFyLi4upEluZGllbiB1IGFra29vcmQgZ2FhdCBtZXQgZGUgdm9vcndhYXJkZW4gdmFuIGRlemUgbGljZW50aWUsIGt1bnQgdSBvcCAnSmEnIGtsaWtrZW4gb20gZGUgcHJvZ3JhbW1hdHV1ciB0ZSBpbnN0YWxsZXJlbi4gSW5kaWVuIHUgbmlldCBha2tvb3JkIGdhYXQsIGtsaWt0IHUgb3AgJ05lZScu + + STR_DATA_SIMPLIFIED_CHINESE + ID - 5007 + 5003 Name - Dutch - - - Attributes - 0x0000 - Data - AAYGU3ZlbnNrCEdvZGuKbm5zBkF2YppqcwhTa3JpdiB1dAhTcGFyYS4uLpNPbSBEdSBnb2Rrim5uZXIgbGljZW5zdmlsbGtvcmVuIGtsaWNrYSBwjCAiR29ka4pubnMiIGaaciBhdHQgaW5zdGFsbGVyYSBwcm9ncmFtcHJvZHVrdGVuLiBPbSBEdSBpbnRlIGdvZGuKbm5lciBsaWNlbnN2aWxsa29yZW4sIGtsaWNrYSBwjCAiQXZimmpzIi4= - ID - 5008 - Name - Swedish - - - Attributes - 0x0000 - Data - AAYRUG9ydHVndZBzLCBCcmFzaWwJQ29uY29yZGFyCURpc2NvcmRhcghJbXByaW1pcglTYWx2YXIuLi6MU2UgZXN0hyBkZSBhY29yZG8gY29tIG9zIHRlcm1vcyBkZXN0YSBsaWNlbo1hLCBwcmVzc2lvbmUgIkNvbmNvcmRhciIgcGFyYSBpbnN0YWxhciBvIHNvZnR3YXJlLiBTZSBui28gZXN0hyBkZSBhY29yZG8sIHByZXNzaW9uZSAiRGlzY29yZGFyIi4= - ID - 5009 - Name - Brazilian Portuguese - - - Attributes - 0x0000 - Data - AAYSU2ltcGxpZmllZCBDaGluZXNlBM2s0uIGsrvNrNLiBLTy06EGtOa0oqGtVMjnufvE+s2s0uKxvtDtv8nQrdLptcTM9b/uo6zH67C0obDNrNLiobHAtLCy17C0y8jtvP6ho8jnufvE+rK7zazS4qOsx+uwtKGwsrvNrNLiobGhow== - ID - 5010 - Name - Simplified Chinese - - - Attributes - 0x0000 - Data - AAYTVHJhZGl0aW9uYWwgQ2hpbmVzZQSmULdOBqSjplC3TgSmQ6ZMBsB4pnOhS1CmcKpHsXqmULdOpbuzXKVpw9K4zKq6sfi02qFBvdCr9qGnplC3TqGopUimd7jLs27F6aFDpnCqR6SjplC3TqFBvdCr9qGnpKOmULdOoaihQw== - ID - 5011 - Name - Traditional Chinese - - - Attributes - 0x0000 - Data - AAYFRGFuc2sERW5pZwVVZW5pZwdVZHNrcml2CkFya2l2ZXIuLi6YSHZpcyBkdSBhY2NlcHRlcmVyIGJldGluZ2Vsc2VybmUgaSBsaWNlbnNhZnRhbGVuLCBza2FsIGR1IGtsaWtrZSBwjCDSRW5pZ9MgZm9yIGF0IGluc3RhbGxlcmUgc29mdHdhcmVuLiBLbGlrIHCMINJVZW5pZ9MgZm9yIGF0IGFubnVsbGVyZSBpbnN0YWxsZXJpbmdlbi4= - ID - 5012 - Name - Danish - - - Attributes - 0x0000 - Data - AAYFU3VvbWkISHl2imtzeW4KRW4gaHl2imtzeQdUdWxvc3RhCVRhbGxlbm5hyW9IeXaKa3N5IGxpc2Vuc3Npc29waW11a3NlbiBlaGRvdCBvc29pdHRhbWFsbGEg1Uh5doprc3nVLiBKb3MgZXQgaHl2imtzeSBzb3BpbXVrc2VuIGVodG9qYSwgb3NvaXRhINVFbiBoeXaKa3N51S4= - ID - 5013 - Name - Finnish - - - Attributes - 0x0000 - Data - AAYRRnJhbo1haXMgY2FuYWRpZW4IQWNjZXB0ZXIHUmVmdXNlcghJbXByaW1lcg5FbnJlZ2lzdHJlci4uLrpTaSB2b3VzIGFjY2VwdGV6IGxlcyB0ZXJtZXMgZGUgbGEgcHKOc2VudGUgbGljZW5jZSwgY2xpcXVleiBzdXIgIkFjY2VwdGVyIiBhZmluIGQnaW5zdGFsbGVyIGxlIGxvZ2ljaWVsLiBTaSB2b3VzIG4nkHRlcyBwYXMgZCdhY2NvcmQgYXZlYyBsZXMgdGVybWVzIGRlIGxhIGxpY2VuY2UsIGNsaXF1ZXogc3VyICJSZWZ1c2VyIi4= - ID - 5014 - Name - French Canadian - - - Attributes - 0x0000 - Data - AAYGS29yZWFuBLW/wMcJtb/AxyC+yMfUBsfBuLDGrgfA+sDlLi4ufrvnv+sgsOi+4LytwMcgs7u/67+hILW/wMfHz7jpLCAitb/AxyIgtNzD37imILStt68gvNLHwcauv/6+7rimILyzxKHHz73KvcO/wC4gtb/Ax8fPwfYgvsq0wrTZuOksICK1v8DHIL7Ix9QiILTcw9+4piC0qbijvcq9w7/ALg== - ID - 5015 - Name - Korean - - - Attributes - 0x0000 - Data - AAYFTm9yc2sERW5pZwlJa2tlIGVuaWcIU2tyaXYgdXQKQXJraXZlci4uLqNIdmlzIERlIGVyIGVuaWcgaSBiZXN0ZW1tZWxzZW5lIGkgZGVubmUgbGlzZW5zYXZ0YWxlbiwga2xpa2tlciBEZSBwjCAiRW5pZyIta25hcHBlbiBmb3IgjCBpbnN0YWxsZXJlIHByb2dyYW12YXJlbi4gSHZpcyBEZSBpa2tlIGVyIGVuaWcsIGtsaWtrZXIgRGUgcIwgIklra2UgZW5pZyIu - ID - 5016 - Name - Norwegian + Chinese (Simplified) TEXT @@ -194,50 +75,49 @@ Attributes 0x0000 Data - APPLICATION_LICENSE_TEXT + + APPLICATION_LICENSE_TEXT + ID 5000 Name - English SLA + English (United States) SLA + + + Attributes + 0x0000 + Data + + APPLICATION_LICENSE_TEXT + + ID + 5001 + Name + German SLA - - TMPL - Attributes 0x0000 Data - E0RlZmF1bHQgTGFuZ3VhZ2UgSUREV1JEBUNvdW50T0NOVAQqKioqTFNUQwtzeXMgbGFuZyBJRERXUkQebG9jYWwgcmVzIElEIChvZmZzZXQgZnJvbSA1MDAwRFdSRBAyLWJ5dGUgbGFuZ3VhZ2U/RFdSRAQqKioqTFNURQ== + + APPLICATION_LICENSE_TEXT + ID - 128 + 5002 Name - LPic + Japanese SLA - - plst - - - Attributes - 0x0050 - Data - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - ID - 0 - Name - - - - styl - Attributes 0x0000 Data - AAMAAAAAAAwACQAUAAAAAAAAAAAAAAAAACcADAAJABQBAAAAAAAAAAAAAAAAKgAMAAkAFAAAAAAAAAAAAAA= + + APPLICATION_LICENSE_TEXT + ID - 5000 + 5003 Name - English SLA + Chinese (Simplified) SLA diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 6896668ffdc..9d5407524a8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package jdk.jpackage.internal; import static jdk.jpackage.internal.I18N.buildConfigException; import java.nio.file.Path; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; @@ -44,6 +45,7 @@ import jdk.jpackage.internal.model.LauncherIcon; import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.ResourceDirLauncherIcon; import jdk.jpackage.internal.model.RuntimeBuilder; +import jdk.jpackage.internal.util.RootedPath; final class ApplicationBuilder { @@ -65,8 +67,8 @@ final class ApplicationBuilder { Optional.ofNullable(version).orElseGet(DEFAULTS::version), Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor), Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), - Optional.ofNullable(srcDir), - Optional.ofNullable(contentDirs).orElseGet(List::of), + Optional.ofNullable(appDirSources).orElseGet(List::of), + Optional.ofNullable(contentDirSources).orElseGet(List::of), appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList, @@ -126,13 +128,13 @@ final class ApplicationBuilder { return this; } - ApplicationBuilder srcDir(Path v) { - srcDir = v; + ApplicationBuilder appDirSources(Collection v) { + appDirSources = v; return this; } - ApplicationBuilder contentDirs(List v) { - contentDirs = v; + ApplicationBuilder contentDirSources(Collection v) { + contentDirSources = v; return this; } @@ -246,8 +248,8 @@ final class ApplicationBuilder { app.version(), app.vendor(), app.copyright(), - app.srcDir(), - app.contentDirs(), + app.appDirSources(), + app.contentDirSources(), Objects.requireNonNull(appImageLayout), app.runtimeBuilder(), app.launchers(), @@ -294,9 +296,9 @@ final class ApplicationBuilder { private String version; private String vendor; private String copyright; - private Path srcDir; + private Collection appDirSources; private ExternalApplication externalApp; - private List contentDirs; + private Collection contentDirSources; private AppImageLayout appImageLayout; private RuntimeBuilder runtimeBuilder; private ApplicationLaunchers launchers; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java index 3d2ffbfdc7c..5edc4d69c81 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,19 +25,14 @@ package jdk.jpackage.internal; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - -import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Stream; import jdk.jpackage.internal.PackagingPipeline.ApplicationImageTaskAction; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; @@ -45,7 +40,7 @@ import jdk.jpackage.internal.model.CustomLauncherIcon; import jdk.jpackage.internal.model.DefaultLauncherIcon; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.ResourceDirLauncherIcon; -import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.RootedPath; final class ApplicationImageUtils { @@ -86,21 +81,14 @@ final class ApplicationImageUtils { }; } - static ApplicationImageTaskAction createCopyContentAction(Supplier> excludeCopyDirs) { + static ApplicationImageTaskAction createCopyContentAction() { return env -> { - var excludeCandidates = Stream.concat( - excludeCopyDirs.get().stream(), - Stream.of(env.env().buildRoot(), env.env().appImageDir()) - ).map(Path::toAbsolutePath).toList(); - - env.app().srcDir().ifPresent(toConsumer(srcDir -> { - copyRecursive(srcDir, env.resolvedLayout().appDirectory(), excludeCandidates); - })); - - for (var srcDir : env.app().contentDirs()) { - copyRecursive(srcDir, - env.resolvedLayout().contentDirectory().resolve(srcDir.getFileName()), - excludeCandidates); + for (var e : List.of( + Map.entry(env.app().appDirSources(), env.resolvedLayout().appDirectory()), + Map.entry(env.app().contentDirSources(), env.resolvedLayout().contentDirectory()) + )) { + RootedPath.copy(e.getKey().stream(), e.getValue(), + StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); } }; } @@ -126,21 +114,4 @@ final class ApplicationImageUtils { } }; } - - private static void copyRecursive(Path srcDir, Path dstDir, List excludeDirs) throws IOException { - srcDir = srcDir.toAbsolutePath(); - - List excludes = new ArrayList<>(); - - for (var path : excludeDirs) { - if (Files.isDirectory(path)) { - if (path.startsWith(srcDir) && !Files.isSameFile(path, srcDir)) { - excludes.add(path); - } - } - } - - FileUtils.copyRecursive(srcDir, dstDir.toAbsolutePath(), excludes, - LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING); - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java index e4473b1e5ce..331bde29d27 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java @@ -42,17 +42,15 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; -import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; import jdk.jpackage.internal.cli.CliBundlingEnvironment; import jdk.jpackage.internal.cli.Options; import jdk.jpackage.internal.cli.StandardBundlingOperation; -import jdk.jpackage.internal.model.AppImagePackageType; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.PackageType; -import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.Result; class DefaultBundlingEnvironment implements CliBundlingEnvironment { @@ -134,7 +132,9 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { Objects.requireNonNull(app); Objects.requireNonNull(pipelineBuilder); - final var outputDir = OptionUtils.outputDir(options).resolve(app.appImageDirName()); + final var outputDir = PathUtils.normalizedAbsolutePath(OptionUtils.outputDir(options).resolve(app.appImageDirName())); + + Log.verbose(I18N.getString("message.create-app-image")); IOUtils.writableOutputDir(outputDir.getParent()); @@ -142,14 +142,13 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { .predefinedAppImageLayout(app.asApplicationLayout().orElseThrow()) .create(options, app); - Log.verbose(I18N.format("message.creating-app-bundle", outputDir.getFileName(), outputDir.toAbsolutePath().getParent())); - if (Files.exists(outputDir)) { - throw new JPackageException(I18N.format("error.root-exists", outputDir.toAbsolutePath())); + throw new JPackageException(I18N.format("error.root-exists", outputDir)); } - pipelineBuilder.excludeDirFromCopying(outputDir.getParent()) - .create().execute(BuildEnv.withAppImageDir(env, outputDir), app); + pipelineBuilder.create().execute(BuildEnv.withAppImageDir(env, outputDir), app); + + Log.verbose(I18N.getString("message.app-image-created")); } static void createNativePackage(Options options, @@ -174,11 +173,20 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { Objects.requireNonNull(createPipelineBuilder); Objects.requireNonNull(pipelineBuilderMutatorFactory); + var pipelineBuilder = Objects.requireNonNull(createPipelineBuilder.apply(pkg)); + + // Delete an old output package file (if any) before creating a new one. + pipelineBuilder.task(PackageTaskID.DELETE_OLD_PACKAGE_FILE) + .addDependencies(pipelineBuilder.taskGraphSnapshot().getTailsOf(PackageTaskID.CREATE_PACKAGE_FILE)) + .addDependent(PackageTaskID.CREATE_PACKAGE_FILE) + .packageAction(PackagingPipeline::deleteOutputBundle) + .add(); + Packager.build().pkg(pkg) - .outputDir(OptionUtils.outputDir(options)) - .env(Objects.requireNonNull(createBuildEnv.apply(options, pkg))) - .pipelineBuilderMutatorFactory(pipelineBuilderMutatorFactory) - .execute(Objects.requireNonNull(createPipelineBuilder.apply(pkg))); + .outputDir(OptionUtils.outputDir(options)) + .env(Objects.requireNonNull(createBuildEnv.apply(options, pkg))) + .pipelineBuilderMutatorFactory(pipelineBuilderMutatorFactory) + .execute(pipelineBuilder); } @Override @@ -195,10 +203,6 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { permanentWorkDirectory = Optional.of(tempDir.path()); } bundler.accept(tempDir.options()); - - var packageType = OptionUtils.bundlingOperation(cmdline).packageType(); - - Log.verbose(I18N.format("message.bundle-created", I18N.getString(bundleTypeDescription(packageType, op.os())))); } catch (IOException ex) { throw new UncheckedIOException(ex); } finally { @@ -219,55 +223,6 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { }); } - private String bundleTypeDescription(PackageType type, OperatingSystem os) { - switch (type) { - case StandardPackageType stdType -> { - switch (stdType) { - case WIN_MSI -> { - return "bundle-type.win-msi"; - } - case WIN_EXE -> { - return "bundle-type.win-exe"; - } - case LINUX_DEB -> { - return "bundle-type.linux-deb"; - } - case LINUX_RPM -> { - return "bundle-type.linux-rpm"; - } - case MAC_DMG -> { - return "bundle-type.mac-dmg"; - } - case MAC_PKG -> { - return "bundle-type.mac-pkg"; - } - default -> { - throw new AssertionError(); - } - } - } - case AppImagePackageType appImageType -> { - switch (os) { - case WINDOWS -> { - return "bundle-type.win-app"; - } - case LINUX -> { - return "bundle-type.linux-app"; - } - case MACOS -> { - return "bundle-type.mac-app"; - } - default -> { - throw new AssertionError(); - } - } - } - default -> { - throw new AssertionError(); - } - } - } - private static final class CachingSupplier implements Supplier { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java index ca7a630b6d1..53c587ab37c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Executor.java @@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.UnaryOperator; import java.util.spi.ToolProvider; import java.util.stream.Stream; +import jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput; import jdk.jpackage.internal.util.CommandLineFormat; import jdk.jpackage.internal.util.CommandOutputControl; import jdk.jpackage.internal.util.CommandOutputControl.ProcessAttributes; @@ -211,17 +212,11 @@ final class Executor { throw new IllegalStateException("No target to execute"); } - PrintableOutputBuilder printableOutputBuilder; - if (dumpOutput()) { - printableOutputBuilder = new PrintableOutputBuilder(coc); - } else { - printableOutputBuilder = null; - } - if (dumpOutput()) { Log.verbose(String.format("Running %s", CommandLineFormat.DEFAULT.apply(List.of(commandLine().getFirst())))); } + var printableOutputBuilder = new PrintableOutputBuilder(coc); Result result; try { if (timeout == null) { @@ -233,11 +228,12 @@ final class Executor { throw ExceptionBox.toUnchecked(ex); } + var printableOutput = printableOutputBuilder.create(); if (dumpOutput()) { - log(result, printableOutputBuilder.create()); + log(result, printableOutput); } - return result; + return ExecutableAttributesWithCapturedOutput.augmentResultWithOutput(result, printableOutput); } Result executeExpectSuccess() throws IOException { @@ -309,7 +305,7 @@ final class Executor { pid.ifPresent(p -> { sb.append(" [PID: ").append(p).append("]"); }); - sb.append(":\n ").append(result.execAttrs()); + sb.append(":\n ").append(result.execAttrs().printableCommandLine()); Log.verbose(sb.toString()); if (!printableOutput.isEmpty()) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java index 6b74cab4e65..cccd05792d6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +46,7 @@ import static jdk.jpackage.internal.cli.StandardOption.RESOURCE_DIR; import static jdk.jpackage.internal.cli.StandardOption.VENDOR; import java.nio.file.Path; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; @@ -60,6 +61,7 @@ import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.LauncherModularStartupInfo; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.util.RootedPath; final class FromOptions { @@ -168,8 +170,15 @@ final class FromOptions { APP_VERSION.ifPresentIn(options, appBuilder::version); VENDOR.ifPresentIn(options, appBuilder::vendor); COPYRIGHT.ifPresentIn(options, appBuilder::copyright); - INPUT.ifPresentIn(options, appBuilder::srcDir); - APP_CONTENT.ifPresentIn(options, appBuilder::contentDirs); + INPUT.ifPresentIn(options, appBuilder::appDirSources); + APP_CONTENT.findIn(options).map((List> v) -> { + // Reverse the order of content sources. + // If there are multiple source files for the same + // destination file, only the first will be used. + // Reversing the order of content sources makes it use the last file + // from the original list of source files for the given destination file. + return v.reversed().stream().flatMap(Collection::stream).toList(); + }).ifPresent(appBuilder::contentDirSources); if (isRuntimeInstaller) { appBuilder.appImageLayout(runtimeLayout); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java index c1b56b24e0a..91ae37870a5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import java.io.PrintWriter; import java.util.Optional; import java.util.function.Supplier; @@ -46,6 +47,18 @@ public final class Globals { return objectFactory(ObjectFactory.build(objectFactory).executorFactory(v).create()); } + Log.Logger logger() { + return logger; + } + + public void loggerOutputStreams(PrintWriter out, PrintWriter err) { + logger.setPrintWriter(out, err); + } + + public void loggerVerbose() { + logger.setVerbose(); + } + public static int main(Supplier mainBody) { if (INSTANCE.isBound()) { return mainBody.get(); @@ -65,6 +78,7 @@ public final class Globals { } private ObjectFactory objectFactory = ObjectFactory.DEFAULT; + private final Log.Logger logger = new Log.Logger(); private static final ScopedValue INSTANCE = ScopedValue.newInstance(); private static final Globals DEFAULT = new Globals(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java index ed030a4a726..1ba384dba2d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 +51,12 @@ import jdk.jpackage.internal.FileAssociationGroup.FileAssociationNoMimesExceptio import jdk.jpackage.internal.cli.Options; import jdk.jpackage.internal.cli.StandardFaOption; import jdk.jpackage.internal.model.CustomLauncherIcon; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.DefaultLauncherIcon; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.LauncherIcon; +import jdk.jpackage.internal.util.RootedPath; final class LauncherFromOptions { @@ -91,7 +93,9 @@ final class LauncherFromOptions { if (PREDEFINED_APP_IMAGE.findIn(options).isEmpty()) { final var startupInfoBuilder = new LauncherStartupInfoBuilder(); - INPUT.ifPresentIn(options, startupInfoBuilder::inputDir); + INPUT.findIn(options).flatMap(v -> { + return v.stream().findAny().map(RootedPath::root); + }).ifPresent(startupInfoBuilder::inputDir); ARGUMENTS.ifPresentIn(options, startupInfoBuilder::defaultParameters); JAVA_OPTIONS.ifPresentIn(options, startupInfoBuilder::javaOptions); MAIN_JAR.ifPresentIn(options, startupInfoBuilder::mainJar); @@ -130,8 +134,7 @@ final class LauncherFromOptions { .advice("error.no-content-types-for-file-association.advice", faID) .create(); } catch (FileAssociationNoExtensionsException ex) { - // TODO: Must do something about this condition! - throw new AssertionError(); + throw new JPackageException(I18N.format("error.no-extensions-for-file-association", faID)); } catch (FileAssociationException ex) { // Should never happen throw new UnsupportedOperationException(ex); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java index 0f51fa166f9..5c27ef67500 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java @@ -61,16 +61,6 @@ public class Log { this.err = err; } - public void flush() { - if (out != null) { - out.flush(); - } - - if (err != null) { - err.flush(); - } - } - public void info(String msg) { if (out != null) { out.println(msg); @@ -111,46 +101,27 @@ public class Log { } } - private static final InheritableThreadLocal instance = - new InheritableThreadLocal() { - @Override protected Logger initialValue() { - return new Logger(); - } - }; - - public static void setPrintWriter (PrintWriter out, PrintWriter err) { - instance.get().setPrintWriter(out, err); - } - - public static void flush() { - instance.get().flush(); - } - public static void info(String msg) { - instance.get().info(msg); + Globals.instance().logger().info(msg); } public static void fatalError(String msg) { - instance.get().fatalError(msg); + Globals.instance().logger().fatalError(msg); } public static void error(String msg) { - instance.get().error(msg); - } - - public static void setVerbose() { - instance.get().setVerbose(); + Globals.instance().logger().error(msg); } public static boolean isVerbose() { - return instance.get().isVerbose(); + return Globals.instance().logger().isVerbose(); } public static void verbose(String msg) { - instance.get().verbose(msg); + Globals.instance().logger().verbose(msg); } public static void verbose(Throwable t) { - instance.get().verbose(t); + Globals.instance().logger().verbose(t); } } 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 c94dada9262..315e3bce0f1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ import static java.util.stream.Collectors.toMap; import static jdk.jpackage.internal.model.AppImageLayout.toPathGroup; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -39,12 +39,16 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.Callable; +import java.util.function.BiConsumer; +import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Stream; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.pipeline.DirectedEdge; import jdk.jpackage.internal.pipeline.FixedDAG; @@ -97,7 +101,7 @@ final class PackagingPipeline { /** * The way to access packaging build environment before building a package in a pipeline. */ - interface StartupParameters { + sealed interface StartupParameters { BuildEnv packagingEnv(); } @@ -127,6 +131,7 @@ final class PackagingPipeline { enum PackageTaskID implements TaskID { RUN_POST_IMAGE_USER_SCRIPT, CREATE_CONFIG_FILES, + DELETE_OLD_PACKAGE_FILE, CREATE_PACKAGE_FILE } @@ -183,9 +188,11 @@ final class PackagingPipeline { void execute() throws IOException; } - record TaskConfig(Optional action) { + record TaskConfig(Optional action, Optional beforeAction, Optional afterAction) { TaskConfig { Objects.requireNonNull(action); + Objects.requireNonNull(beforeAction); + Objects.requireNonNull(afterAction); } } @@ -196,47 +203,64 @@ final class PackagingPipeline { final class TaskBuilder extends TaskSpecBuilder { - private TaskBuilder(TaskID id) { - super(id); - } - - private TaskBuilder(TaskID id, TaskConfig config) { - this(id); - config.action().ifPresent(this::setAction); - } - - private TaskBuilder setAction(TaskAction v) { - action = v; - return this; - } - TaskBuilder noaction() { - action = null; - return this; + return setAction(ActionRole.WORKLOAD, null); } TaskBuilder applicationAction(ApplicationImageTaskAction action) { - return setAction(action); + return applicationAction(ActionRole.WORKLOAD, action); } TaskBuilder appImageAction(AppImageTaskAction action) { - return setAction(action); + return appImageAction(ActionRole.WORKLOAD, action); } TaskBuilder copyAction(CopyAppImageTaskAction action) { - return setAction(action); + return copyAction(ActionRole.WORKLOAD, action); } TaskBuilder packageAction(PackageTaskAction action) { - return setAction(action); + return packageAction(ActionRole.WORKLOAD, action); } TaskBuilder action(NoArgTaskAction action) { - return setAction(action); + return action(ActionRole.WORKLOAD, action); + } + + TaskBuilder logAppImageActionBegin(String keyId, Function, Object[]> formatArgsSupplier) { + return logAppImageAction(ActionRole.BEFORE, keyId, formatArgsSupplier); + } + + TaskBuilder logAppImageActionEnd(String keyId, Function, Object[]> formatArgsSupplier) { + return logAppImageAction(ActionRole.AFTER, keyId, formatArgsSupplier); + } + + TaskBuilder logPackageActionBegin(String keyId, Function, Object[]> argsSupplier) { + return logPackageAction(ActionRole.BEFORE, keyId, argsSupplier); + } + + TaskBuilder logPackageActionEnd(String keyId, Function, Object[]> argsSupplier) { + return logPackageAction(ActionRole.AFTER, keyId, argsSupplier); + } + + TaskBuilder logActionBegin(String keyId, Supplier formatArgsSupplier) { + return logAction(ActionRole.BEFORE, keyId, formatArgsSupplier); + } + + TaskBuilder logActionBegin(String keyId, Object... formatArgsSupplier) { + return logAction(ActionRole.BEFORE, keyId, () -> formatArgsSupplier); + } + + TaskBuilder logActionEnd(String keyId, Supplier formatArgsSupplier) { + return logAction(ActionRole.AFTER, keyId, formatArgsSupplier); + } + + TaskBuilder logActionEnd(String keyId, Object... formatArgsSupplier) { + return logAction(ActionRole.AFTER, keyId, () -> formatArgsSupplier); } boolean hasAction() { - return action != null; + return workloadAction != null; } @Override @@ -272,13 +296,109 @@ final class PackagingPipeline { } Builder add() { - final var config = new TaskConfig(Optional.ofNullable(action)); + final var config = new TaskConfig( + Optional.ofNullable(workloadAction), + Optional.ofNullable(beforeAction), + Optional.ofNullable(afterAction)); taskConfig.put(task(), config); createLinks().forEach(Builder.this::linkTasks); return Builder.this; } - private TaskAction action; + + private enum ActionRole { + WORKLOAD(TaskBuilder::setWorkloadAction), + BEFORE(TaskBuilder::setBeforeAction), + AFTER(TaskBuilder::setAfterAction), + ; + + ActionRole(BiConsumer actionSetter) { + this.actionSetter = Objects.requireNonNull(actionSetter); + } + + TaskBuilder setAction(TaskBuilder taskBuilder, TaskAction action) { + actionSetter.accept(taskBuilder, action); + return taskBuilder; + } + + private final BiConsumer actionSetter; + } + + + private TaskBuilder(TaskID id) { + super(id); + } + + private TaskBuilder(TaskID id, TaskConfig config) { + this(id); + config.action().ifPresent(this::setWorkloadAction); + config.beforeAction().ifPresent(this::setBeforeAction); + config.afterAction().ifPresent(this::setAfterAction); + } + + private TaskBuilder setAction(ActionRole role, TaskAction v) { + return role.setAction(this, v); + } + + private TaskBuilder setWorkloadAction(TaskAction v) { + workloadAction = v; + return this; + } + + private TaskBuilder setBeforeAction(TaskAction v) { + beforeAction = v; + return this; + } + + private TaskBuilder setAfterAction(TaskAction v) { + afterAction = v; + return this; + } + + private TaskBuilder applicationAction(ActionRole role, ApplicationImageTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder appImageAction(ActionRole role, AppImageTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder copyAction(ActionRole role, CopyAppImageTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder packageAction(ActionRole role, PackageTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder action(ActionRole role, NoArgTaskAction action) { + return setAction(role, action); + } + + private TaskBuilder logAppImageAction(ActionRole role, String keyId, Function, Object[]> formatArgsSupplier) { + Objects.requireNonNull(keyId); + return appImageAction(role, (AppImageBuildEnv env) -> { + Log.verbose(I18N.format(keyId, formatArgsSupplier.apply(env))); + }); + } + + private TaskBuilder logPackageAction(ActionRole role, String keyId, Function, Object[]> formatArgsSupplier) { + Objects.requireNonNull(keyId); + return packageAction(role, (PackageBuildEnv env) -> { + Log.verbose(I18N.format(keyId, formatArgsSupplier.apply(env))); + }); + } + + private TaskBuilder logAction(ActionRole role, String keyId, Supplier formatArgsSupplier) { + Objects.requireNonNull(keyId); + return action(role, () -> { + Log.verbose(I18N.format(keyId, formatArgsSupplier.get())); + }); + } + + private TaskAction workloadAction; + private TaskAction beforeAction; + private TaskAction afterAction; } Builder linkTasks(DirectedEdge edge) { @@ -294,7 +414,11 @@ final class PackagingPipeline { } TaskBuilder task(TaskID id) { - return new TaskBuilder(id); + return Optional.ofNullable(taskConfig.get(id)).map(taskConfig -> { + return new TaskBuilder(id, taskConfig); + }).orElseGet(() -> { + return new TaskBuilder(id); + }); } Stream configuredTasks() { @@ -303,12 +427,6 @@ final class PackagingPipeline { }); } - Builder excludeDirFromCopying(Path path) { - Objects.requireNonNull(path); - excludeCopyDirs.add(path); - return this; - } - Builder contextMapper(UnaryOperator v) { contextMapper = v; return this; @@ -331,7 +449,6 @@ final class PackagingPipeline { } private final FixedDAG.Builder taskGraphBuilder = FixedDAG.build(); - private final List excludeCopyDirs = new ArrayList<>(); private final Map taskConfig = new HashMap<>(); private UnaryOperator contextMapper; private FixedDAG taskGraphSnapshot; @@ -365,7 +482,7 @@ final class PackagingPipeline { builder.task(BuildApplicationTaskID.CONTENT) .addDependent(BuildApplicationTaskID.APP_IMAGE_FILE) - .applicationAction(ApplicationImageUtils.createCopyContentAction(() -> builder.excludeCopyDirs)).add(); + .applicationAction(ApplicationImageUtils.createCopyContentAction()).add(); return builder; } @@ -392,6 +509,8 @@ final class PackagingPipeline { builder.task(PackageTaskID.CREATE_PACKAGE_FILE) .addDependent(PrimaryTaskID.PACKAGE) + .logActionBegin("message.create-package") + .logActionEnd("message.package-created") .add(); builder.task(PrimaryTaskID.PACKAGE).add(); @@ -425,6 +544,17 @@ final class PackagingPipeline { .run(env.env(), env.pkg().app().name()); } + static void deleteOutputBundle(PackageBuildEnv env) throws IOException { + + var outputBundle = env.outputDir().resolve(env.pkg().packageFileNameWithSuffix()); + + try { + Files.deleteIfExists(outputBundle); + } catch (IOException ex) { + throw new JPackageException(I18N.format("error.output-bundle-cannot-be-overwritten", outputBundle.toAbsolutePath()), ex); + } + } + private PackagingPipeline(FixedDAG taskGraph, Map taskConfig, UnaryOperator contextMapper) { this.taskGraph = Objects.requireNonNull(taskGraph); @@ -645,7 +775,13 @@ final class PackagingPipeline { } if (accepted) { + if (config.beforeAction.isPresent()) { + context.execute(config.beforeAction.orElseThrow()); + } context.execute(config.action.orElseThrow()); + if (config.afterAction.isPresent()) { + context.execute(config.afterAction.orElseThrow()); + } } return null; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java index 57b92471e4a..bff35874645 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package jdk.jpackage.internal.cli; import static java.util.stream.Collectors.toUnmodifiableMap; import static java.util.stream.Collectors.toUnmodifiableSet; +import static jdk.jpackage.internal.cli.OptionValueConverter.convertString; import java.lang.reflect.Array; import java.util.ArrayList; @@ -565,7 +566,7 @@ final class JOptSimpleOptionsBuilder { final var converter = optionSpec.converter().orElseThrow(); final Result conversionResult = optionValue.map(v -> { - return converter.convert(optionName(), StringToken.of(v)); + return convertString(converter, optionName(), StringToken.of(v)); }).orElseGet(() -> { return Result.ofValue(optionSpec.defaultOptionalValue().orElseThrow()); }); @@ -579,7 +580,7 @@ final class JOptSimpleOptionsBuilder { final String str = getOptionValue(List.of(tokens), optionSpec.mergePolicy()).getFirst(); final String[] token = arrConverter.tokenize(str); if (token.length == 1 && str.equals(token[0])) { - final var singleTokenConversionResult = converter.convert(optionName(), StringToken.of(str)); + final var singleTokenConversionResult = convertString(converter, optionName(), StringToken.of(str)); if (singleTokenConversionResult.hasValue()) { return singleTokenConversionResult; } 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 31be2bb33c5..562a0d2d3c1 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 @@ -29,10 +29,12 @@ import static jdk.jpackage.internal.cli.StandardOption.HELP; import static jdk.jpackage.internal.cli.StandardOption.VERBOSE; import static jdk.jpackage.internal.cli.StandardOption.VERSION; +import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; +import java.io.StringReader; import java.io.UncheckedIOException; import java.nio.file.NoSuchFileException; import java.util.Collection; @@ -48,7 +50,11 @@ import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.Globals; import jdk.jpackage.internal.Log; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput; import jdk.jpackage.internal.model.JPackageException; +import jdk.jpackage.internal.model.SelfContainedException; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedExitCodeException; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedResultException; import jdk.jpackage.internal.util.Slot; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -79,8 +85,8 @@ public final class Main { @Override public int run(PrintStream out, PrintStream err, String... args) { - PrintWriter outWriter = new PrintWriter(out, true); - PrintWriter errWriter = new PrintWriter(err, true); + PrintWriter outWriter = toPrintWriter(out); + PrintWriter errWriter = toPrintWriter(err); try { try { return run(outWriter, errWriter, args); @@ -98,8 +104,8 @@ public final class Main { } public static void main(String... args) { - var out = new PrintWriter(System.out, true); - var err = new PrintWriter(System.err, true); + var out = toPrintWriter(System.out); + var err = toPrintWriter(System.err); System.exit(run(out, err, args)); } @@ -127,7 +133,7 @@ public final class Main { Objects.requireNonNull(out); Objects.requireNonNull(err); - Log.setPrintWriter(out, err); + Globals.instance().loggerOutputStreams(out, err); final var runner = new Runner(t -> { new ErrorReporter(_ -> { @@ -179,7 +185,7 @@ public final class Main { } if (VERBOSE.containsIn(options)) { - Log.setVerbose(); + Globals.instance().loggerVerbose(); } final var optionsProcessor = new OptionsProcessor(parsedOptionsBuilder, bundlingEnv); @@ -239,44 +245,60 @@ public final class Main { reportError(ex.getCause()); } else if (t instanceof UncheckedIOException ex) { reportError(ex.getCause()); + } else if (t instanceof UnexpectedResultException ex) { + printExternalCommandError(ex); } else { printError(t, Optional.empty()); } } - private void printError(Throwable t, Optional advice) { - var isAlienException = isAlienExceptionType(t); + private void printExternalCommandError(UnexpectedResultException ex) { + var result = ex.getResult(); + var commandOutput = ((ExecutableAttributesWithCapturedOutput)result.execAttrs()).printableOutput(); + var printableCommandLine = result.execAttrs().printableCommandLine(); - if (isAlienException || verbose) { + if (verbose) { + stackTracePrinter.accept(ex); + } + + String msg; + if (ex instanceof UnexpectedExitCodeException) { + msg = I18N.format("error.command-failed-unexpected-exit-code", result.getExitCode(), printableCommandLine); + } else if (result.exitCode().isPresent()) { + msg = I18N.format("error.command-failed-unexpected-output", printableCommandLine); + } else { + msg = I18N.format("error.command-failed-timed-out", printableCommandLine); + } + + messagePrinter.accept(I18N.format("message.error-header", msg)); + if (!verbose) { + messagePrinter.accept(I18N.format("message.failed-command-output-header")); + try (var lines = new BufferedReader(new StringReader(commandOutput)).lines()) { + lines.forEach(messagePrinter); + } + } + } + + private void printError(Throwable t, Optional advice) { + var isSelfContained = isSelfContained(t); + + if (!isSelfContained || verbose) { stackTracePrinter.accept(t); } String msg; - if (isAlienException) { - msg = t.toString(); - } else { + if (isSelfContained) { msg = t.getMessage(); + } else { + msg = t.toString(); } messagePrinter.accept(I18N.format("message.error-header", msg)); advice.ifPresent(v -> messagePrinter.accept(I18N.format("message.advice-header", v))); } - private static boolean isAlienExceptionType(Throwable t) { - switch (t) { - case JPackageException _ -> { - return false; - } - case Utils.ParseException _ -> { - return false; - } - case StandardOption.AddLauncherIllegalArgumentException _ -> { - return false; - } - default -> { - return true; - } - } + private static boolean isSelfContained(Throwable t) { + return t.getClass().getAnnotation(SelfContainedException.class) != null; } } @@ -310,6 +332,10 @@ public final class Main { return System.getProperty("java.version"); } + private static PrintWriter toPrintWriter(PrintStream ps) { + return new PrintWriter(ps, true, ps.charset()); + } + private enum DefaultBundlingEnvironmentLoader implements Supplier { INSTANCE; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionArrayValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionArrayValueConverter.java index 401d5e15d28..9b757c29d36 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionArrayValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionArrayValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package jdk.jpackage.internal.cli; * * @param option value element type */ -interface OptionArrayValueConverter extends OptionValueConverter { +interface OptionArrayValueConverter extends OptionValueConverter { /** * Splits the given string into tokens and returns the result. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java index c6aa46a6940..60674e6bdfe 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Stream; +import jdk.jpackage.internal.util.Result; /** @@ -56,7 +57,7 @@ import java.util.stream.Stream; */ record OptionSpec( List names, - Optional> converter, + Optional> converter, Set scope, MergePolicy mergePolicy, Optional defaultOptionalValue, @@ -134,7 +135,7 @@ record OptionSpec( }); } - OptionSpec copyWithConverter(OptionValueConverter converter) { + OptionSpec copyWithConverter(OptionValueConverter converter) { if (!defaultOptionalValue.isEmpty()) { throw new UnsupportedOperationException("Can not convert an option spec with optional value"); } @@ -169,12 +170,16 @@ record OptionSpec( return valueType(converter).orElseThrow(); } + Result convert(OptionName optionName, StringToken optionValue) { + return OptionValueConverter.convertString(converter().orElseThrow(), optionName, optionValue); + } + @SuppressWarnings("unchecked") Optional> arrayValueConverter() { return converter.filter(OptionArrayValueConverter.class::isInstance).map(v -> (OptionArrayValueConverter)v); } - private static Optional> valueType(Optional> valueConverter) { + private static Optional> valueType(Optional> valueConverter) { return valueConverter.map(OptionValueConverter::valueType); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java index e27d6472369..5eecbc9b464 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal.cli; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + import java.io.File; import java.lang.reflect.Array; import java.util.Arrays; @@ -61,22 +63,49 @@ final class OptionSpecBuilder { this.valueType = Objects.requireNonNull(valueType); } - OptionSpecBuilder(OptionSpecBuilder other) { + private OptionSpecBuilder(OptionSpecBuilder other) { valueType = other.valueType; + initFrom(other); + defaultValue = other.defaultValue; + defaultOptionalValue = other.defaultOptionalValue; + converterBuilder = other.converterBuilder.copy(); + validatorBuilder = other.validatorBuilder.copy(); + validator = other.validator; + + if (other.arrayDefaultValue != null) { + arrayDefaultValue = Arrays.copyOf(other.arrayDefaultValue, other.arrayDefaultValue.length); + } else { + arrayDefaultValue = null; + } + } + + private OptionSpecBuilder(OptionSpecBuilder other, ValueConverter converter) { + Function converterFunction = toFunction(converter::convert); + + this.valueType = converter.valueType(); + initFrom(other); + converter(other, converter); + + other.defaultValue().map(converterFunction).ifPresent(this::defaultValue); + other.defaultOptionalValue().map(converterFunction).ifPresent(this::defaultOptionalValue); + + if (other.arrayDefaultValue != null) { + arrayDefaultValue = Stream.of(other.arrayDefaultValue).map(converterFunction).toArray(length -> { + @SuppressWarnings("unchecked") + var arr = (T[])Array.newInstance(valueType, length); + return arr; + }); + } + } + + private void initFrom(OptionSpecBuilder other) { name = other.name; + nameAliases.clear(); nameAliases.addAll(other.nameAliases); description = other.description; mergePolicy = other.mergePolicy; scope = Set.copyOf(other.scope); - defaultValue = other.defaultValue; - defaultOptionalValue = other.defaultOptionalValue; valuePattern = other.valuePattern; - converterBuilder = other.converterBuilder.copy(); - validatorBuilder = other.validatorBuilder.copy(); - - if (other.arrayDefaultValue != null) { - arrayDefaultValue = Arrays.copyOf(other.arrayDefaultValue, other.arrayDefaultValue.length); - } arrayValuePatternSeparator = other.arrayValuePatternSeparator; arrayTokenizer = other.arrayTokenizer; } @@ -85,6 +114,14 @@ final class OptionSpecBuilder { return new OptionSpecBuilder<>(this); } + OptionSpecBuilder map(ValueConverter converter) { + return new OptionSpecBuilder<>(this, converter); + } + + OptionSpecBuilder map(Function, OptionSpecBuilder> mapper) { + return mapper.apply(this); + } + Class valueType() { return valueType; } @@ -135,10 +172,20 @@ final class OptionSpecBuilder { scope, OptionSpecBuilder.this.mergePolicy().orElse(MergePolicy.CONCATENATE), defaultArrayOptionalValue(), - Optional.of(arryValuePattern()), + Optional.of(arrayValuePattern()), OptionSpecBuilder.this.description().orElse("")); } + Optional> createValidator() { + return Optional.ofNullable(validator).or(() -> { + if (validatorBuilder.hasValidatingMethod()) { + return Optional.of(validatorBuilder.create()); + } else { + return Optional.empty(); + } + }); + } + OptionSpecBuilder tokenizer(String splitRegexp) { Objects.requireNonNull(splitRegexp); return tokenizer(str -> { @@ -162,11 +209,13 @@ final class OptionSpecBuilder { OptionSpecBuilder validatorExceptionFormatString(String v) { validatorBuilder.formatString(v); + validator = null; return this; } - OptionSpecBuilder validatorExceptionFormatString(UnaryOperator mutator) { - validatorBuilder.formatString(mutator.apply(validatorBuilder.formatString().orElse(null))); + OptionSpecBuilder validatorExceptionFormatString(UnaryOperator mapper) { + validatorBuilder.formatString(mapper.apply(validatorBuilder.formatString().orElse(null))); + validator = null; return this; } @@ -175,18 +224,19 @@ final class OptionSpecBuilder { return this; } - OptionSpecBuilder converterExceptionFormatString(UnaryOperator mutator) { - converterBuilder.formatString(mutator.apply(converterBuilder.formatString().orElse(null))); + OptionSpecBuilder converterExceptionFormatString(UnaryOperator mapper) { + converterBuilder.formatString(mapper.apply(converterBuilder.formatString().orElse(null))); return this; } OptionSpecBuilder validatorExceptionFactory(OptionValueExceptionFactory v) { validatorBuilder.exceptionFactory(v); + validator = null; return this; } - OptionSpecBuilder validatorExceptionFactory(UnaryOperator> mutator) { - return validatorExceptionFactory(mutator.apply(validatorBuilder.exceptionFactory().orElse(null))); + OptionSpecBuilder validatorExceptionFactory(UnaryOperator> mapper) { + return validatorExceptionFactory(mapper.apply(validatorBuilder.exceptionFactory().orElse(null))); } OptionSpecBuilder converterExceptionFactory(OptionValueExceptionFactory v) { @@ -194,49 +244,68 @@ final class OptionSpecBuilder { return this; } - OptionSpecBuilder converterExceptionFactory(UnaryOperator> mutator) { - return converterExceptionFactory(mutator.apply(converterBuilder.exceptionFactory().orElse(null))); + OptionSpecBuilder converterExceptionFactory(UnaryOperator> mapper) { + return converterExceptionFactory(mapper.apply(converterBuilder.exceptionFactory().orElse(null))); } OptionSpecBuilder exceptionFormatString(String v) { return validatorExceptionFormatString(v).converterExceptionFormatString(v); } - OptionSpecBuilder exceptionFormatString(UnaryOperator mutator) { - return validatorExceptionFormatString(mutator).converterExceptionFormatString(mutator); + OptionSpecBuilder exceptionFormatString(UnaryOperator mapper) { + return validatorExceptionFormatString(mapper).converterExceptionFormatString(mapper); } OptionSpecBuilder exceptionFactory(OptionValueExceptionFactory v) { return validatorExceptionFactory(v).converterExceptionFactory(v); } - OptionSpecBuilder exceptionFactory(UnaryOperator> mutator) { - return validatorExceptionFactory(mutator).converterExceptionFactory(mutator); + OptionSpecBuilder exceptionFactory(UnaryOperator> mapper) { + return validatorExceptionFactory(mapper).converterExceptionFactory(mapper); } - OptionSpecBuilder converter(ValueConverter v) { + OptionSpecBuilder converter(ValueConverter v) { converterBuilder.converter(v); return this; } - OptionSpecBuilder converter(Function v) { + OptionSpecBuilder converter(OptionSpecBuilder other, ValueConverter v) { + converterBuilder = other.finalizeConverterBuilder().map(v); + return this; + } + + OptionSpecBuilder interimConverter(OptionSpecBuilder other) { + converterBuilder = converterBuilder.map(other.finalizeConverterBuilder()); + return this; + } + + OptionSpecBuilder converter(ValueConverterFunction v) { return converter(ValueConverter.create(v, valueType)); } OptionSpecBuilder validator(Predicate v) { validatorBuilder.predicate(v::test); + validator = null; return this; } @SuppressWarnings("overloads") OptionSpecBuilder validator(Consumer v) { validatorBuilder.consumer(v::accept); + validator = null; return this; } @SuppressWarnings("overloads") - OptionSpecBuilder validator(UnaryOperator> mutator) { - validatorBuilder = mutator.apply(validatorBuilder); + OptionSpecBuilder validator(UnaryOperator> mapper) { + validatorBuilder = mapper.apply(validatorBuilder); + validator = null; + return this; + } + + OptionSpecBuilder validator(Validator v) { + validatorBuilder.predicate(null).consumer(null); + validator = Objects.requireNonNull(v); return this; } @@ -247,6 +316,7 @@ final class OptionSpecBuilder { OptionSpecBuilder withoutValidator() { validatorBuilder.predicate(null).consumer(null); + validator = null; return this; } @@ -279,8 +349,8 @@ final class OptionSpecBuilder { return this; } - OptionSpecBuilder scope(UnaryOperator> mutator) { - return scope(mutator.apply(scope().orElseGet(Set::of))); + OptionSpecBuilder scope(UnaryOperator> mapper) { + return scope(mapper.apply(scope().orElseGet(Set::of))); } OptionSpecBuilder inScope(OptionScope... v) { @@ -400,10 +470,12 @@ final class OptionSpecBuilder { } private Optional defaultValuePattern() { - return converterBuilder.converter().map(_ -> { + if (converterBuilder.hasConverter()) { final var tokens = name.split("-"); - return tokens[tokens.length - 1]; - }); + return Optional.of(tokens[tokens.length - 1]); + } else { + return Optional.empty(); + } } private List names() { @@ -413,25 +485,21 @@ final class OptionSpecBuilder { ).flatMap(Collection::stream).map(OptionName::new).distinct().toList(); } - private Optional> createConverter() { - if (converterBuilder.converter().isPresent()) { - final var newBuilder = converterBuilder.copy(); - createValidator().ifPresent(newBuilder::validator); - return Optional.of(newBuilder.create()); + private Optional> createConverter() { + if (converterBuilder.hasConverter()) { + return Optional.of(finalizeConverterBuilder().create()); } else { return Optional.empty(); } } - private Optional> createValidator() { - if (validatorBuilder.hasValidatingMethod()) { - return Optional.of(validatorBuilder.create()); - } else { - return Optional.empty(); - } + private OptionValueConverter.Builder finalizeConverterBuilder() { + final var newBuilder = converterBuilder.copy(); + createValidator().ifPresent(newBuilder::validator); + return newBuilder; } - private OptionValueConverter createArrayConverter() { + private OptionValueConverter createArrayConverter() { final var newBuilder = converterBuilder.copy(); newBuilder.tokenizer(Optional.ofNullable(arrayTokenizer).orElse(str -> { return new String[] { str }; @@ -440,7 +508,7 @@ final class OptionSpecBuilder { return newBuilder.createArray(); } - private String arryValuePattern() { + private String arrayValuePattern() { final var elementValuePattern = OptionSpecBuilder.this.valuePattern().orElseThrow(); if (arrayValuePatternSeparator == null) { return elementValuePattern; @@ -468,6 +536,7 @@ final class OptionSpecBuilder { private String valuePattern; private OptionValueConverter.Builder converterBuilder = OptionValueConverter.build(); private Validator.Builder validatorBuilder = Validator.build(); + private Validator validator; private T[] arrayDefaultValue; private String arrayValuePatternSeparator; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecMapperOptionScope.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecMapperOptionScope.java index 7b517f768bf..42ed704ec6e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecMapperOptionScope.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecMapperOptionScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package jdk.jpackage.internal.cli; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.SequencedMap; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.IdentityWrapper; import jdk.jpackage.internal.util.SetBuilder; /** @@ -42,9 +48,9 @@ import jdk.jpackage.internal.util.SetBuilder; * varies depending on the current OS. * * @param the type of option value - * @param the type of context + * @param the type of context */ -interface OptionSpecMapperOptionScope extends OptionScope { +sealed interface OptionSpecMapperOptionScope extends OptionScope { OptionSpec createOptionSpec(U context, boolean createArray); @@ -52,7 +58,7 @@ interface OptionSpecMapperOptionScope extends OptionScope { @SuppressWarnings("unchecked") static OptionSpec mapOptionSpec(OptionSpec optionSpec, U context) { - return optionSpec.scope().stream() + var mappedOptionSpec = optionSpec.scope().stream() .filter(OptionSpecMapperOptionScope.class::isInstance) .map(OptionSpecMapperOptionScope.class::cast) .filter(scope -> { @@ -62,6 +68,25 @@ interface OptionSpecMapperOptionScope extends OptionScope { return ((OptionSpecMapperOptionScope)scope).createOptionSpec( context, optionSpec.arrayValueConverter().isPresent()); }).orElse(optionSpec); + + Optional valueType = optionSpec.converter().map(OptionValueConverter::valueType); + Optional mappedValueType = mappedOptionSpec.converter().map(OptionValueConverter::valueType); + + while (!mappedValueType.equals(valueType)) { + // Source and mapped option specs have different option value types. + if (Stream.of(valueType, mappedValueType).anyMatch(Optional::isEmpty) && + Stream.of(valueType, mappedValueType) + .filter(Optional::isPresent).map(Optional::get) + .anyMatch(Predicate.isEqual(Boolean.class))) { + // One option spec doesn't have a converter and another has a converter of type `Boolean`. + // They are compatible, let it pass. + break; + } + + throw new IllegalStateException(String.format("Bad option spec mapping from %s to %s", valueType, mappedValueType)); + } + + return mappedOptionSpec; } static Consumer> createOptionSpecBuilderMutator( @@ -94,23 +119,23 @@ interface OptionSpecMapperOptionScope extends OptionScope { var contextOptionScope = scope.stream() .filter(AccumulatingContextOptionScope.class::isInstance) - .map(AccumulatingContextOptionScope.class::cast) + .map(v -> { + @SuppressWarnings("unchecked") + var tv = (AccumulatingContextOptionScope)v; + return tv; + }) .filter(s -> { return s.contextType().equals(contextType); }) .findFirst(); + contextOptionScope.ifPresent(v -> { - @SuppressWarnings("unchecked") - var mutators = (AccumulatingContextOptionScope)v; - mutators.addMutator(optionSpecBuilderMutator); - if (optionSpecBuilder != mutators.optionSpecBuilder) { - throw new IllegalArgumentException(); - } + v.addMutator(optionSpecBuilder, optionSpecBuilderMutator); }); if (contextOptionScope.isEmpty()) { - var mutators = new AccumulatingContextOptionScope(optionSpecBuilder, contextType); - mutators.addMutator(optionSpecBuilderMutator); + var mutators = new AccumulatingContextOptionScope(contextType); + mutators.addMutator(optionSpecBuilder, optionSpecBuilderMutator); scope = SetBuilder.build().add(scope).add(mutators).create(); } @@ -119,23 +144,24 @@ interface OptionSpecMapperOptionScope extends OptionScope { private static final class AccumulatingContextOptionScope implements OptionSpecMapperOptionScope { - AccumulatingContextOptionScope(OptionSpecBuilder optionSpecBuilder, Class contextType) { - this.optionSpecBuilder = Objects.requireNonNull(optionSpecBuilder); + AccumulatingContextOptionScope(Class contextType) { this.contextType = Objects.requireNonNull(contextType); } @SuppressWarnings("unchecked") @Override public OptionSpec createOptionSpec(U context, boolean createArray) { - var copy = optionSpecBuilder.copy(); - for (var mutator : optionSpecBuilderMutators) { - mutator.accept(copy, context); + var it = builders.values().iterator(); + + var builder = it.next().initBuilder(context, Optional.empty()); + while (it.hasNext()) { + builder = it.next().initBuilder(context, Optional.of(builder)); } if (createArray) { - return (OptionSpec)copy.createArrayOptionSpec(); + return (OptionSpec)builder.createArrayOptionSpec(); } else { - return copy.createOptionSpec(); + return (OptionSpec)builder.createOptionSpec(); } } @@ -144,14 +170,43 @@ interface OptionSpecMapperOptionScope extends OptionScope { return contextType; } - void addMutator(BiConsumer, U> mutator) { - optionSpecBuilderMutators.add(mutator); + void addMutator(OptionSpecBuilder builder, BiConsumer, U> mutator) { + @SuppressWarnings("unchecked") + var builderWithMutators = ((OptionSpecBuilderWithMutators)builders.computeIfAbsent(new IdentityWrapper<>(builder), _ -> { + return new OptionSpecBuilderWithMutators(builder); + })); + + builderWithMutators.addMutator(mutator); } - private final OptionSpecBuilder optionSpecBuilder; private final Class contextType; - private final List, U>> optionSpecBuilderMutators = new ArrayList<>(); + private final SequencedMap>, OptionSpecBuilderWithMutators> builders = new LinkedHashMap<>(); } + private static final class OptionSpecBuilderWithMutators { + + OptionSpecBuilderWithMutators(OptionSpecBuilder builder) { + this.builder = Objects.requireNonNull(builder); + } + + OptionSpecBuilder initBuilder(U context, Optional> other) { + Objects.requireNonNull(context); + Objects.requireNonNull(other); + + var copy = builder.copy(); + other.ifPresent(copy::interimConverter); + for (var mutator : mutators) { + mutator.accept(copy, context); + } + return copy; + } + + void addMutator(BiConsumer, U> mutator) { + mutators.add(Objects.requireNonNull(mutator)); + } + + private final OptionSpecBuilder builder; + private final List, U>> mutators = new ArrayList<>(); + } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionValueConverter.java index 8544853d584..7e249ca1508 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,28 +35,35 @@ import jdk.jpackage.internal.cli.Validator.ParsedValue; import jdk.jpackage.internal.util.Result; /** - * Defines creating an option value of type {@link T} from a string. + * Defines creating an option value of type {@link U} from value of type {@link T}. * - * @param option value type + * @param input option value type + * @param output option value type */ -interface OptionValueConverter { +interface OptionValueConverter { /** - * Converts the given string value corresponding to the given option name into a - * Java type. + * Converts the given value of type {@link T} corresponding to the given option name + * and option string value to an object of type {@link U}. * * @param optionName the option name - * @param optionValue the string value of the option to convert + * @param optionValue the string value of the option + * @param value the value of the option to convert * @return the conversion result + * @throws ConverterException if internal converter error occurs */ - Result convert(OptionName optionName, StringToken optionValue); + Result convert(OptionName optionName, StringToken optionValue, T value) throws ConverterException; /** * Gives the class of the type of values this converter converts to. * * @return the target class for conversion */ - Class valueType(); + Class valueType(); + + static Result convertString(OptionValueConverter converter, OptionName optionName, StringToken optionValue) { + return converter.convert(optionName, optionValue, optionValue.value()); + } /** * Thrown to indicate an error in the normal execution of the converter. @@ -74,54 +81,78 @@ interface OptionValueConverter { return new Builder<>(); } + static final class Builder { private Builder() { + this(new OneStepBackend<>(new StepBuilder<>(true))); + } + + private Builder(Backend backend) { + this.backend = Objects.requireNonNull(backend); } private Builder(Builder other) { - converter = other.converter; - validator = other.validator; + backend = other.backend.copy(); tokenizer = other.tokenizer; - formatString = other.formatString; - exceptionFactory = other.exceptionFactory; } Builder copy() { return new Builder<>(this); } - OptionValueConverter create() { - return new DefaultOptionValueConverter<>( - converter, - formatString().orElseGet(() -> { - if (exceptionFactory == null) { - return ""; - } else { - return null; - } - }), - exceptionFactory().orElseGet(() -> { - if (formatString == null) { - return OptionValueExceptionFactory.unreachable(); - } else { - return null; - } - }), - validator()); + Builder map(ValueConverter converter) { + Objects.requireNonNull(converter); + return new Builder<>(new TwoStepBackend<>( + backend, + new StepBuilder(false).converter(converter))).tokenizer(tokenizer); + } + + Builder map(Builder other) { + Objects.requireNonNull(other); + switch (backend) { + case OneStepBackend _ -> { + throw new UnsupportedOperationException(); + } + case TwoStepBackend b -> { + var fromInterimValueType = other.backend.valueType().orElseThrow(); + var toInterimValueType = b.interimValueType(); + if (fromInterimValueType.equals(toInterimValueType)) { + @SuppressWarnings("unchecked") + var twoStepBackend = (TwoStepBackend)b; + return new Builder<>(new TwoStepBackend<>( + other.backend, + twoStepBackend.otherConvBuilder())).tokenizer(tokenizer); + } else { + throw new IllegalArgumentException(String.format( + "Expected (%s); actual (%s)", toInterimValueType, fromInterimValueType)); + } + } + } + } + + OptionValueConverter create() { + return backend.create(); } OptionArrayValueConverter createArray() { return new DefaultOptionArrayValueConverter<>(create(), tokenizer); } - Builder converter(ValueConverter v) { - converter = v; + Builder converter(ValueConverter v) { + switch (backend) { + case OneStepBackend b -> { + b.stringConvBuilder().converter(v); + } + case TwoStepBackend _ -> { + throw new UnsupportedOperationException(); + } + } return this; } Builder validator(Validator v) { - validator = v; + backend.validator(v); return this; } @@ -131,12 +162,12 @@ interface OptionValueConverter { } Builder formatString(String v) { - formatString = v; + backend.formatString(v); return this; } Builder exceptionFactory(OptionValueExceptionFactory v) { - exceptionFactory = v; + backend.exceptionFactory(v); return this; } @@ -145,12 +176,30 @@ interface OptionValueConverter { return this; } - Optional> converter() { - return Optional.ofNullable(converter); + boolean hasConverter() { + switch (backend) { + case OneStepBackend b -> { + return b.stringConvBuilder().converter().isPresent(); + } + case TwoStepBackend _ -> { + return true; + } + } } Optional> validator() { - return Optional.ofNullable(validator); + return backend.validator(); + } + + Optional> converter() { + switch (backend) { + case OneStepBackend b -> { + return b.stringConvBuilder().converter(); + } + case TwoStepBackend _ -> { + throw new UnsupportedOperationException(); + } + } } Optional> tokenizer() { @@ -158,68 +207,15 @@ interface OptionValueConverter { } Optional formatString() { - return Optional.ofNullable(formatString); + return backend.formatString(); } Optional> exceptionFactory() { - return Optional.ofNullable(exceptionFactory); + return backend.exceptionFactory(); } - private record DefaultOptionValueConverter(ValueConverter converter, String formatString, - OptionValueExceptionFactory exceptionFactory, - Optional> validator) implements OptionValueConverter { - - DefaultOptionValueConverter { - Objects.requireNonNull(converter); - Objects.requireNonNull(formatString); - Objects.requireNonNull(exceptionFactory); - Objects.requireNonNull(validator); - } - - @Override - public Result convert(OptionName optionName, StringToken optionValue) { - Objects.requireNonNull(optionName); - - final T convertedValue; - try { - convertedValue = converter.convert(optionValue.value()); - } catch (Exception ex) { - return handleException(optionName, optionValue, ex); - } - - final List validationExceptions = validator.map(val -> { - try { - return val.validate(optionName, ParsedValue.create(convertedValue, optionValue)); - } catch (Validator.ValidatorException ex) { - // All unexpected exceptions that the converter yields should be tunneled via ConverterException. - throw new ConverterException(ex.getCause()); - } - }).orElseGet(List::of); - - if (validationExceptions.isEmpty()) { - return Result.ofValue(convertedValue); - } else { - return Result.ofErrors(validationExceptions); - } - } - - @Override - public Class valueType() { - return converter.valueType(); - } - - private Result handleException(OptionName optionName, StringToken optionValue, Exception ex) { - if (ex instanceof IllegalArgumentException) { - return Result.ofError(exceptionFactory.create(optionName, optionValue, formatString, Optional.of(ex))); - } else { - throw new ConverterException(ex); - } - } - } - - - private record DefaultOptionArrayValueConverter(OptionValueConverter elementConverter, + private record DefaultOptionArrayValueConverter(OptionValueConverter elementConverter, Function tokenizer) implements OptionArrayValueConverter { DefaultOptionArrayValueConverter { @@ -229,14 +225,18 @@ interface OptionValueConverter { @SuppressWarnings("unchecked") @Override - public Result convert(OptionName optionName, StringToken optionValue) { + public Result convert(OptionName optionName, StringToken optionValue, String value) { + + if (!value.equals(optionValue.value())) { + throw new IllegalArgumentException(); + } final List exceptions = new ArrayList<>(); final List convertedValues = new ArrayList<>(); final var tokens = tokenize(optionValue.value()); for (var token : tokens) { - final var result = elementConverter.convert(optionName, StringToken.of(optionValue.value(), token)); + final var result = elementConverter.convert(optionName, StringToken.of(optionValue.value(), token), token); exceptions.addAll(result.errors()); if (exceptions.isEmpty()) { result.value().ifPresent(convertedValues::add); @@ -264,10 +264,311 @@ interface OptionValueConverter { } } - private ValueConverter converter; - private Validator validator; + + private record TwoStepOptionValueConverter(OptionValueConverter stringConverter, + OptionValueConverter converter) implements OptionValueConverter { + + TwoStepOptionValueConverter { + Objects.requireNonNull(stringConverter); + Objects.requireNonNull(converter); + } + + @Override + public Result convert(OptionName optionName, StringToken optionValue, String value) { + final var interimResult = stringConverter.convert(optionName, optionValue, value); + return interimResult.flatMap(interimValue -> { + return converter.convert(optionName, optionValue, interimValue); + }); + } + + @Override + public Class valueType() { + return converter.valueType(); + } + } + + + private sealed interface Backend { + + OptionValueConverter create(); + + Backend copy(); + + void validator(Validator v); + + void formatString(String v); + + void exceptionFactory(OptionValueExceptionFactory v); + + Optional> valueType(); + + Optional> validator(); + + Optional formatString(); + + Optional> exceptionFactory(); + } + + + private record OneStepBackend(StepBuilder stringConvBuilder) implements Backend { + + OneStepBackend { + Objects.requireNonNull(stringConvBuilder); + } + + @Override + public Backend copy() { + return new OneStepBackend<>(stringConvBuilder.copy()); + } + + @Override + public OptionValueConverter create() { + return stringConvBuilder.create(); + } + + @Override + public void validator(Validator v) { + stringConvBuilder.validator(v); + } + + @Override + public void formatString(String v) { + stringConvBuilder.formatString(v); + } + + @Override + public void exceptionFactory(OptionValueExceptionFactory v) { + stringConvBuilder.exceptionFactory(v); + } + + @Override + public Optional> valueType() { + return stringConvBuilder.converter().map(ValueConverter::valueType); + } + + @Override + public Optional> validator() { + return stringConvBuilder.validator(); + } + + @Override + public Optional formatString() { + return stringConvBuilder.formatString(); + } + + @Override + public Optional> exceptionFactory() { + return stringConvBuilder.exceptionFactory(); + } + } + + + private record TwoStepBackend(Backend stringConvBuilder, StepBuilder otherConvBuilder) implements Backend { + + TwoStepBackend { + Objects.requireNonNull(stringConvBuilder); + Objects.requireNonNull(otherConvBuilder); + } + + Class interimValueType() { + return stringConvBuilder.valueType().orElseThrow(); + } + + @Override + public Backend copy() { + return new TwoStepBackend<>(stringConvBuilder.copy(), otherConvBuilder.copy()); + } + + @Override + public OptionValueConverter create() { + return new TwoStepOptionValueConverter<>(stringConvBuilder.create(), otherConvBuilder.create()); + } + + @Override + public void validator(Validator v) { + otherConvBuilder.validator(v); + } + + @Override + public void formatString(String v) { + otherConvBuilder.formatString(v); + } + + @Override + public void exceptionFactory(OptionValueExceptionFactory v) { + otherConvBuilder.exceptionFactory(v); + } + + @Override + public Optional> valueType() { + return otherConvBuilder.converter().map(ValueConverter::valueType); + } + + @Override + public Optional> validator() { + return otherConvBuilder.validator(); + } + + @Override + public Optional formatString() { + return otherConvBuilder.formatString(); + } + + @Override + public Optional> exceptionFactory() { + return otherConvBuilder.exceptionFactory(); + } + } + + + private static final class StepBuilder { + + private StepBuilder(boolean starter) { + this.starter = starter; + } + + private StepBuilder(StepBuilder other) { + starter = other.starter; + converter = other.converter; + validator = other.validator; + formatString = other.formatString; + exceptionFactory = other.exceptionFactory; + } + + StepBuilder copy() { + return new StepBuilder<>(this); + } + + OptionValueConverter create() { + return new DefaultOptionValueConverter<>( + converter, + formatString().orElseGet(() -> { + if (exceptionFactory == null) { + return ""; + } else { + return null; + } + }), + exceptionFactory().orElseGet(() -> { + if (formatString == null) { + return OptionValueExceptionFactory.unreachable(); + } else { + return null; + } + }), + validator(), + starter); + } + + StepBuilder converter(ValueConverter v) { + converter = v; + return this; + } + + StepBuilder validator(Validator v) { + validator = v; + return this; + } + + StepBuilder formatString(String v) { + formatString = v; + return this; + } + + StepBuilder exceptionFactory(OptionValueExceptionFactory v) { + exceptionFactory = v; + return this; + } + + Optional> converter() { + return Optional.ofNullable(converter); + } + + Optional> validator() { + return Optional.ofNullable(validator); + } + + Optional formatString() { + return Optional.ofNullable(formatString); + } + + Optional> exceptionFactory() { + return Optional.ofNullable(exceptionFactory); + } + + + private record DefaultOptionValueConverter( + ValueConverter converter, + String formatString, + OptionValueExceptionFactory exceptionFactory, + Optional> validator, + boolean starter) implements OptionValueConverter { + + DefaultOptionValueConverter { + Objects.requireNonNull(converter); + Objects.requireNonNull(formatString); + Objects.requireNonNull(exceptionFactory); + Objects.requireNonNull(validator); + } + + @Override + public Result convert(OptionName optionName, StringToken optionValue, T value) { + Objects.requireNonNull(optionName); + Objects.requireNonNull(optionValue); + Objects.requireNonNull(value); + + if (starter && !value.equals(optionValue.value())) { + throw new IllegalArgumentException(); + } + + final U convertedValue; + try { + convertedValue = converter.convert(value); + } catch (Exception ex) { + return handleException(optionName, optionValue, ex); + } + + final List validationExceptions = validator.map(val -> { + try { + return val.validate(optionName, ParsedValue.create(convertedValue, optionValue)); + } catch (Validator.ValidatorException ex) { + // All unexpected exceptions that the converter yields should be tunneled via ConverterException. + throw new ConverterException(ex.getCause()); + } + }).orElseGet(List::of); + + if (validationExceptions.isEmpty()) { + return Result.ofValue(convertedValue); + } else { + return Result.ofErrors(validationExceptions); + } + } + + @Override + public Class valueType() { + return converter.valueType(); + } + + private Result handleException(OptionName optionName, StringToken optionValue, Exception ex) { + if (ex instanceof IllegalArgumentException) { + return Result.ofError(exceptionFactory.create(optionName, optionValue, formatString, Optional.of(ex))); + } else { + throw new ConverterException(ex); + } + } + } + + + private final boolean starter; + private ValueConverter converter; + private Validator validator; + private String formatString; + private OptionValueExceptionFactory exceptionFactory; + } + + + private final Backend backend; private Function tokenizer; - private String formatString; - private OptionValueExceptionFactory exceptionFactory; } } + diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java index 67e87d55d8b..6c32a3d1569 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +56,7 @@ import jdk.jpackage.internal.model.BundlingEnvironment; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.JPackageException; -import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.BundleType; /** * Analyzes jpackage command line structure. @@ -250,7 +250,7 @@ final class OptionsAnalyzer { return error("ERR_NoInstallerEntryPoint", mapFormatArguments(optionSpec)); } else { return error("ERR_InvalidTypeOption", mapFormatArguments( - optionSpec, bundlingOperation.packageTypeValue())); + optionSpec, bundlingOperation.bundleTypeValue())); } } @@ -267,30 +267,30 @@ final class OptionsAnalyzer { final var typeOption = TYPE.getOption(); return cmdline.find(typeOption).map(obj -> { - if (obj instanceof PackageType packageType) { - return packageType; + if (obj instanceof BundleType bundleType) { + return bundleType; } else { - return typeOption.spec() - .converter().orElseThrow() - .convert(typeOption.spec().name(), StringToken.of(((String[])obj)[0])) + var spec = new StandardOptionContext(os).mapOptionSpec(typeOption.spec()); + return spec + .convert(spec.name(), StringToken.of(((String[])obj)[0])) .orElseThrow(); } - }).map(packageType -> { - // Find standard bundling operations producing the given package type. + }).map(bundleType -> { + // Find standard bundling operations producing the given bundle type. var bundlingOperations = Stream.of(StandardBundlingOperation.values()).filter(op -> { - return op.packageType().equals(packageType); + return op.bundleType().equals(bundleType); }).toList(); if (bundlingOperations.isEmpty()) { // jpackage internal error: none of the standard bundling operations produce - // bundles of the `packageType`. + // bundles of the `bundleType`. throw new AssertionError(String.format( "None of the standard bundling operations produce bundles of type [%s]", - packageType)); + bundleType)); } else if (bundlingOperations.size() == 1) { return bundlingOperations.getFirst(); } else { - // Multiple standard bundling operations produce the `packageType` package type. + // Multiple standard bundling operations produce the `bundleType` bundle type. // Filter those that belong to the current OS bundlingOperations = bundlingOperations.stream().filter(op -> { return op.os().equals(OperatingSystem.current()); @@ -298,10 +298,10 @@ final class OptionsAnalyzer { if (bundlingOperations.isEmpty()) { // jpackage internal error: none of the standard bundling operations produce - // bundles of the `packageType` on the current OS. + // bundles of the `bundleType` on the current OS. throw new AssertionError(String.format( "None of the standard bundling operations produce bundles of type [%s] on %s", - packageType, OperatingSystem.current())); + bundleType, OperatingSystem.current())); } else if (bundlingOperations.size() == 1) { return bundlingOperations.getFirst(); } else if (StandardBundlingOperation.MACOS_APP_IMAGE.containsAll(bundlingOperations)) { @@ -316,7 +316,7 @@ final class OptionsAnalyzer { } } }).orElseGet(() -> { - // No package type specified, use the default bundling operation in the given environment. + // No bundle type specified, use the default bundling operation in the given environment. return env.defaultOperation().map(descriptor -> { return Stream.of(StandardBundlingOperation.values()).filter(op -> { return descriptor.equals(op.descriptor()); 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 54003b714a2..3c0eab77f8a 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 static java.util.stream.Collectors.counting; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toMap; import static jdk.jpackage.internal.cli.Option.fromOptionSpecPredicate; +import static jdk.jpackage.internal.cli.OptionValueConverter.convertString; import static jdk.jpackage.internal.cli.StandardOption.ADDITIONAL_LAUNCHERS; import static jdk.jpackage.internal.cli.StandardOption.platformOption; @@ -380,8 +381,8 @@ final class OptionsProcessor { } @Override - public Result convert(OptionName optionName, StringToken optionValue) { - return converter.convert(optionName, optionValue).flatMap(arr -> { + public Result convert(OptionName optionName, StringToken optionValue, String value) { + return convertString(converter, optionName, optionValue).flatMap(arr -> { return Stream.of(arr).map(mapper).reduce(Result.>ofValue(new ArrayList<>()), (result, o) -> { if (Result.allHaveValues(result, o)) { return result.map(v -> { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java index 330a650e513..2538bbf4fb4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardAppImageFileOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -169,15 +169,6 @@ public final class StandardAppImageFileOption { .mutate(setPlatformScope(OperatingSystem.MACOS)) .toOptionValueBuilder().id(StandardOption.MAC_APP_STORE.id()).create(); - /** - * Is an application image is signed. macOS-only. - */ - public static final OptionValue MAC_SIGNED = booleanOption("signed") - .inScope(AppImageFileOptionScope.APP) - .mutate(setPlatformScope(OperatingSystem.MACOS)) - .toOptionValueBuilder().id(StandardOption.MAC_SIGN.id()).create(); - - public static final class InvalidOptionValueException extends RuntimeException { InvalidOptionValueException(String str, Throwable t) { @@ -239,7 +230,7 @@ public final class StandardAppImageFileOption { } return strValue.map(v -> { - return spec.converter().orElseThrow().convert(spec.name(), StringToken.of(v)).orElseThrow(); + return spec.convert(spec.name(), StringToken.of(v)).orElseThrow(); }).map(v -> { return Map.entry(option, v); }); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardBundlingOperation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardBundlingOperation.java index 45f9194db0b..f6fcd68a6d8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardBundlingOperation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardBundlingOperation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ */ package jdk.jpackage.internal.cli; -import static jdk.jpackage.internal.model.AppImagePackageType.APP_IMAGE; - import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -34,6 +32,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.AppImageBundleType; +import jdk.jpackage.internal.model.BundleType; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.StandardPackageType; @@ -44,16 +44,16 @@ import jdk.jpackage.internal.util.SetBuilder; * Standard jpackage operations. */ public enum StandardBundlingOperation implements BundlingOperationOptionScope { - CREATE_WIN_APP_IMAGE(APP_IMAGE, "^(?!(linux-|mac-|win-exe-|win-msi-))", OperatingSystem.WINDOWS), - CREATE_LINUX_APP_IMAGE(APP_IMAGE, "^(?!(win-|mac-|linux-rpm-|linux-deb-))", OperatingSystem.LINUX), - CREATE_MAC_APP_IMAGE(APP_IMAGE, "^(?!(linux-|win-|mac-dmg-|mac-pkg-))", OperatingSystem.MACOS), + CREATE_WIN_APP_IMAGE(AppImageBundleType.WIN_APP_IMAGE, "^(?!(linux-|mac-|win-exe-|win-msi-))", OperatingSystem.WINDOWS), + CREATE_LINUX_APP_IMAGE(AppImageBundleType.LINUX_APP_IMAGE, "^(?!(win-|mac-|linux-rpm-|linux-deb-))", OperatingSystem.LINUX), + CREATE_MAC_APP_IMAGE(AppImageBundleType.MAC_APP_IMAGE, "^(?!(linux-|win-|mac-dmg-|mac-pkg-))", OperatingSystem.MACOS), CREATE_WIN_EXE(StandardPackageType.WIN_EXE, "^(?!(linux-|mac-|win-msi-))", OperatingSystem.WINDOWS), CREATE_WIN_MSI(StandardPackageType.WIN_MSI, "^(?!(linux-|mac-|win-exe-))", OperatingSystem.WINDOWS), CREATE_LINUX_RPM(StandardPackageType.LINUX_RPM, "^(?!(win-|mac-|linux-deb-))", OperatingSystem.LINUX), CREATE_LINUX_DEB(StandardPackageType.LINUX_DEB, "^(?!(win-|mac-|linux-rpm-))", OperatingSystem.LINUX), CREATE_MAC_PKG(StandardPackageType.MAC_PKG, "^(?!(linux-|win-|mac-dmg-))", OperatingSystem.MACOS), CREATE_MAC_DMG(StandardPackageType.MAC_DMG, "^(?!(linux-|win-|mac-pkg-))", OperatingSystem.MACOS), - SIGN_MAC_APP_IMAGE(APP_IMAGE, OperatingSystem.MACOS, Verb.SIGN); + SIGN_MAC_APP_IMAGE(AppImageBundleType.MAC_APP_IMAGE, OperatingSystem.MACOS, Verb.SIGN); /** * Supported values of the {@link BundlingOperationDescriptor#verb()} property. @@ -78,19 +78,19 @@ public enum StandardBundlingOperation implements BundlingOperationOptionScope { private final String value; } - StandardBundlingOperation(PackageType packageType, String optionNameRegexp, OperatingSystem os, Verb descriptorVerb) { - this.packageType = Objects.requireNonNull(packageType); + StandardBundlingOperation(BundleType bundleType, String optionNameRegexp, OperatingSystem os, Verb descriptorVerb) { + this.bundleType = Objects.requireNonNull(bundleType); optionNamePredicate = Pattern.compile(optionNameRegexp).asPredicate(); this.os = Objects.requireNonNull(os); this.descriptorVerb = Objects.requireNonNull(descriptorVerb); } - StandardBundlingOperation(PackageType packageType, String optionNameRegexp, OperatingSystem os) { - this(packageType, optionNameRegexp, os, Verb.CREATE); + StandardBundlingOperation(BundleType bundleType, String optionNameRegexp, OperatingSystem os) { + this(bundleType, optionNameRegexp, os, Verb.CREATE); } - StandardBundlingOperation(PackageType packageType, OperatingSystem os, Verb descriptorVerb) { - this.packageType = Objects.requireNonNull(packageType); + StandardBundlingOperation(BundleType bundleType, OperatingSystem os, Verb descriptorVerb) { + this.bundleType = Objects.requireNonNull(bundleType); optionNamePredicate = v -> false; this.os = Objects.requireNonNull(os); this.descriptorVerb = Objects.requireNonNull(descriptorVerb); @@ -100,16 +100,20 @@ public enum StandardBundlingOperation implements BundlingOperationOptionScope { return os; } - public String packageTypeValue() { - if (packageType.equals(APP_IMAGE)) { + public String bundleTypeValue() { + if (bundleType instanceof AppImageBundleType) { return "app-image"; } else { - return ((StandardPackageType)packageType).suffix().substring(1); + return ((StandardPackageType)bundleType).suffix().substring(1); } } + public BundleType bundleType() { + return bundleType; + } + public PackageType packageType() { - return packageType; + return (PackageType)bundleType(); } /** @@ -122,7 +126,7 @@ public enum StandardBundlingOperation implements BundlingOperationOptionScope { @Override public BundlingOperationDescriptor descriptor() { - return new BundlingOperationDescriptor(os(), packageTypeValue(), descriptorVerb.value()); + return new BundlingOperationDescriptor(os(), bundleTypeValue(), descriptorVerb.value()); } public static Optional valueOf(BundlingOperationDescriptor descriptor) { @@ -199,6 +203,6 @@ public enum StandardBundlingOperation implements BundlingOperationOptionScope { private final Predicate optionNamePredicate; private final OperatingSystem os; - private final PackageType packageType; + private final BundleType bundleType; private final Verb descriptorVerb; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index 0fa0af296dc..fedb55116a3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -37,6 +37,7 @@ import static jdk.jpackage.internal.cli.StandardOptionValueExceptionFactory.ERRO import static jdk.jpackage.internal.cli.StandardOptionValueExceptionFactory.forMessageWithOptionValueAndName; import static jdk.jpackage.internal.cli.StandardValueConverter.addLauncherShortcutConv; import static jdk.jpackage.internal.cli.StandardValueConverter.booleanConv; +import static jdk.jpackage.internal.cli.StandardValueConverter.explodedPathConverter; import static jdk.jpackage.internal.cli.StandardValueConverter.identityConv; import static jdk.jpackage.internal.cli.StandardValueConverter.mainLauncherShortcutConv; import static jdk.jpackage.internal.cli.StandardValueConverter.pathConv; @@ -44,22 +45,27 @@ import static jdk.jpackage.internal.cli.StandardValueConverter.uuidConv; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.AppImageBundleType; +import jdk.jpackage.internal.model.BundleType; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; -import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.util.RootedPath; +import jdk.jpackage.internal.model.SelfContainedException; import jdk.jpackage.internal.util.SetBuilder; /** @@ -103,23 +109,26 @@ public final class StandardOption { public static final OptionValue VERBOSE = auxilaryOption("verbose").create(); - public static final OptionValue TYPE = option("type", PackageType.class).addAliases("t") + public static final OptionValue TYPE = option("type", BundleType.class).addAliases("t") .scope(StandardBundlingOperation.values()).inScope(NOT_BUILDING_APP_IMAGE) .converterExceptionFactory(ERROR_WITH_VALUE).converterExceptionFormatString("ERR_InvalidInstallerType") .converter(str -> { - Objects.requireNonNull(str); - return Stream.of(StandardBundlingOperation.values()).filter(bundlingOperation -> { - return bundlingOperation.packageTypeValue().equals(str); - }).map(StandardBundlingOperation::packageType).findFirst().orElseThrow(IllegalArgumentException::new); + return parseBundleType(str, OperatingSystem.current()); }) .description("help.option.type" + resourceKeySuffix(OperatingSystem.current())) .mutate(createOptionSpecBuilderMutator((b, context) -> { b.description("help.option.type" + resourceKeySuffix(context.os())); + b.converter(str -> { + return parseBundleType(str, context.os()); + }); })).create(); - public static final OptionValue INPUT = directoryOption("input").addAliases("i") + public static final OptionValue> INPUT = directoryOption("input").addAliases("i") .outOfScope(NOT_BUILDING_APP_IMAGE) - .create(); + .map(explodedPathOptionMapper(explodedPathConverter().create())) + .create(optionValueBuilder -> { + return optionValueBuilder.to(List::of).create(); + }); public static final OptionValue DEST = directoryOption("dest").addAliases("d") .valuePattern("destination path") @@ -190,16 +199,17 @@ public final class StandardOption { .inScope(LauncherProperty.VALUE) .createArray(toList()); - public static final OptionValue> APP_CONTENT = pathOption("app-content") + public static final OptionValue>> APP_CONTENT = existingPathOption("app-content") .tokenizer(",") .valuePattern("additional content") .outOfScope(NOT_BUILDING_APP_IMAGE) + .map(explodedPathOptionMapper(explodedPathConverter().withPathFileName().create())) .mutate(createOptionSpecBuilderMutator((b, context) -> { if (context.os() == OperatingSystem.MACOS) { b.description("help.option.app-content" + resourceKeySuffix(context.os())); } })) - .createArray(toList()); + .createArray(toExplodedPathList()); static final OptionValue FILE_ASSOCIATIONS_INTERNAL = fileOption("file-associations") .tokenizer(pathSeparator()) @@ -233,6 +243,12 @@ public final class StandardOption { .mutate(createOptionSpecBuilderMutator((b, context) -> { if (context.os() == OperatingSystem.MACOS) { b.description("help.option.app-image" + resourceKeySuffix(context.os())); + var directoryValidator = b.createValidator().orElseThrow(); + var macBundleValidator = b + .validatorExceptionFormatString("error.parameter-not-mac-bundle") + .validator(StandardValidator.IS_VALID_MAC_BUNDLE) + .createValidator().orElseThrow(); + b.validator(Validator.and(directoryValidator, macBundleValidator)); } })) .create(); @@ -315,10 +331,11 @@ public final class StandardOption { // MacOS-specific // - public static final OptionValue> MAC_DMG_CONTENT = pathOption("mac-dmg-content") + public static final OptionValue>> MAC_DMG_CONTENT = existingPathOption("mac-dmg-content") .valuePattern("additional content path") .tokenizer(",") - .createArray(toList()); + .map(explodedPathOptionMapper(explodedPathConverter().withPathFileName().create())) + .createArray(toExplodedPathList()); public static final OptionValue MAC_SIGN = booleanOption("mac-sign").scope(MAC_SIGNING).addAliases("s").create(); @@ -504,12 +521,57 @@ public final class StandardOption { static Consumer> directoryOptionMutator() { return builder -> { builder.mutate(pathOptionMutator()) + .mutate(createOptionSpecBuilderMutator((b, context) -> { + context.asFileSource().ifPresent(propertyFile -> { + b.validatorExceptionFactory(forMessageWithOptionValueAndName(propertyFile)); + b.validatorExceptionFormatString("error.properties-parameter-not-directory"); + }); + })) .validator(StandardValidator.IS_DIRECTORY) .validatorExceptionFactory(ERROR_WITH_VALUE_AND_OPTION_NAME) .validatorExceptionFormatString("error.parameter-not-directory"); }; } + static Consumer> existingPathOptionMutator() { + + return builder -> { + builder.mutate(pathOptionMutator()) + .validator(createExistingPathValidator(Validator.build().exceptionFactory(ERROR_WITH_VALUE_AND_OPTION_NAME), true)) + .mutate(createOptionSpecBuilderMutator((b, context) -> { + context.asFileSource().ifPresent(propertyFile -> { + var validatorBuilder = Validator.build(); + validatorBuilder.exceptionFactory(forMessageWithOptionValueAndName(propertyFile)); + b.validator(createExistingPathValidator(validatorBuilder, false)); + }); + })); + }; + } + + private static Validator createExistingPathValidator(Validator.Builder builder, boolean cmdline) { + + if (cmdline) { + builder.formatString("error.parameter-not-directory"); + } else { + builder.formatString("error.properties-parameter-not-directory"); + } + + var isDirectoryValidator = builder.predicate(StandardValidator.IS_DIRECTORY).create(); + + if (cmdline) { + builder.formatString("error.parameter-not-file"); + } else { + builder.formatString("error.properties-parameter-not-file"); + } + + var isFileValidator = builder.predicate(StandardValidator.IS_FILE_OR_SYMLINK).create(); + + @SuppressWarnings("unchecked") + var validator = (Validator)isDirectoryValidator.or(isFileValidator); + + return validator; + } + static Consumer> booleanOptionMutator() { return builder -> { builder.mutate(createOptionSpecBuilderMutator((b, context) -> { @@ -537,6 +599,30 @@ public final class StandardOption { }; } + static Function, OptionSpecBuilder> explodedPathOptionMapper(ValueConverter conv) { + Objects.requireNonNull(conv); + return builder -> { + return builder.map(conv) + .converterExceptionFactory(ERROR_WITH_VALUE_AND_OPTION_NAME) + .converterExceptionFormatString("error.path-parameter-ioexception") + // Add empty mutator to OptionSpecMapperOptionScope to make + // mapped option spec have `RootedPath[]` type. + // Otherwise, it will have `Path` type. + .mutate(createOptionSpecBuilderMutator((b, context) -> { + })); + }; + } + + private static Function, OptionValue>>> toExplodedPathList() { + return builder -> { + return builder.to((RootedPath[][] v) -> { + return Stream.of(v).map(arr -> { + return (Collection)List.of(arr); + }).toList(); + }).create(); + }; + } + private static OptionSpecBuilder option(String name, Class valueType) { return OptionSpecBuilder.create(valueType) .name(Objects.requireNonNull(name)) @@ -565,6 +651,10 @@ public final class StandardOption { return option(name, Path.class).mutate(pathOptionMutator()); } + private static OptionSpecBuilder existingPathOption(String name) { + return option(name, Path.class).mutate(existingPathOptionMutator()); + } + private static OptionSpecBuilder fileOption(String name) { return option(name, Path.class) .valuePattern("file path") @@ -615,8 +705,7 @@ public final class StandardOption { } private static OptionValue createAddLauncherOption(String name) { - OptionValueConverter propertyFileConverter = fileOption(name) - .create().getSpec().converter().orElseThrow(); + var propertyFileSpec = fileOption(name).create().getSpec(); return option(name, AdditionalLauncher.class) .valuePattern("=") @@ -648,7 +737,7 @@ public final class StandardOption { final Path propertyFile; try { - propertyFile = propertyFileConverter.convert(OptionName.of(name), + propertyFile = propertyFileSpec.convert(OptionName.of(name), StringToken.of(value, components[1])).orElseThrow(); } catch (JPackageException ex) { throw new AddLauncherInvalidPropertyFileException(I18N.format( @@ -659,6 +748,23 @@ public final class StandardOption { }).defaultArrayValue(new AdditionalLauncher[0]).createArray(); } + private static BundleType parseBundleType(String str, OperatingSystem appImageOS) { + Objects.requireNonNull(str); + Objects.requireNonNull(appImageOS); + + return Stream.of(StandardBundlingOperation.values()).filter(bundlingOperation -> { + return bundlingOperation.bundleTypeValue().equals(str); + }) + .filter(bundlingOperation -> { + // Skip app image bundle type if it is from another platform. + return !(bundlingOperation.bundleType() instanceof AppImageBundleType) + || (bundlingOperation.os() == appImageOS); + }) + .map(StandardBundlingOperation::bundleType) + .findFirst() + .orElseThrow(IllegalArgumentException::new); + } + private static String resourceKeySuffix(OperatingSystem os) { switch (os) { case LINUX -> { @@ -677,6 +783,7 @@ public final class StandardOption { } + @SelfContainedException static class AddLauncherIllegalArgumentException extends IllegalArgumentException { AddLauncherIllegalArgumentException(String message) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java index 0038740f9df..cfa97439592 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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.function.Consumer; import java.util.function.Predicate; import jdk.jpackage.internal.cli.Validator.ValidatingConsumerException; import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.MacBundle; final public class StandardValidator { @@ -138,6 +139,10 @@ final public class StandardValidator { return true; }; + public static Predicate IS_VALID_MAC_BUNDLE = path -> { + return MacBundle.fromPath(path).isPresent(); + }; + public static final class DirectoryListingIOException extends RuntimeException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java index 3a310166fa8..b1e1189654d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 @@ package jdk.jpackage.internal.cli; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.UUID; +import java.util.function.Function; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.ParseUtils; +import jdk.jpackage.internal.util.RootedPath; final class StandardValueConverter { @@ -37,33 +41,59 @@ final class StandardValueConverter { private StandardValueConverter() { } - static ValueConverter identityConv() { + static ValueConverter identityConv() { return IDENTITY_CONV; } - static ValueConverter pathConv() { + static ValueConverter pathConv() { return PATH_CONV; } - static ValueConverter uuidConv() { + static ValueConverter uuidConv() { return UUID_CONV; } - static ValueConverter booleanConv() { + static ValueConverter booleanConv() { return BOOLEAN_CONV; } - static ValueConverter mainLauncherShortcutConv() { + static ValueConverter mainLauncherShortcutConv() { return MAIN_LAUNCHER_SHORTCUT_CONV; } - static ValueConverter addLauncherShortcutConv() { + static ValueConverter addLauncherShortcutConv() { return ADD_LAUNCHER_SHORTCUT_CONV; } - private static final ValueConverter IDENTITY_CONV = ValueConverter.create(x -> x, String.class); + static ExplodedPathConverterBuilder explodedPathConverter() { + return new ExplodedPathConverterBuilder(); + } - private static final ValueConverter PATH_CONV = ValueConverter.create(str -> { + static final class ExplodedPathConverterBuilder { + private ExplodedPathConverterBuilder() { + } + + ValueConverter create() { + return ValueConverter.create(path -> { + return explodePath(path, withPathFileName); + }, RootedPath[].class); + } + + ExplodedPathConverterBuilder withPathFileName(boolean v) { + withPathFileName = v; + return this; + } + + ExplodedPathConverterBuilder withPathFileName() { + return withPathFileName(true); + } + + private boolean withPathFileName; + } + + private static final ValueConverter IDENTITY_CONV = ValueConverter.create(x -> x, String.class); + + private static final ValueConverter PATH_CONV = ValueConverter.create(str -> { try { return Path.of(str); } catch (InvalidPathException ex) { @@ -71,13 +101,33 @@ final class StandardValueConverter { } }, Path.class); - private static final ValueConverter UUID_CONV = ValueConverter.create(UUID::fromString, UUID.class); + private static final ValueConverter UUID_CONV = ValueConverter.create(UUID::fromString, UUID.class); - private static final ValueConverter BOOLEAN_CONV = ValueConverter.create(Boolean::valueOf, Boolean.class); + private static final ValueConverter BOOLEAN_CONV = ValueConverter.create(Boolean::valueOf, Boolean.class); - private static final ValueConverter MAIN_LAUNCHER_SHORTCUT_CONV = ValueConverter.create( + private static final ValueConverter MAIN_LAUNCHER_SHORTCUT_CONV = ValueConverter.create( ParseUtils::parseLauncherShortcutForMainLauncher, LauncherShortcut.class); - private static final ValueConverter ADD_LAUNCHER_SHORTCUT_CONV = ValueConverter.create( + private static final ValueConverter ADD_LAUNCHER_SHORTCUT_CONV = ValueConverter.create( ParseUtils::parseLauncherShortcutForAddLauncher, LauncherShortcut.class); + + private static RootedPath[] explodePath(Path path, boolean withPathFileName) throws Exception { + + Function mapper; + if (withPathFileName) { + mapper = RootedPath.toRootedPath(path.getParent()); + } else { + mapper = RootedPath.toRootedPath(path); + } + + RootedPath[] items; + try (var walk = Files.walk(path)) { + items = walk.map(mapper).toArray(RootedPath[]::new); + } catch (IOException ex) { + // IOException is not a converter error, it is a converting error, so map it into IAE. + throw new IllegalArgumentException(ex); + } + + return items; + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Utils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Utils.java index 0565a8f1235..a94de355284 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Utils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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.function.IntPredicate; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.BundlingEnvironment; +import jdk.jpackage.internal.model.SelfContainedException; final class Utils { @@ -98,6 +99,7 @@ final class Utils { }); } + @SelfContainedException static final class ParseException extends RuntimeException { ParseException(String msg) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java index 0ddf0e1984f..0701071b00f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Validator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,63 @@ */ package jdk.jpackage.internal.cli; -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.Predicate; +import java.util.stream.Stream; @FunctionalInterface interface Validator { - List validate(OptionName optionName, ParsedValue optionValue); + /** + * Validates the given option value. + * + * @param optionName the name of an option to validate + * @param optionValue the value of an option to validate + * @return the list of validation errors + * @throws ValidatorException if internal validator error occurs + */ + List validate(OptionName optionName, ParsedValue optionValue) throws ValidatorException; - default Validator andThen(Validator after) { - return reduce(this, after); + default Validator and(Validator after) { + Objects.requireNonNull(after); + var before = this; + return (optionName, optionValue) -> { + return Stream.concat( + before.validate(optionName, optionValue).stream(), + after.validate(optionName, optionValue).stream() + ).toList(); + }; + } + + default Validator or(Validator after) { + Objects.requireNonNull(after); + var before = this; + return (optionName, optionValue) -> { + var bErrors = before.validate(optionName, optionValue); + if (bErrors.isEmpty()) { + return List.of(); + } + + var aErrors = after.validate(optionName, optionValue); + if (aErrors.isEmpty()) { + return List.of(); + } + + return Stream.concat(bErrors.stream(), aErrors.stream()).toList(); + }; + } + + @SuppressWarnings("unchecked") + static Validator and(Validator first, Validator second) { + return (Validator)first.and(second); + } + + @SuppressWarnings("unchecked") + static Validator or(Validator first, Validator second) { + return (Validator)first.or(second); } /** @@ -251,15 +294,4 @@ interface Validator { } } } - - @SafeVarargs - private static Validator reduce(Validator... validators) { - @SuppressWarnings("varargs") - var theValidators = List.of(validators); - return (optionName, optionValue) -> { - return theValidators.stream().map(validator -> { - return validator.validate(optionName, optionValue); - }).flatMap(Collection::stream).map(Exception.class::cast).toList(); - }; - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java index ba52ca35f50..122b212d295 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,41 +25,30 @@ package jdk.jpackage.internal.cli; import java.util.Objects; -import java.util.function.Function; -interface ValueConverter { - - /** - * Converts the given string value into a Java type. - * - * @param value the string to convert - * @return the converted value - * @throws IllegalArgumentException if the given string value can not be - * converted to an object of type {@link T} - */ - T convert(String value) throws IllegalArgumentException; +interface ValueConverter extends ValueConverterFunction { /** * Gives the class of the type of values this converter converts to. * * @return the target class for conversion */ - Class valueType(); + Class valueType(); - static ValueConverter create(Function mapper, Class type) { - Objects.requireNonNull(mapper); + static ValueConverter create(ValueConverterFunction conv, Class type) { + Objects.requireNonNull(conv); Objects.requireNonNull(type); return new ValueConverter<>() { @Override - public T convert(String value) { + public U convert(T value) throws Exception { Objects.requireNonNull(value); - return Objects.requireNonNull(mapper.apply(value)); + return Objects.requireNonNull(conv.convert(value)); } @Override - public Class valueType() { + public Class valueType() { return type; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverterFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverterFunction.java new file mode 100644 index 00000000000..28702afff75 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverterFunction.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * 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.jpackage.internal.cli; + +@FunctionalInterface +interface ValueConverterFunction { + + /** + * Converts value of one type into another. + * + * @param value the value to convert + * @return the converted value + * @throws IllegalArgumentException if the given value can not be converted to + * an object of type {@link U} + * @throws Exception if internal converter error occurs + */ + U convert(T value) throws Exception, IllegalArgumentException; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageBundleType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageBundleType.java new file mode 100644 index 00000000000..c5d2f0d1569 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageBundleType.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * 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.jpackage.internal.model; + +import java.util.Objects; + +/** + * App image bundle type. + * + * @see StandardPackageType + */ +public enum AppImageBundleType implements BundleType { + + WIN_APP_IMAGE("bundle-type.win-app"), + LINUX_APP_IMAGE("bundle-type.linux-app"), + MAC_APP_IMAGE("bundle-type.mac-app"), + ; + + private AppImageBundleType(String key) { + this.key = Objects.requireNonNull(key); + } + + @Override + public String label() { + return I18N.getString(key); + } + + private final String key; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 5b20a0690d3..7860a04faac 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Stream; +import jdk.jpackage.internal.util.RootedPath; /** * A generic application for packaging. @@ -78,27 +80,25 @@ public non-sealed interface Application extends BundleSpec { String copyright(); /** - * Gets the source directory of this application if available or an empty - * {@link Optional} instance. + * Gets the source paths that should be copied into + * {@link ApplicationLayout#appDirectory()} directory of the image of this + * application. *

- * Source directory is a directory with the applications's classes and other + * Source paths are supposed to contain the applications's classes and other * resources. * - * @return the source directory of this application + * @return the source paths */ - Optional srcDir(); + Collection appDirSources(); /** - * Gets the input content directories of this application. - *

- * Contents of the content directories will be copied as-is into the dedicated - * location of the application image. + * Gets the source paths that should be copied into + * {@link ApplicationLayout#contentDirectory()} directory of the image of this + * application. * - * @see ApplicationLayout#contentDirectory - * - * @return the input content directories of this application + * @return the source paths */ - List contentDirs(); + Collection contentDirSources(); /** * Gets the unresolved app image layout of this application. @@ -244,8 +244,17 @@ public non-sealed interface Application extends BundleSpec { /** * Default implementation of {@link Application} interface. */ - record Stub(String name, String description, String version, String vendor, String copyright, Optional srcDir, - List contentDirs, AppImageLayout imageLayout, Optional runtimeBuilder, - List launchers, Map extraAppImageFileData) implements Application { + record Stub( + String name, + String description, + String version, + String vendor, + String copyright, + Collection appDirSources, + Collection contentDirSources, + AppImageLayout imageLayout, + Optional runtimeBuilder, + List launchers, + Map extraAppImageFileData) implements Application { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleType.java similarity index 77% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleType.java index 4e28bb05aef..009725f3e92 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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,20 +22,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.jpackage.internal.model; -/** - * App image packaging type. - * - * @see StandardPackageType - */ -public final class AppImagePackageType implements PackageType { - private AppImagePackageType() { - } +/** + * Generic bundle type. E.g.: application image, rpm, msi are all bundle types. + */ +public sealed interface BundleType permits PackageType, AppImageBundleType { /** - * Singleton + * Returns a user-facing label of this bundle type. + * @return a user-facing label of this bundle type. */ - public static final AppImagePackageType APP_IMAGE = new AppImagePackageType(); + String label(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExecutableAttributesWithCapturedOutput.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExecutableAttributesWithCapturedOutput.java new file mode 100644 index 00000000000..faed9d24d01 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExecutableAttributesWithCapturedOutput.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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.jpackage.internal.model; + +import java.util.List; +import java.util.Objects; +import jdk.jpackage.internal.util.CommandOutputControl.ExecutableAttributes; +import jdk.jpackage.internal.util.CommandOutputControl.Result; + +/** + * {@link ExecutableAttributes} augmented with printable command output. + */ +public record ExecutableAttributesWithCapturedOutput(ExecutableAttributes execAttrs, String printableOutput) + implements ExecutableAttributes { + + public ExecutableAttributesWithCapturedOutput { + Objects.requireNonNull(execAttrs); + Objects.requireNonNull(printableOutput); + } + + @Override + public List commandLine() { + return execAttrs.commandLine(); + } + + public static Result augmentResultWithOutput(Result result, String output) { + var execAttrs = new ExecutableAttributesWithCapturedOutput(result.execAttrs(), output); + return result.copyWithExecutableAttributes(execAttrs); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/JPackageException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/JPackageException.java index 9727f21d2d7..3d24d293f18 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/JPackageException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/JPackageException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.util.Objects; /** * Generic jpackage exception with non-null message. */ +@SelfContainedException public class JPackageException extends RuntimeException { public JPackageException(String msg) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java index d0a4fd010e6..e7273d27ba5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +27,8 @@ package jdk.jpackage.internal.model; /** - * Generic package type. E.g.: application image, rpm, msi are all package types. + * Native package type. E.g.: dmg, rpm, msi are all package types. * * @see jdk.jpackage.internal.model.Package */ -public interface PackageType {} +public non-sealed interface PackageType extends BundleType {} diff --git a/src/java.desktop/share/native/libjsound/Platform.c b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/SelfContainedException.java similarity index 66% rename from src/java.desktop/share/native/libjsound/Platform.c rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/SelfContainedException.java index ecb389c89b7..c7d1b3016ac 100644 --- a/src/java.desktop/share/native/libjsound/Platform.c +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/SelfContainedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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,21 +23,20 @@ * questions. */ +package jdk.jpackage.internal.model; -#include "Utilities.h" -// Platform.java includes -#include "com_sun_media_sound_Platform.h" +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; -/* - * Declare library specific JNI_Onload entry if static build +/** + * Annotation for exceptions with self-contained error messages that don't + * require an additional context, like exception class name or a stack trace. */ -DEF_STATIC_JNI_OnLoad - -/* - * Class: com_sun_media_sound_Platform - * Method: nIsBigEndian - * Signature: ()Z - */ -JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_Platform_nIsBigEndian(JNIEnv *env, jclass clss) { - return UTIL_IsBigEndianPlatform(); +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface SelfContainedException { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java index ccdeceb4a04..6fadc748ecc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,22 @@ */ package jdk.jpackage.internal.model; +import java.util.Objects; + /** * Standard native package types. */ public enum StandardPackageType implements PackageType { - WIN_MSI(".msi"), - WIN_EXE(".exe"), - LINUX_DEB(".deb"), - LINUX_RPM(".rpm"), - MAC_PKG(".pkg"), - MAC_DMG(".dmg"); + WIN_MSI("bundle-type.win-msi", ".msi"), + WIN_EXE("bundle-type.win-exe", ".exe"), + LINUX_DEB("bundle-type.linux-deb", ".deb"), + LINUX_RPM("bundle-type.linux-rpm", ".rpm"), + MAC_PKG("bundle-type.mac-pkg", ".pkg"), + MAC_DMG("bundle-type.mac-dmg", ".dmg"); - StandardPackageType(String suffix) { - this.suffix = suffix; + StandardPackageType(String key, String suffix) { + this.key = Objects.requireNonNull(key); + this.suffix = Objects.requireNonNull(suffix); } /** @@ -48,5 +51,11 @@ public enum StandardPackageType implements PackageType { return suffix; } + @Override + public String label() { + return I18N.getString(key); + } + + private final String key; private final String suffix; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index e97bee79e6e..6e5de3d9729 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -28,14 +28,14 @@ param.copyright.default=Copyright (C) {0,date,YYYY} param.vendor.default=Unknown bundle-type.win-app=Windows Application Image -bundle-type.win-exe=EXE Installer Package -bundle-type.win-msi=MSI Installer Package +bundle-type.win-exe=Windows EXE Installer +bundle-type.win-msi=Windows MSI Installer bundle-type.mac-app=Mac Application Image bundle-type.mac-dmg=Mac DMG Package bundle-type.mac-pkg=Mac PKG Package bundle-type.linux-app=Linux Application Image -bundle-type.linux-deb=DEB Bundle -bundle-type.linux-rpm=RPM Bundle +bundle-type.linux-deb=Linux DEB Package +bundle-type.linux-rpm=Linux RPM Package resource.post-app-image-script=script to run after application image is populated @@ -43,13 +43,23 @@ message.using-default-resource=Using default package resource {0} {1} (add {2} t message.no-default-resource=No default package resource {0} (add {1} to the resource-dir to customize). message.using-custom-resource-from-file=Using custom package resource {0} (loaded from file {1}). message.using-custom-resource=Using custom package resource {0} (loaded from {1}). -message.creating-app-bundle=Creating app package: {0} in {1} + +message.create-package=Building output package file... +message.create-app-image=Building output application image directory... +message.package-created=Succeeded in building output package file +message.app-image-created=Succeeded in building output application image directory + message.debug-working-directory=Kept working directory for debug: {0} -message.bundle-created=Succeeded in building {0} package + message.module-version=Using version "{0}" from module "{1}" as application version message.error-header=Error: {0} message.advice-header=Advice to fix: {0} +message.failed-command-output-header=Command output: + +error.command-failed-unexpected-output=Unexpected output from executing the command {0} +error.command-failed-unexpected-exit-code=Unexpected exit code {0} from executing the command {1} +error.command-failed-timed-out=Timed-out command {0} error.version-string-empty=Version may not be empty string error.version-string-zero-length-component=Version [{0}] contains a zero length component @@ -75,13 +85,16 @@ error.parameter-not-directory=The value "{0}" provided for parameter {1} is not error.parameter-not-empty-directory=The value "{0}" provided for parameter {1} is not an empty directory or non existent path error.parameter-not-url=The value "{0}" provided for parameter {1} is not a valid URL error.parameter-not-launcher-shortcut-dir=The value "{0}" provided for parameter {1} is not a valid shortcut startup directory +error.parameter-not-mac-bundle=The value "{0}" provided for parameter {1} is not a valid macOS bundle error.path-parameter-ioexception=I/O error accessing path value "{0}" of parameter {1} error.parameter-add-launcher-malformed=The value "{0}" provided for parameter {1} does not match the pattern = error.parameter-add-launcher-not-file=The value of path to a property file "{0}" provided for additional launcher "{1}" is not a valid file path error.properties-parameter-not-path=The value "{0}" provided for property "{1}" in "{2}" file is not a valid path error.properties-parameter-not-file=The value "{0}" provided for property "{1}" in "{2}" file is not a file +error.properties-parameter-not-directory=The value "{0}" provided for property "{1}" in "{2}" file is not a directory error.properties-parameter-not-launcher-shortcut-dir=The value "{0}" provided for property "{1}" in "{2}" file is not a valid shortcut startup directory +error.no-extensions-for-file-association=No extensions were specified for File Association number {0} error.no-content-types-for-file-association=No MIME types were specified for File Association number {0} error.no-content-types-for-file-association.advice=Specify MIME type for File Association number {0} error.too-many-content-types-for-file-association=More than one MIME types was specified for File Association number {0} @@ -96,6 +109,8 @@ error.tool-not-found.advice=Please install "{0}" error.tool-old-version=Can not find "{0}" {1} or newer error.tool-old-version.advice=Please install "{0}" {1} or newer +error.output-bundle-cannot-be-overwritten=Output package file "{0}" exists and can not be removed. + error.blocked.option=jlink option [{0}] is not permitted in --jlink-options error.no.name=Name not specified with --name and cannot infer one from app-image error.no.name.advice=Specify name with --name diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CommandOutputControl.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CommandOutputControl.java index e35439815b1..00fbdd71919 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CommandOutputControl.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CommandOutputControl.java @@ -796,6 +796,10 @@ public final class CommandOutputControl { public interface ExecutableAttributes { List commandLine(); + + default String printableCommandLine() { + return CommandLineFormat.DEFAULT.apply(commandLine()); + } } public sealed interface Executable { @@ -812,11 +816,6 @@ public final class CommandOutputControl { Objects.requireNonNull(pid); commandLine.forEach(Objects::requireNonNull); } - - @Override - public String toString() { - return CommandLineFormat.DEFAULT.apply(commandLine()); - } } public record ToolProviderAttributes(String name, List args) implements ExecutableAttributes { @@ -825,11 +824,6 @@ public final class CommandOutputControl { args.forEach(Objects::requireNonNull); } - @Override - public String toString() { - return CommandLineFormat.DEFAULT.apply(commandLine()); - } - @Override public List commandLine() { return Stream.concat(Stream.of(name), args.stream()).toList(); @@ -837,14 +831,9 @@ public final class CommandOutputControl { } public static ExecutableAttributes EMPTY_EXECUTABLE_ATTRIBUTES = new ExecutableAttributes() { - @Override - public String toString() { - return ""; - } - @Override public List commandLine() { - return List.of(); + return List.of(""); } }; @@ -869,6 +858,51 @@ public final class CommandOutputControl { Objects.requireNonNull(execAttrs); } + public static Builder build() { + return new Builder(); + } + + public static final class Builder { + + public Result create() { + return new Result( + exitCode, + Optional.ofNullable(content).map(List::copyOf).map(StringListContent::new).map(c -> { + return new CommandOutput>(Optional.of(c), c.size(), true); + }), + Optional.empty(), + Optional.ofNullable(execAttrs).orElse(EMPTY_EXECUTABLE_ATTRIBUTES)); + } + + public Builder exitCode(int v) { + exitCode = Optional.of(v); + return this; + } + + public Builder noExitCode() { + exitCode = Optional.empty(); + return this; + } + + public Builder execAttrs(ExecutableAttributes v) { + execAttrs = v; + return this; + } + + public Builder content(List v) { + content = v; + return this; + } + + public Builder content(String... v) { + return content(List.of(v)); + } + + private ExecutableAttributes execAttrs; + private List content; + private Optional exitCode = Optional.empty(); + } + public Result(int exitCode) { this(Optional.of(exitCode), Optional.empty(), Optional.empty(), EMPTY_EXECUTABLE_ATTRIBUTES); } @@ -1019,7 +1053,8 @@ public final class CommandOutputControl { } private UnexpectedResultException(Result value) { - this(value, String.format("Unexpected result from executing the command %s", value.execAttrs())); + this(value, String.format("Unexpected result from executing the command %s", + value.execAttrs().printableCommandLine())); } public Result getResult() { @@ -1034,11 +1069,21 @@ public final class CommandOutputControl { public static final class UnexpectedExitCodeException extends UnexpectedResultException { public UnexpectedExitCodeException(Result value, String message) { - super(value, message); + super(requireExitCode(value), message); } public UnexpectedExitCodeException(Result value) { - this(value, String.format("Unexpected exit code %d from executing the command %s", value.getExitCode(), value.execAttrs())); + this(value, String.format("Unexpected exit code %d from executing the command %s", + requireExitCode(value).getExitCode(), value.execAttrs().printableCommandLine())); + } + + private static Result requireExitCode(Result v) { + Objects.requireNonNull(v); + if (v.exitCode().isPresent()) { + return v; + } else { + throw new IllegalArgumentException(); + } } private static final long serialVersionUID = 1L; 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 2f7f2682a71..b143a54cb5c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +57,6 @@ public final class FileUtils { public static void copyRecursive(Path src, Path dest, CopyOption... options) throws IOException { - copyRecursive(src, dest, List.of(), options); - } - - public static void copyRecursive(Path src, Path dest, - final List excludes, CopyOption... options) - throws IOException { List copyActions = new ArrayList<>(); @@ -71,24 +65,18 @@ public final class FileUtils { @Override public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) { - if (isPathMatch(dir, excludes)) { - return FileVisitResult.SKIP_SUBTREE; - } else { - copyActions.add(new CopyAction(null, dest.resolve(src.relativize(dir)))); - return FileVisitResult.CONTINUE; - } + copyActions.add(new CopyAction(null, dest.resolve(src.relativize(dir)))); + return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) { - if (!isPathMatch(file, excludes)) { - copyActions.add(new CopyAction(file, dest.resolve(src.relativize(file)))); - } + copyActions.add(new CopyAction(file, dest.resolve(src.relativize(file)))); return FileVisitResult.CONTINUE; } }); - } else if (!isPathMatch(src, excludes)) { + } else { Optional.ofNullable(dest.getParent()).ifPresent(dstDir -> { copyActions.add(new CopyAction(null, dstDir)); }); @@ -113,10 +101,6 @@ public final class FileUtils { } } - private static boolean isPathMatch(Path what, List paths) { - return paths.stream().anyMatch(what::endsWith); - } - private static record CopyAction(Path src, Path dest) { void apply(CopyOption... options) throws IOException { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MacBundle.java similarity index 63% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MacBundle.java index 723614f9bd6..95629e7d4b5 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MacBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,54 +23,49 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.util; import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.model.AppImageLayout; /** * An abstraction of macOS Application bundle. * * @see https://en.wikipedia.org/wiki/Bundle_(macOS)#Application_bundles */ -record MacBundle(Path root) { +public record MacBundle(Path root) { - MacBundle { + public MacBundle { Objects.requireNonNull(root); } - boolean isValid() { + public boolean isValid() { return Files.isDirectory(contentsDir()) && Files.isDirectory(macOsDir()) && Files.isRegularFile(infoPlistFile()); } - boolean isSigned() { - return Files.isDirectory(contentsDir().resolve("_CodeSignature")); - } - - Path contentsDir() { + public Path contentsDir() { return root.resolve("Contents"); } - Path homeDir() { + public Path homeDir() { return contentsDir().resolve("Home"); } - Path macOsDir() { + public Path macOsDir() { return contentsDir().resolve("MacOS"); } - Path resourcesDir() { + public Path resourcesDir() { return contentsDir().resolve("Resources"); } - Path infoPlistFile() { + public Path infoPlistFile() { return contentsDir().resolve("Info.plist"); } - static Optional fromPath(Path path) { + public static Optional fromPath(Path path) { var bundle = new MacBundle(path); if (bundle.isValid()) { return Optional.of(bundle); @@ -78,20 +73,4 @@ record MacBundle(Path root) { return Optional.empty(); } } - - static Optional fromAppImageLayout(AppImageLayout layout) { - final var root = layout.rootDirectory(); - final var bundleSubdir = root.relativize(layout.runtimeDirectory()); - final var contentsDirname = Path.of("Contents"); - var bundleRoot = root; - for (int i = 0; i != bundleSubdir.getNameCount(); i++) { - var nameComponent = bundleSubdir.getName(i); - if (contentsDirname.equals(nameComponent)) { - return Optional.of(new MacBundle(bundleRoot)); - } else { - bundleRoot = bundleRoot.resolve(nameComponent); - } - } - return Optional.empty(); - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java new file mode 100644 index 00000000000..21d3b6b17b0 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * 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.jpackage.internal.util; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.CopyOption; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * A relative path (branch) rooted at the root. + */ +public sealed interface RootedPath { + + Path root(); + Path branch(); + + default Path fullPath() { + return root().resolve(branch()); + } + + public static Function toRootedPath(Path root) { + return path -> { + if (!path.startsWith(root)) { + throw new IllegalArgumentException(String.format("Expected path [%s] to start with [%s] root", path, root)); + } + return new Details.DefaultRootedPath(root, root.relativize(path), Files.isDirectory(path)); + }; + } + + public static void copy(Stream rootedPaths, Path dest, CopyOption...options) throws IOException { + Objects.requireNonNull(rootedPaths); + Objects.requireNonNull(dest); + + var marks = new HashMap(); + + // Preset marks for the preexisting paths. + Files.walkFileTree(dest, new FileVisitor() { + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + marks.put(dir, new Details.PathMark(true, true)); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + marks.put(file, new Details.PathMark(false, true)); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + return FileVisitResult.TERMINATE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + }); + + var replacePreexisting = Set.of(options).contains(StandardCopyOption.REPLACE_EXISTING); + + Predicate canReplace = v -> { + return v.isPreexisting() && replacePreexisting; + }; + + try { + rootedPaths.sequential().map(Details.DefaultRootedPath.class::cast).forEach(rootedPath -> { + + final var dstPath = dest.resolve(rootedPath.branch()); + + var dstPathMark = marks.get(dstPath); + + if (!Optional.ofNullable(dstPathMark).map(canReplace::test).orElse(true)) { + // Destination path can not be replaced, bail out. + return; + } + + // Check the ancestors of the destination path. + for (var ancestor : Details.ancestorPaths(rootedPath.branch())) { + var mark = Optional.ofNullable(marks.get(dest.resolve(ancestor))); + + if (!mark.map(Details.PathMark::isDirectory).orElse(true)) { + // `ancestor` is a file, don't overwrite it. + return; + } + } + + dstPathMark = rootedPath.createPathMark(); + marks.put(dstPath, dstPathMark); + + try { + if (replacePreexisting && (rootedPath.isDirectory() != dstPathMark.isDirectory())) { + FileUtils.deleteRecursive(dstPath); + } + + if (rootedPath.isDirectory()) { + Files.createDirectories(dstPath); + } else { + Files.createDirectories(dstPath.getParent()); + Files.copy(rootedPath.fullPath(), dstPath, options); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + } catch (UncheckedIOException ex) { + throw ex.getCause(); + } + } + + static final class Details { + + private Details() { + } + + private record DefaultRootedPath(Path root, Path branch, boolean isDirectory) implements RootedPath { + + DefaultRootedPath { + Objects.requireNonNull(root); + Objects.requireNonNull(branch); + if (branch.isAbsolute()) { + throw new IllegalArgumentException(); + } + } + + PathMark createPathMark() { + return new PathMark(isDirectory); + } + } + + private record PathMark(boolean isDirectory, boolean isPreexisting) { + PathMark(boolean isDirectory) { + this(isDirectory, false); + } + } + + private static List ancestorPaths(Path path) { + var ancestors = new ArrayList(); + while ((path = path.getParent()) != null) { + ancestors.add(path); + } + return ancestors; + } + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java index 9a13a0f954d..21f941eedf5 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +52,7 @@ final record WinExePackager(BuildEnv env, WinExePackage pkg, Path outputDir, Pat @Override public void accept(PackagingPipeline.Builder pipelineBuilder) { - pipelineBuilder.excludeDirFromCopying(outputDir) + pipelineBuilder .task(ExePackageTaskID.RUN_POST_MSI_USER_SCRIPT) .action(this::runPostMsiScript) .addDependency(PackageTaskID.CREATE_PACKAGE_FILE) @@ -79,8 +79,6 @@ final record WinExePackager(BuildEnv env, WinExePackage pkg, Path outputDir, Pat private void wrapMsiInExe() throws IOException { - Log.verbose(I18N.format("message.outputting-to-location", outputDir.toAbsolutePath())); - final var msi = msi(); // Copy template msi wrapper next to msi file @@ -102,7 +100,5 @@ final record WinExePackager(BuildEnv env, WinExePackage pkg, Path outputDir, Pat Files.copy(exePath, dstExePath, StandardCopyOption.REPLACE_EXISTING); dstExePath.toFile().setExecutable(true); - - Log.verbose(I18N.format("message.output-location", outputDir.toAbsolutePath())); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java index 915d034bd82..c72b14a76d5 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +162,7 @@ final class WinMsiPackager implements Consumer { @Override public void accept(PackagingPipeline.Builder pipelineBuilder) { - pipelineBuilder.excludeDirFromCopying(outputDir) + pipelineBuilder .task(PackagingPipeline.PackageTaskID.CREATE_CONFIG_FILES) .action(this::prepareConfigFiles) .add() @@ -315,7 +315,6 @@ final class WinMsiPackager implements Consumer { private void buildPackage() throws IOException { final var msiOut = outputDir.resolve(pkg.packageFileNameWithSuffix()); - Log.verbose(I18N.format("message.generating-msi", msiOut.toAbsolutePath())); wixPipeline.buildMsi(msiOut.toAbsolutePath()); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties index 1f485e6c6c8..38d0bd02bbb 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. # 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,9 @@ error.missing-service-installer.advice=Add 'service-installer.exe' service insta message.icon-not-ico=The specified icon "{0}" is not an ICO file and will not be used. The default icon will be used in it's place. message.potential.windows.defender.issue=Warning: Windows Defender may prevent jpackage from functioning. If there is an issue, it can be addressed by either disabling realtime monitoring, or adding an exclusion for the directory "{0}". -message.outputting-to-location=Generating EXE for installer to: {0}. -message.output-location=Installer (.exe) saved to: {0} message.tool-version=Detected [{0}] version [{1}]. message.wrong-tool-version=Detected [{0}] version {1} but version {2} is required. message.use-wix36-features=WiX {0} detected. Enabling advanced cleanup action. message.product-code=MSI ProductCode: {0}. message.upgrade-code=MSI UpgradeCode: {0}. message.preparing-msi-config=Preparing MSI config: {0}. -message.generating-msi=Generating MSI: {0}. - diff --git a/test/hotspot/gtest/opto/test_rangeinference.cpp b/test/hotspot/gtest/opto/test_rangeinference.cpp index 61a9ff7fb70..fd49050d022 100644 --- a/test/hotspot/gtest/opto/test_rangeinference.cpp +++ b/test/hotspot/gtest/opto/test_rangeinference.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -202,7 +202,7 @@ static void test_canonicalize_constraints_random() { } } -TEST(opto, canonicalize_constraints) { +TEST_VM(opto, canonicalize_constraints) { test_canonicalize_constraints_trivial(); test_canonicalize_constraints_exhaustive, uintn_t<1>>(); test_canonicalize_constraints_exhaustive, uintn_t<2>>(); @@ -216,13 +216,13 @@ TEST(opto, canonicalize_constraints) { // Implementations of TypeIntMirror methods for testing purposes template -const TypeIntMirror* TypeIntMirror::operator->() const { - return this; +TypeIntMirror TypeIntMirror::make(const TypeIntMirror& t, int widen) { + return t; } template -TypeIntMirror TypeIntMirror::meet(const TypeIntMirror& o) const { - return TypeIntHelper::int_type_union(*this, o); +const TypeIntMirror* TypeIntMirror::operator->() const { + return this; } template diff --git a/test/hotspot/jtreg/compiler/c2/ClearArray.java b/test/hotspot/jtreg/compiler/c2/ClearArray.java index ee376641650..d218eef5780 100644 --- a/test/hotspot/jtreg/compiler/c2/ClearArray.java +++ b/test/hotspot/jtreg/compiler/c2/ClearArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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 ClearArray.java - * @bug 8284883 + * @bug 8284883 8374570 * @compile ClearArray.java * @summary ClearArray instruction overflows scratch buffer * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -Xbatch @@ -33,6 +33,8 @@ * -XX:InitArrayShortSize=32768 -XX:-IdealizeClearArrayNode -XX:UseAVX=3 compiler.c2.ClearArray * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -Xbatch * -XX:InitArrayShortSize=32768 -XX:MaxVectorSize=8 -XX:-IdealizeClearArrayNode -XX:UseAVX=3 compiler.c2.ClearArray + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -Xbatch + * -XX:+EnableX86ECoreOpts -XX:MaxVectorSize=8 -XX:UseAVX=3 compiler.c2.ClearArray */ package compiler.c2; diff --git a/test/hotspot/jtreg/compiler/ccp/TestWrongXorIWiden.java b/test/hotspot/jtreg/compiler/ccp/TestWrongXorIWiden.java new file mode 100644 index 00000000000..3b058758beb --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestWrongXorIWiden.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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.ccp; + +/* + * @test + * @bug 8374180 + * @summary Test that _widen is set correctly in XorI::add_ring() to ensure monotonicity. + * @run main/othervm -XX:CompileCommand=compileonly,${test.main.class}::* -Xcomp ${test.main.class} + */ +public class TestWrongXorIWiden { + static byte byFld; + + public static void main(String[] strArr) { + test(); + } + + static void test() { + int k, i17 = 0; + long lArr[] = new long[400]; + for (int i = 9; i < 54; ++i) { + for (int j = 7; j > 1; j--) { + for (k = 1; k < 2; k++) { + i17 >>= i; + } + byFld += j ^ i17; + for (int a = 1; a < 2; a++) { + i17 = k; + } + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestSplitLoadThroughPhiDuringEA.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestSplitLoadThroughPhiDuringEA.java new file mode 100644 index 00000000000..1221c1b8064 --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestSplitLoadThroughPhiDuringEA.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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.escapeAnalysis; + +import java.util.Objects; + +/* + * @test + * @bug 8374435 + * @summary assert during escape analysis when splitting a Load through a Phi because the input of + * the result Phi is a Load not from an AddP + * @run main/othervm -XX:-UseOnStackReplacement -XX:-UseCompressedOops ${test.main.class} + */ +public class TestSplitLoadThroughPhiDuringEA { + static class Holder { + Object o; + } + + public static void main(String[] args) { + Object o = new Object(); + Holder h = new Holder(); + for (int i = 0; i < 20000; i++) { + test(true, h, o); + test(false, h, o); + } + } + + private static Object test(boolean b, Holder h, Object o) { + h = Objects.requireNonNull(h); + if (b) { + h = new Holder(); + // This access has the pattern LoadP -> LoadP, which upsets the compiler because the + // pointer input of a LoadP is not an AddP + h.o = o.getClass(); + } + return h.o; + } +} diff --git a/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java b/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java new file mode 100644 index 00000000000..d358359ff14 --- /dev/null +++ b/test/hotspot/jtreg/compiler/igvn/TestMinMaxIdentity.java @@ -0,0 +1,186 @@ +/* + * 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 8373134 + * @summary Verify that min/max add identity optimizations get applied correctly + * @modules java.base/jdk.internal.misc + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver ${test.main.class} + */ + +package compiler.igvn; + +import compiler.lib.compile_framework.CompileFramework; +import compiler.lib.template_framework.Template; +import compiler.lib.template_framework.TemplateToken; +import compiler.lib.template_framework.library.CodeGenerationDataNameType; +import compiler.lib.template_framework.library.PrimitiveType; +import compiler.lib.template_framework.library.TestFrameworkClass; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import static compiler.lib.template_framework.Template.let; +import static compiler.lib.template_framework.Template.scope; + +public class TestMinMaxIdentity { + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("compiler.igvn.templated.MinMaxIdentity", generate(comp)); + + // Compile the source file. + comp.compile("--add-modules=jdk.incubator.vector"); + + comp.invoke("compiler.igvn.templated.MinMaxIdentity", "main", new Object[] {new String[] { + "--add-modules=jdk.incubator.vector", + "--add-opens", "jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED" + }}); + } + + private static String generate(CompileFramework comp) { + // Create a list to collect all tests. + List testTemplateTokens = new ArrayList<>(); + + Stream.of(MinMaxOp.values()) + .flatMap(MinMaxOp::generate) + .forEach(testTemplateTokens::add); + + Stream.of(Fp16MinMaxOp.values()) + .flatMap(Fp16MinMaxOp::generate) + .forEach(testTemplateTokens::add); + + // Create the test class, which runs all testTemplateTokens. + return TestFrameworkClass.render( + // package and class name. + "compiler.igvn.templated", "MinMaxIdentity", + // List of imports. + Set.of("jdk.incubator.vector.Float16"), + // classpath, so the Test VM has access to the compiled class files. + comp.getEscapedClassPathOfCompiledClasses(), + // The list of tests. + testTemplateTokens); + } + + enum MinMaxOp { + MIN_D("min", CodeGenerationDataNameType.doubles()), + MAX_D("max", CodeGenerationDataNameType.doubles()), + MIN_F("min", CodeGenerationDataNameType.floats()), + MAX_F("max", CodeGenerationDataNameType.floats()), + MIN_I("min", CodeGenerationDataNameType.ints()), + MAX_I("max", CodeGenerationDataNameType.ints()), + MIN_L("min", CodeGenerationDataNameType.longs()), + MAX_L("max", CodeGenerationDataNameType.longs()); + + final String functionName; + final PrimitiveType type; + + MinMaxOp(String functionName, PrimitiveType type) { + this.functionName = functionName; + this.type = type; + } + + Stream generate() { + return Stream.of(template("a", "b"), template("b", "a")). + map(Template.ZeroArgs::asToken); + } + + private Template.ZeroArgs template(String arg1, String arg2) { + return Template.make(() -> scope( + let("boxedTypeName", type.boxedTypeName()), + let("op", name()), + let("type", type.name()), + let("functionName", functionName), + let("arg1", arg1), + let("arg2", arg2), + """ + @Test + @IR(counts = {IRNode.#op, "= 1"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @Arguments(values = {Argument.NUMBER_42, Argument.NUMBER_42}) + public #type $test(#type #arg1, #type #arg2) { + int i; + for (i = -10; i < 1; i++) { + } + #type c = a * i; + return #boxedTypeName.#functionName(a, #boxedTypeName.#functionName(b, c)); + } + """ + )); + } + } + + enum Fp16MinMaxOp { + MAX_HF("max"), + MIN_HF("min"); + + final String functionName; + + Fp16MinMaxOp(String functionName) { + this.functionName = functionName; + } + + Stream generate() { + return Stream.of(template("a", "b"), template("b", "a")). + map(Template.ZeroArgs::asToken); + } + + private Template.ZeroArgs template(String arg1, String arg2) { + return Template.make(() -> scope( + let("op", name()), + let("functionName", functionName), + let("arg1", arg1), + let("arg2", arg2), + """ + @Setup + private static Object[] $setup() { + return new Object[] {Float16.valueOf(42), Float16.valueOf(42)}; + } + + @Test + @IR(counts = {IRNode.#op, "= 1"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION, + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.#op, "= 1"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + @Arguments(setup = "$setup") + public Float16 $test(Float16 #arg1, Float16 #arg2) { + int i; + for (i = -10; i < 1; i++) { + } + Float16 c = Float16.multiply(a, Float16.valueOf(i)); + return Float16.#functionName(a, Float16.#functionName(b, c)); + } + """ + )); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/AbstractInfo.java b/test/hotspot/jtreg/compiler/lib/ir_framework/AbstractInfo.java index 20a865b1337..b57b209112c 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/AbstractInfo.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/AbstractInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,7 @@ abstract public class AbstractInfo { } /** - * Returns a boolean indicating if the test VM runs with flags that allow C2 compilations. + * Returns a boolean indicating if the Test VM runs with flags that allow C2 compilations. * * @return {@code true} if C2 compilations are allowed; * {@code false} otherwise (run with {@code -XX:TieredStopAtLevel={1,2,3}, -XX:-UseCompiler}). diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/CompLevel.java b/test/hotspot/jtreg/compiler/lib/ir_framework/CompLevel.java index b6e55c0f617..f8760b4dfad 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/CompLevel.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/CompLevel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +51,7 @@ public enum CompLevel { * Can only be used at {@link Test#compLevel()}. After the warm-up, the framework keeps invoking the test over a span * of 10s (configurable by setting the property flag {@code -DWaitForCompilationTimeout}) until HotSpot compiles the * {@link Test} method. If the method was not compiled after 10s, an exception is thrown. The framework does not wait - * for the compilation if the test VM is run with {@code -Xcomp}, {@code -XX:-UseCompiler}, or + * for the compilation if the Test VM is run with {@code -Xcomp}, {@code -XX:-UseCompiler}, or * {@code -DExcludeRandom=true}. */ WAIT_FOR_COMPILATION(-4), diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java index fd2cd69056a..96df71dacd7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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 java.lang.annotation.RetentionPolicy; * For any other flag specified either by user code (e.g. {@link Scenario#Scenario(int, String...)}, * {@link TestFramework#runWithFlags(String...) etc.} or as part of the JTreg whitelist, IR verification is applied. * To restrict the application of IR rules when certain flags are present that could change the IR, each {@code @IR} - * annotation can specify additional preconditions on the allowed test VM flags that must hold when an IR rule is applied. + * annotation can specify additional preconditions on the allowed Test VM flags that must hold when an IR rule is applied. * If the specified preconditions fail, then the framework does not apply the IR rule. These preconditions can be * set with {@link #applyIf()}, {@link #applyIfNot()}, {@link #applyIfAnd()}, or {@link #applyIfOr()}. *

diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md index c0df8b54658..da59bd61b13 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md @@ -115,7 +115,7 @@ The [@IR](./IR.java) annotation provides two kinds of checks: - `counts`: A list of one or more "IR node/user-defined regex - counter" pairs which specify how often each IR node/user-defined regex should be matched on the compilation output of each compile phase. #### Disable/Enable IR Rules based on VM Flags -One might also want to restrict the application of certain `@IR` rules depending on the used flags in the test VM. These could be flags defined by the user or by JTreg. In the latter case, the flags must be whitelisted in `JTREG_WHITELIST_FLAGS` in [TestFramework](./TestFramework.java) (i.e. have no unexpected impact on the IR except if the flag simulates a specific machine setup like `UseAVX={1,2,3}` etc.) to enable an IR verification by the framework. The `@IR` rules thus have an option to restrict their application: +One might also want to restrict the application of certain `@IR` rules depending on the used flags in the Test VM. These could be flags defined by the user or by JTreg. In the latter case, the flags must be whitelisted in `JTREG_WHITELIST_FLAGS` in [TestFramework](./TestFramework.java) (i.e. have no unexpected impact on the IR except if the flag simulates a specific machine setup like `UseAVX={1,2,3}` etc.) to enable an IR verification by the framework. The `@IR` rules thus have an option to restrict their application: - `applyIf`: Only apply a rule if a flag has the specified value/range of values. - `applyIfNot`: Only apply a rule if a flag has **not** a specified value/range of values @@ -144,7 +144,7 @@ An IR verification cannot always be performed. Certain VM flags explicitly disab More information about IR matching can be found in the Javadocs of [IR](./IR.java). Concrete examples on how to specify IR constraint/rules can be found in [IRExample](../../../testlibrary_tests/ir_framework/examples/IRExample.java), [TestIRMatching](../../../testlibrary_tests/ir_framework/tests/TestIRMatching.java) (internal framework test), and [TestPhaseIRMatching](../../../testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java) (internal framework test). ### 2.3 Test VM Flags and Scenarios -The recommended way to use the framework is by defining a single `@run driver` statement in the JTreg header which, however, does not allow the specification of additional test VM flags. Instead, the user has the possibility to provide VM flags by calling `TestFramework.runWithFlags()` or by creating a `TestFramework` builder object on which `addFlags()` can be called. +The recommended way to use the framework is by defining a single `@run driver` statement in the JTreg header which, however, does not allow the specification of additional Test VM flags. Instead, the user has the possibility to provide VM flags by calling `TestFramework.runWithFlags()` or by creating a `TestFramework` builder object on which `addFlags()` can be called. If a user wants to provide multiple flag combinations for a single test, he or she has the option to provide different scenarios. A scenario based flag will always have precedence over other user defined flags. More information about scenarios can be found in the Javadocs of [Scenario](./Scenario.java). If a user wants to test all combinations of multiple sets of flags, they can use `TestFramework.addCrossProductScenarios()`. @@ -174,16 +174,16 @@ The framework provides various stress and debug flags. They should mainly be use - `-DExclude=test3`: Provide a list of `@Test` method names which should be excluded from execution. - `-DScenarios=1,2`: Provide a list of scenario indexes to specify which scenarios should be executed. - `-DWarmup=200`: Provide a new default value of the number of warm-up iterations (framework default is 2000). This might have an influence on the resulting IR and could lead to matching failures (the user can also set a fixed default warm-up value in a test with `testFrameworkObject.setDefaultWarmup(200)`). -- `-DReportStdout=true`: Print the standard output of the test VM. +- `-DReportStdout=true`: Print the standard output of the Test VM. - `-DVerbose=true`: Enable more fine-grained logging (slows the execution down). -- `-DReproduce=true`: Flag to use when directly running a test VM to bypass dependencies to the driver VM state (for example, when reproducing an issue). +- `-DReproduce=true`: Flag to use when directly running a Test VM to bypass dependencies to the Driver VM state (for example, when reproducing an issue). - `-DPrintTimes=true`: Print the execution time measurements of each executed test. - `-DPrintRuleMatchingTime=true`: Print the time of matching IR rules per method. Slows down the execution as the rules are warmed up before measurement. -- `-DVerifyVM=true`: The framework runs the test VM with additional verification flags (slows the execution down). +- `-DVerifyVM=true`: The framework runs the Test VM with additional verification flags (slows the execution down). - `-DExcludeRandom=true`: The framework randomly excludes some methods from compilation. IR verification is disabled completely with this flag. - `-DFlipC1C2=true`: The framework compiles all `@Test` annotated method with C1 if a C2 compilation would have been applied and vice versa. IR verification is disabled completely with this flag. - `-DShuffleTests=false`: Disables the random execution order of all tests (such a shuffling is always done by default). -- `-DDumpReplay=true`: Add the `DumpReplay` directive to the test VM. +- `-DDumpReplay=true`: Add the `DumpReplay` directive to the Test VM. - `-DGCAfter=true`: Perform `System.gc()` after each test (slows the execution down). - `-DTestCompilationTimeout=20`: Change the default waiting time (default: 10s) for a compilation of a normal `@Test` annotated method. - `-DWaitForCompilationTimeout=20`: Change the default waiting time (default: 10s) for a compilation of a `@Test` annotated method with compilation level [WAIT\_FOR\_COMPILATION](./CompLevel.java). @@ -193,12 +193,12 @@ The framework provides various stress and debug flags. They should mainly be use ## 3. Test Framework Execution This section gives an overview of how the framework is executing a JTreg test that calls the framework from within its `main()` method. -The framework will spawn a new "test VM" to execute the user defined tests. The test VM collects all tests of the test class specified by the user code in `main()` and ensures that there is no violation of the required format by the framework. In a next step, the framework does the following for each test in general: +The framework will spawn a new "Test VM" to execute the user defined tests. The Test VM collects all tests of the test class specified by the user code in `main()` and ensures that there is no violation of the required format by the framework. In a next step, the framework does the following for each test in general: 1. Warm the test up for a predefined number of times (default 2000). This can also be adapted for all tests by using `testFrameworkobject.setDefaultWarmup(100)` or for individual tests with an additional [@Warmup](./Warmup.java) annotation. 2. After the warm-up is finished, the framework compiles the associated `@Test` annotated method at the specified compilation level (default: C2). 3. After the compilation, the test is invoked one more time. -Once the test VM terminates, IR verification (if possible) is performed on the output of the test VM. If any test throws an exception during its execution or if IR matching fails, the failures are collected and reported in a pretty format. Check the standard error and output for more information and how to reproduce these failures. +Once the Test VM terminates, IR verification (if possible) is performed on the output of the Test VM. If any test throws an exception during its execution or if IR matching fails, the failures are collected and reported in a pretty format. Check the standard error and output for more information and how to reproduce these failures. Some of the steps above can be different due to the kind of the test or due to using non-default annotation properties. These details and differences are described in the Javadocs for the three tests (see section 2.1 Different Tests). @@ -212,10 +212,10 @@ Additional testing was performed by converting all compiler Inline Types tests t ## 5. Framework Package Structure A user only needs to import classes from the package `compiler.lib.ir_framework` (e.g. `import compiler.lib.ir_framework.*;`) which represents the interface classes to the framework. The remaining framework internal classes are kept in separate subpackages and should not directly be imported: -- `compiler.lib.ir_framework.driver`: These classes are used while running the driver VM (same VM as the one running the user code's `main()` method of a JTreg test). -- `compiler.lib.ir_framework.flag`: These classes are used while running the flag VM to determine additional flags for the test VM which are required for IR verification. -- `compiler.lib.ir_framework.test`: These classes are used while running the test VM (i.e. the actual execution of the user tests as described in section 3). -- `compiler.lib.ir_framework.shared`: These classes can be called from either the driver, flag, or test VM. +- `compiler.lib.ir_framework.driver`: These classes are used while running the Driver VM (same VM as the one running the user code's `main()` method of a JTreg test). +- `compiler.lib.ir_framework.flag`: These classes are used while running the Flag VM to determine additional flags for the Test VM which are required for IR verification. +- `compiler.lib.ir_framework.test`: These classes are used while running the Test VM (i.e. the actual execution of the user tests as described in section 3). +- `compiler.lib.ir_framework.shared`: These classes can be called from either the driver, flag, or Test VM. ## 6. Summary The initial design and feature set was kept simple and straight forward and serves well for small to medium sized tests. There are a lot of possibilities to further enhance the framework and make it more powerful. This can be tackled in additional RFEs. A few ideas can be found as subtasks of the [initial RFE](https://bugs.openjdk.org/browse/JDK-8254129) for this framework. diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java b/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java index 17776f7285c..65f61173e2a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,16 +121,16 @@ public class Scenario { } /** - * Get the test VM output (stdout + stderr) of this scenario from the last execution of the framework. + * Get the Test VM output (stdout + stderr) of this scenario from the last execution of the framework. * - * @return the test VM output. + * @return the Test VM output. */ public String getTestVMOutput() { return testVMOutput; } /** - * Set the test VM output, called by the framework. + * Set the Test VM output, called by the framework. */ void setTestVMOutput(String testVMOutput) { this.testVMOutput = testVMOutput; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 09e291ce5a4..1fea5da52ef 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,19 +85,19 @@ import java.util.stream.Stream; * {@code runXX()} methods of {@link TestFramework}. The second way, which gives more control, is to create a new * {@code TestFramework} builder object on which {@link #start()} needs to be eventually called to start the testing. *

- * The framework is called from the driver VM in which the JTreg test is initially run by specifying {@code + * The framework is called from the Driver VM in which the JTreg test is initially run by specifying {@code * @run driver} in the JTreg header. This strips all additionally specified JTreg VM and Javaoptions. - * The framework creates a new flag VM with all these flags added again in order to figure out which flags are + * The framework creates a new Flag VM with all these flags added again in order to figure out which flags are * required to run the tests specified in the test class (e.g. {@code -XX:+PrintIdeal} and {@code -XX:+PrintOptoAssembly} * for IR matching). *

- * After the flag VM terminates, it starts a new test VM which performs the execution of the specified + * After the Flag VM terminates, it starts a new Test VM which performs the execution of the specified * tests in the test class as described in {@link Test}, {@link Check}, and {@link Run}. *

- * In a last step, once the test VM has terminated without exceptions, IR matching is performed if there are any IR + * In a last step, once the Test VM has terminated without exceptions, IR matching is performed if there are any IR * rules and if no VM flags disable it (e.g. not running with {@code -Xint}, see {@link IR} for more details). * The IR regex matching is done on the output of {@code -XX:+PrintIdeal} and {@code -XX:+PrintOptoAssembly} by parsing - * the hotspot_pid file of the test VM. Failing IR rules are reported by throwing a {@link IRViolationException}. + * the hotspot_pid file of the Test VM. Failing IR rules are reported by throwing a {@link IRViolationException}. * * @see Test * @see Check @@ -166,7 +166,7 @@ public class TestFramework { ############################################################# - To only run the failed tests use -DTest, -DExclude, and/or -DScenarios. - - To also get the standard output of the test VM run with + - To also get the standard output of the Test VM run with -DReportStdout=true or for even more fine-grained logging use -DVerbose=true. ############################################################# @@ -236,10 +236,10 @@ public class TestFramework { } /** - * Tests the class from which this method was invoked from. The test VM is called with the specified {@code flags}. + * Tests the class from which this method was invoked from. The Test VM is called with the specified {@code flags}. *

    *
  • The {@code flags} override any set VM or Javaoptions flags by JTreg by default.

    - * Use {@code -DPreferCommandLineFlags=true} if you want to prefer the JTreg VM and Javaoptions flags over + * Use {@code -DPreferCommandLineFlags=true} if you want to prefer the JTreg VM and Javaoptions flags over * the specified {@code flags} of this method.

  • *
  • If you want to run your entire JTreg test with additional flags, use this method.

  • *
  • If you want to run your entire JTreg test with additional flags but for another test class then the one @@ -248,7 +248,7 @@ public class TestFramework { * {@link #addScenarios(Scenario...)}

  • *
* - * @param flags VM flags to be used for the test VM. + * @param flags VM flags to be used for the Test VM. */ public static void runWithFlags(String... flags) { StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); @@ -258,13 +258,13 @@ public class TestFramework { } /** - * Add VM flags to be used for the test VM. These flags override any VM or Javaoptions set by JTreg by default.

+ * Add VM flags to be used for the Test VM. These flags override any VM or Javaoptions set by JTreg by default.

* Use {@code -DPreferCommandLineFlags=true} if you want to prefer the VM or Javaoptions over the scenario flags. * *

* The testing can be started by invoking {@link #start()} * - * @param flags VM options to be applied to the test VM. + * @param flags VM options to be applied to the Test VM. * @return the same framework instance. */ public TestFramework addFlags(String... flags) { @@ -306,7 +306,7 @@ public class TestFramework { } /** - * Add scenarios to be used for the test VM. A test VM is called for each scenario in {@code scenarios} by using the + * Add scenarios to be used for the Test VM. A Test VM is called for each scenario in {@code scenarios} by using the * specified VM flags in the scenario. The scenario flags override any flags set by {@link #addFlags(String...)} * and thus also override any VM or Javaoptions set by JTreg by default.

* Use {@code -DPreferCommandLineFlags=true} if you want to prefer the VM and Javaoptions over the scenario flags. @@ -314,7 +314,7 @@ public class TestFramework { *

* The testing can be started by invoking {@link #start()} * - * @param scenarios scenarios which specify specific flags for the test VM. + * @param scenarios scenarios which specify specific flags for the Test VM. * @return the same framework instance. */ public TestFramework addScenarios(Scenario... scenarios) { @@ -503,10 +503,10 @@ public class TestFramework { } /** - * Get the VM output of the test VM. Use {@code -DVerbose=true} to enable more debug information. If scenarios + * Get the VM output of the Test VM. Use {@code -DVerbose=true} to enable more debug information. If scenarios * were run, use {@link Scenario#getTestVMOutput()}. * - * @return the last test VM output. + * @return the last Test VM output. */ public static String getLastTestVMOutput() { return TestVMProcess.getLastTestVMOutput(); @@ -796,9 +796,9 @@ public class TestFramework { } /** - * Execute a separate "flag" VM with White Box access to determine all test VM flags. The flag VM sends an encoding of - * all required flags for the test VM to the driver VM over a socket. Once the flag VM exits, this driver VM parses the - * test VM flags, which also determine if IR matching should be done, and then starts the test VM to execute all tests. + * Execute a separate Flag VM with White Box access to determine all Test VM flags. The Flag VM sends an encoding of + * all required flags for the Test VM to the Driver VM over a socket. Once the Flag VM exits, this Driver VM parses the + * Test VM flags, which also determine if IR matching should be done, and then starts the Test VM to execute all tests. */ private void start(Scenario scenario) { if (scenario != null && !scenario.isEnabled()) { @@ -823,12 +823,12 @@ public class TestFramework { "" : " - [" + String.join(", ", additionalFlags) + "]"; if (shouldVerifyIR) { - // Only need to use flag VM if an IR verification is possibly done. + // Only need to use Flag VM if an IR verification is possibly done. System.out.println("Run Flag VM:"); FlagVMProcess flagVMProcess = new FlagVMProcess(testClass, additionalFlags); shouldVerifyIR = flagVMProcess.shouldVerifyIR(); if (shouldVerifyIR) { - // Add more flags for the test VM which are required to do IR verification. + // Add more flags for the Test VM which are required to do IR verification. additionalFlags.addAll(flagVMProcess.getTestVMFlags()); } // else: Flag VM found a reason to not do IR verification. } else { @@ -882,7 +882,7 @@ public class TestFramework { try { TestClassParser testClassParser = new TestClassParser(testClass, isAllowNotCompilable); Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), - testVMProcess.getIrEncoding()); + testVMProcess.getApplicableIRRules()); IRMatcher matcher = new IRMatcher(testClassMatchable); matcher.match(); } catch (IRViolationException e) { @@ -892,7 +892,7 @@ public class TestFramework { } else { System.out.println("IR verification disabled either due to no @IR annotations, through explicitly setting " + "-DVerify=false, due to not running a debug build, using a non-whitelisted JTreg VM or " + - "Javaopts flag like -Xint, or running the test VM with other VM flags added by user code " + + "Javaopts flag like -Xint, or running the Test VM with other VM flags added by user code " + "that make the IR verification impossible (e.g. -XX:-UseCompile, " + "-XX:TieredStopAtLevel=[1,2,3], etc.)."); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java index 0b7d1db125c..86eb1935207 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/FlagVMProcess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +41,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * This class prepares, creates, and runs the "flag" VM with verification of proper termination. The flag VM determines - * the flags required for the "test" VM. The flag VM writes these flags to a dedicated file which is then parsed by this - * class after the termination of the flag VM. + * This class prepares, creates, and runs the Flag VM with verification of proper termination. The Flag VM determines + * the flags required for the Test VM. The Flag VM writes these flags to a dedicated file which is then parsed by this + * class after the termination of the Flag VM. * * @see FlagVM */ @@ -73,7 +73,7 @@ public class FlagVMProcess { String patternString = "(.*DShouldDoIRVerification=(true|false).*)"; Pattern pattern = Pattern.compile(patternString); Matcher matcher = pattern.matcher(flags); - TestFramework.check(matcher.find(), "Invalid flag encoding emitted by flag VM"); + TestFramework.check(matcher.find(), "Invalid flag encoding emitted by Flag VM"); // Maybe we run with flags that make IR verification impossible shouldVerifyIR = Boolean.parseBoolean(matcher.group(2)); testVMFlags.addAll(Arrays.asList(matcher.group(1).split(FlagVM.TEST_VM_FLAGS_DELIMITER))); @@ -91,8 +91,8 @@ public class FlagVMProcess { } /** - * The flag VM needs White Box access to prepare all test VM flags. The flag VM will write the test VM flags to - * a dedicated file which is afterwards parsed by the driver VM and added as flags to the test VM. + * The Flag VM needs White Box access to prepare all Test VM flags. The Flag VM will write the Test VM flags to + * a dedicated file which is afterwards parsed by the Driver VM and added as flags to the Test VM. */ private void prepareVMFlags(Class testClass, List additionalFlags) { cmds.add("-Dtest.jdk=" + Utils.TEST_JDK); @@ -103,7 +103,7 @@ public class FlagVMProcess { cmds.add("-Xbootclasspath/a:."); cmds.add("-XX:+UnlockDiagnosticVMOptions"); cmds.add("-XX:+WhiteBoxAPI"); - // TestFramework and scenario flags might have an influence on the later used test VM flags. Add them as well. + // TestFramework and scenario flags might have an influence on the later used Test VM flags. Add them as well. cmds.addAll(additionalFlags); cmds.add(FlagVM.class.getCanonicalName()); cmds.add(testClass.getCanonicalName()); @@ -111,10 +111,10 @@ public class FlagVMProcess { private void start() { try { - // Run "flag" VM with White Box access to determine the test VM flags and if IR verification should be done. + // Run Flag VM with White Box access to determine the Test VM flags and if IR verification should be done. oa = ProcessTools.executeTestJava(cmds); } catch (Exception e) { - throw new TestRunException("Failed to execute TestFramework flag VM", e); + throw new TestRunException("Failed to execute TestFramework Flag VM", e); } testVMFlagsFile = FlagVM.TEST_VM_FLAGS_FILE_PREFIX + oa.pid() + FlagVM.FILE_POSTFIX; @@ -125,14 +125,14 @@ public class FlagVMProcess { String flagVMOutput = oa.getOutput(); int exitCode = oa.getExitValue(); if (VERBOSE && exitCode == 0) { - System.out.println("--- OUTPUT TestFramework flag VM ---"); + System.out.println("--- OUTPUT TestFramework Flag VM ---"); System.out.println(flagVMOutput); } if (exitCode != 0) { - System.err.println("--- OUTPUT TestFramework flag VM ---"); + System.err.println("--- OUTPUT TestFramework Flag VM ---"); System.err.println(flagVMOutput); - throw new RuntimeException("TestFramework flag VM exited with " + exitCode); + throw new RuntimeException("TestFramework Flag VM exited with " + exitCode); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMException.java index 63b3d522b86..8de9ac8e348 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMException.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package compiler.lib.ir_framework.driver; import compiler.lib.ir_framework.shared.TestFormatException; /** - * Exception that is thrown if the test VM has thrown any kind of exception (except for {@link TestFormatException}). + * Exception that is thrown if the Test VM has thrown any kind of exception (except for {@link TestFormatException}). */ public class TestVMException extends RuntimeException { private final String exceptionInfo; @@ -37,9 +37,9 @@ public class TestVMException extends RuntimeException { } /** - * Get some more detailed information about the exception thrown in the test VM and how to reproduce it. + * Get some more detailed information about the exception thrown in the Test VM and how to reproduce it. * - * @return a formatted string containing information about the exception of the test VM and how to reproduce it. + * @return a formatted string containing information about the exception of the Test VM and how to reproduce it. */ public String getExceptionInfo() { return exceptionInfo; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 2b7fd2a1eea..a172dce1991 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +41,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; /** - * This class prepares, creates, and runs the "test" VM with verification of proper termination. The class also stores - * information about the test VM which is later queried for IR matching. The communication between this driver VM - * and the test VM is done over a dedicated socket. + * This class prepares, creates, and runs the Test VM with verification of proper termination. The class also stores + * information about the Test VM which is later queried for IR matching. The communication between this Driver VM + * and the Test VM is done over a dedicated socket. * * @see TestVM * @see TestFrameworkSocket @@ -62,7 +62,7 @@ public class TestVMProcess { private String hotspotPidFileName; private String commandLine; private OutputAnalyzer oa; - private String irEncoding; + private String applicableIRRules; public TestVMProcess(List additionalFlags, Class testClass, Set> helperClasses, int defaultWarmup, boolean allowNotCompilable, boolean testClassesOnBootClassPath) { @@ -81,8 +81,8 @@ public class TestVMProcess { return commandLine; } - public String getIrEncoding() { - return irEncoding; + public String getApplicableIRRules() { + return applicableIRRules; } public String getHotspotPidFileName() { @@ -98,7 +98,7 @@ public class TestVMProcess { boolean testClassesOnBootClassPath) { // Set java.library.path so JNI tests which rely on jtreg nativepath setting work cmds.add("-Djava.library.path=" + Utils.TEST_NATIVE_PATH); - // Need White Box access in test VM. + // Need White Box access in Test VM. String bootClassPath = "-Xbootclasspath/a:."; if (testClassesOnBootClassPath) { // Add test classes themselves to boot classpath to make them privileged. @@ -112,7 +112,8 @@ public class TestVMProcess { if (!PREFER_COMMAND_LINE_FLAGS) { cmds.addAll(jtregVMFlags); } - // Add server property flag that enables test VM to print encoding for IR verification last and debug messages. + // Add server property flag that enables the Test VM to print the Applicable IR Rules for IR verification and + // debug messages. cmds.add(socket.getPortPropertyFlag()); cmds.addAll(additionalFlags); cmds.addAll(Arrays.asList(getDefaultFlags())); @@ -142,7 +143,7 @@ public class TestVMProcess { } /** - * Default flags that are added used for the test VM. + * Default flags that are added used for the Test VM. */ private static String[] getDefaultFlags() { return new String[] {"-XX:-BackgroundCompilation", "-XX:CompileCommand=quiet"}; @@ -169,7 +170,7 @@ public class TestVMProcess { throw new TestFrameworkException("Error while executing Test VM", e); } - process.command().add(1, "-DReproduce=true"); // Add after "/path/to/bin/java" in order to rerun the test VM directly + process.command().add(1, "-DReproduce=true"); // Add after "/path/to/bin/java" in order to rerun the Test VM directly commandLine = "Command Line:" + System.lineSeparator() + String.join(" ", process.command()) + System.lineSeparator(); hotspotPidFileName = String.format("hotspot_pid%d.log", oa.pid()); @@ -178,7 +179,7 @@ public class TestVMProcess { /** * Process the socket output: All prefixed lines are dumped to the standard output while the remaining lines - * represent the IR encoding used for IR matching later. + * represent the Applicable IR Rules used for IR matching later. */ private void processSocketOutput(TestFrameworkSocket socket) { String output = socket.getOutput(); @@ -215,16 +216,16 @@ public class TestVMProcess { System.out.println("---------------------"); System.out.println(messagesBuilder); } - irEncoding = nonStdOutBuilder.toString(); + applicableIRRules = nonStdOutBuilder.toString(); } else { - irEncoding = output; + applicableIRRules = output; } } private void checkTestVMExitCode() { final int exitCode = oa.getExitValue(); if (EXCLUDE_RANDOM || REPORT_STDOUT || (VERBOSE && exitCode == 0)) { - System.out.println("--- OUTPUT TestFramework test VM ---"); + System.out.println("--- OUTPUT TestFramework Test VM ---"); System.out.println(oa.getOutput()); } @@ -234,7 +235,7 @@ public class TestVMProcess { } /** - * Exit code was non-zero of test VM. Check the stderr to determine what kind of exception that should be thrown to + * Exit code was non-zero of Test VM. Check the stderr to determine what kind of exception that should be thrown to * react accordingly later. */ private void throwTestVMException() { @@ -266,7 +267,7 @@ public class TestVMProcess { stdOut = System.lineSeparator() + System.lineSeparator() + "Standard Output" + System.lineSeparator() + "---------------" + System.lineSeparator() + oa.getOutput(); } - return "TestFramework test VM exited with code " + exitCode + System.lineSeparator() + stdOut + return "TestFramework Test VM exited with code " + exitCode + System.lineSeparator() + stdOut + System.lineSeparator() + commandLine + System.lineSeparator() + System.lineSeparator() + "Error Output" + System.lineSeparator() + "------------" + System.lineSeparator() + stdErr + System.lineSeparator() + System.lineSeparator(); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IREncodingParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java similarity index 60% rename from test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IREncodingParser.java rename to test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java index 28c4213f82d..7aaf0c2b285 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IREncodingParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import compiler.lib.ir_framework.TestFramework; import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.HotSpotPidFileParser; import compiler.lib.ir_framework.shared.TestFormat; import compiler.lib.ir_framework.shared.TestFrameworkException; -import compiler.lib.ir_framework.test.IREncodingPrinter; +import compiler.lib.ir_framework.test.ApplicableIRRulesPrinter; import java.lang.reflect.Method; import java.util.HashMap; @@ -37,34 +37,34 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Class to parse the IR encoding emitted by the test VM and creating {@link TestMethod} objects for each entry. + * Class to parse the Applicable IR Rules emitted by the Test VM and creating {@link TestMethod} objects for each entry. * * @see TestMethod */ -public class IREncodingParser { +public class ApplicableIRRulesParser { - private static final boolean PRINT_IR_ENCODING = Boolean.parseBoolean(System.getProperty("PrintIREncoding", "false")); - private static final Pattern IR_ENCODING_PATTERN = - Pattern.compile("(?<=" + IREncodingPrinter.START + "\r?\n).*\\R([\\s\\S]*)(?=" + IREncodingPrinter.END + ")"); + private static final boolean PRINT_APPLICABLE_IR_RULES = Boolean.parseBoolean(System.getProperty("PrintApplicableIRRules", "false")); + private static final Pattern APPLICABLE_IR_RULES_PATTERN = + Pattern.compile("(?<=" + ApplicableIRRulesPrinter.START + "\r?\n).*\\R([\\s\\S]*)(?=" + ApplicableIRRulesPrinter.END + ")"); private final Map testMethods; private final Class testClass; - public IREncodingParser(Class testClass) { + public ApplicableIRRulesParser(Class testClass) { this.testClass = testClass; this.testMethods = new HashMap<>(); } /** - * Parse the IR encoding passed as parameter and return a "test name" -> TestMethod map that contains an entry - * for each method that needs to be IR matched on. + * Parse the Applicable IR rules passed as parameter and return a "test name" -> TestMethod map that contains an + * entry for each method that needs to be IR matched on. */ - public TestMethods parse(String irEncoding) { - if (TestFramework.VERBOSE || PRINT_IR_ENCODING) { - System.out.println("Read IR encoding from test VM:"); - System.out.println(irEncoding); + public TestMethods parse(String applicableIRRules) { + if (TestFramework.VERBOSE || PRINT_APPLICABLE_IR_RULES) { + System.out.println("Read Applicable IR Rules from Test VM:"); + System.out.println(applicableIRRules); } - createTestMethodMap(irEncoding, testClass); + createTestMethodMap(applicableIRRules, testClass); // We could have found format errors in @IR annotations. Report them now with an exception. TestFormat.throwIfAnyFailures(); return new TestMethods(testMethods); @@ -74,22 +74,22 @@ public class IREncodingParser { * Sets up a map testname -> TestMethod map. The TestMethod object will later be filled with the ideal and opto * assembly output in {@link HotSpotPidFileParser}. */ - private void createTestMethodMap(String irEncoding, Class testClass) { - Map irRulesMap = parseIREncoding(irEncoding); - createTestMethodsWithEncoding(testClass, irRulesMap); + private void createTestMethodMap(String applicableIRRules, Class testClass) { + Map irRulesMap = parseApplicableIRRules(applicableIRRules); + createTestMethodsWithApplicableIRRules(testClass, irRulesMap); } /** - * Read the IR encoding emitted by the test VM to decide if an @IR rule must be checked for a method. + * Read the Applicable IR Rules emitted by the Test VM to decide if an @IR rule must be checked for a method. */ - private Map parseIREncoding(String irEncoding) { + private Map parseApplicableIRRules(String applicableIRRules) { Map irRulesMap = new HashMap<>(); - String[] irEncodingLines = getIREncodingLines(irEncoding); - for (String s : irEncodingLines) { + String[] applicableIRRulesLines = getApplicableIRRulesLines(applicableIRRules); + for (String s : applicableIRRulesLines) { String line = s.trim(); String[] splitLine = line.split(","); if (splitLine.length < 2) { - throw new TestFrameworkException("Invalid IR match rule encoding. No comma found: " + splitLine[0]); + throw new TestFrameworkException("Invalid Applicable IR Rules format. No comma found: " + splitLine[0]); } String testName = splitLine[0]; int[] irRulesIdx = getRuleIndexes(splitLine); @@ -99,11 +99,12 @@ public class IREncodingParser { } /** - * Parse the IR encoding lines without header, explanation line and footer and return them in an array. + * Parse the Applicable IR Rules lines without header, explanation line and footer and return them in an array. */ - private String[] getIREncodingLines(String irEncoding) { - Matcher matcher = IR_ENCODING_PATTERN.matcher(irEncoding); - TestFramework.check(matcher.find(), "Did not find IR encoding in:" + System.lineSeparator() + irEncoding); + private String[] getApplicableIRRulesLines(String applicableIRRules) { + Matcher matcher = APPLICABLE_IR_RULES_PATTERN.matcher(applicableIRRules); + TestFramework.check(matcher.find(), "Did not find Applicable IR Rules in:" + + System.lineSeparator() + applicableIRRules); String lines = matcher.group(1).trim(); if (lines.isEmpty()) { // Nothing to IR match. @@ -113,7 +114,7 @@ public class IREncodingParser { } /** - * Parse rule indexes from IR encoding line of the format: + * Parse rule indexes from a single line of the Applicable IR Rules in the format: */ private int[] getRuleIndexes(String[] splitLine) { int[] irRulesIdx = new int[splitLine.length - 1]; @@ -121,13 +122,13 @@ public class IREncodingParser { try { irRulesIdx[i - 1] = Integer.parseInt(splitLine[i]); } catch (NumberFormatException e) { - throw new TestFrameworkException("Invalid IR match rule encoding. No number found: " + splitLine[i]); + throw new TestFrameworkException("Invalid Applicable IR Rules format. No number found: " + splitLine[i]); } } return irRulesIdx; } - private void createTestMethodsWithEncoding(Class testClass, Map irRulesMap) { + private void createTestMethodsWithApplicableIRRules(Class testClass, Map irRulesMap) { for (Method m : testClass.getDeclaredMethods()) { IR[] irAnnos = m.getAnnotationsByType(IR.class); if (irAnnos.length > 0) { @@ -144,7 +145,7 @@ public class IREncodingParser { private void validateIRRuleIds(Method m, IR[] irAnnos, int[] ids) { TestFramework.check(ids != null, "Should find method name in validIrRulesMap for " + m); TestFramework.check(ids.length > 0, "Did not find any rule indices for " + m); - TestFramework.check((ids[0] >= 1 || ids[0] == IREncodingPrinter.NO_RULE_APPLIED) + TestFramework.check((ids[0] >= 1 || ids[0] == ApplicableIRRulesPrinter.NO_RULE_APPLIED) && ids[ids.length - 1] <= irAnnos.length, "Invalid IR rule index found in validIrRulesMap for " + m); } @@ -153,6 +154,6 @@ public class IREncodingParser { * Does the list of IR rules contain any applicable IR rules for the given conditions? */ private boolean hasAnyApplicableIRRules(int[] irRuleIds) { - return irRuleIds[0] != IREncodingPrinter.NO_RULE_APPLIED; + return irRuleIds[0] != ApplicableIRRulesPrinter.NO_RULE_APPLIED; } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java index 538680496e7..d7a10acd1cd 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package compiler.lib.ir_framework.driver.irmatching.parser; import compiler.lib.ir_framework.Test; -import compiler.lib.ir_framework.TestFramework; import compiler.lib.ir_framework.driver.irmatching.Compilation; import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethodMatchable; @@ -53,7 +52,7 @@ class IRMethodBuilder { } /** - * Create IR methods for all test methods identified by {@link IREncodingParser} by combining them with the parsed + * Create IR methods for all test methods identified by {@link ApplicableIRRulesParser} by combining them with the parsed * compilation output from {@link HotSpotPidFileParser}. */ public SortedSet build(VMInfo vmInfo) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java index b6c9920c2d1..2329b41afbe 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +50,13 @@ public class TestClassParser { } /** - * Parse the IR encoding and hotspot_pid* file to create a collection of {@link IRMethod} objects. + * Parse the Applicable IR Rules and hotspot_pid* file to create a collection of {@link IRMethod} objects. * Return a default/empty TestClass object if there are no applicable @IR rules in any method of the test class. */ - public Matchable parse(String hotspotPidFileName, String irEncoding) { - IREncodingParser irEncodingParser = new IREncodingParser(testClass); - TestMethods testMethods = irEncodingParser.parse(irEncoding); - VMInfo vmInfo = VMInfoParser.parseVMInfo(irEncoding); + public Matchable parse(String hotspotPidFileName, String applicableIRRules) { + ApplicableIRRulesParser applicableIRRulesParser = new ApplicableIRRulesParser(testClass); + TestMethods testMethods = applicableIRRulesParser.parse(applicableIRRules); + VMInfo vmInfo = VMInfoParser.parseVMInfo(applicableIRRules); if (testMethods.hasTestMethods()) { HotSpotPidFileParser hotSpotPidFileParser = new HotSpotPidFileParser(testClass.getName(), testMethods); LoggedMethods loggedMethods = hotSpotPidFileParser.parse(hotspotPidFileName); @@ -66,7 +66,7 @@ public class TestClassParser { } /** - * Create test class with IR methods for all test methods identified by {@link IREncodingParser} by combining them + * Create test class with IR methods for all test methods identified by {@link ApplicableIRRulesParser} by combining them * with the parsed compilation output from {@link HotSpotPidFileParser}. */ private Matchable createTestClass(TestMethods testMethods, LoggedMethods loggedMethods, VMInfo vmInfo) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java index 8491b8d61eb..43f27c80ac6 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +30,10 @@ import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.LoggedMethod; import java.lang.reflect.Method; /** - * This class represents a test method parsed by {@link IREncodingParser}. In combination with the associated + * This class represents a test method parsed by {@link ApplicableIRRulesParser}. In combination with the associated * {@link LoggedMethod}, a new {@link IRMethod} is created to IR match on later. * - * @see IREncodingParser + * @see ApplicableIRRulesParser * @see LoggedMethod * @see IRMethod */ diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethods.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethods.java index ecc8fb4e0b9..d1edfb08fdf 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethods.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +29,15 @@ import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.HotSpotPidFile import java.util.Map; /** - * This class stores all test methods that need to be IR matched as identified by {@link IREncodingParser}. + * This class stores all test methods that need to be IR matched as identified by {@link ApplicableIRRulesParser}. * - * @see IREncodingParser + * @see ApplicableIRRulesParser * @see HotSpotPidFileParser * @see IRMethod */ public class TestMethods { /** - * "Method name" -> TestMethod map created by {@link IREncodingParser} which contains an entry for each method that + * "Method name" -> TestMethod map created by {@link ApplicableIRRulesParser} which contains an entry for each method that * needs to be IR matched on. */ private final Map testMethods; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java index db70e7892a2..89b6d610496 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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.util.regex.Pattern; /** * This class stores the key value mapping from the VMInfo. * - * @see IREncodingParser + * @see ApplicableIRRulesParser */ public class VMInfo { /** diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java index a8e6782ab12..2b17303f1a7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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.util.regex.Matcher; import java.util.regex.Pattern; /** - * Class to parse the VMInfo emitted by the test VM and creating {@link VMInfo} objects for each entry. + * Class to parse the VMInfo emitted by the Test VM and creating {@link VMInfo} objects for each entry. * * @see VMInfo */ @@ -43,11 +43,11 @@ public class VMInfoParser { Pattern.compile("(?<=" + VMInfoPrinter.START_VM_INFO + "\r?\n).*\\R([\\s\\S]*)(?=" + VMInfoPrinter.END_VM_INFO + ")"); /** - * Extract VMInfo from the irEncoding. + * Extract VMInfo from the applicableIRRules. */ - public static VMInfo parseVMInfo(String irEncoding) { + public static VMInfo parseVMInfo(String applicableIRRules) { Map map = new HashMap<>(); - String[] lines = getVMInfoLines(irEncoding); + String[] lines = getVMInfoLines(applicableIRRules); for (String s : lines) { String line = s.trim(); String[] splitLine = line.split(":", 2); @@ -62,11 +62,11 @@ public class VMInfoParser { } /** - * Extract the VMInfo from the irEncoding string, strip away the header and return the individual key-value lines. + * Extract the VMInfo from the applicableIRRules string, strip away the header and return the individual key-value lines. */ - private static String[] getVMInfoLines(String irEncoding) { - Matcher matcher = VM_INFO_PATTERN.matcher(irEncoding); - TestFramework.check(matcher.find(), "Did not find VMInfo in:" + System.lineSeparator() + irEncoding); + private static String[] getVMInfoLines(String applicableIRRules) { + Matcher matcher = VM_INFO_PATTERN.matcher(applicableIRRules); + TestFramework.check(matcher.find(), "Did not find VMInfo in:" + System.lineSeparator() + applicableIRRules); String lines = matcher.group(1).trim(); if (lines.isEmpty()) { // Nothing to IR match. diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompileQueueMessages.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompileQueueMessages.java index 9ccb78ea892..f9fa0d1433e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompileQueueMessages.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/CompileQueueMessages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package compiler.lib.ir_framework.driver.irmatching.parser.hotspot; import compiler.lib.ir_framework.TestFramework; -import compiler.lib.ir_framework.driver.irmatching.parser.IREncodingParser; +import compiler.lib.ir_framework.driver.irmatching.parser.ApplicableIRRulesParser; import compiler.lib.ir_framework.driver.irmatching.parser.TestMethods; import java.util.HashMap; @@ -34,9 +34,9 @@ import java.util.regex.Pattern; /** * This class parses compile queue messages found in the hotspot_pid* files and keeps track of those that need to be - * IR matched (i.e. identified by {@link IREncodingParser}. + * IR matched (i.e. identified by {@link ApplicableIRRulesParser}. * - * @see IREncodingParser + * @see ApplicableIRRulesParser */ class CompileQueueMessages { private static final Pattern COMPILE_ID_PATTERN = Pattern.compile("compile_id='(\\d+)'"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/HotSpotPidFileParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/HotSpotPidFileParser.java index a5a5a0b20a9..f39f7cc9a83 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/HotSpotPidFileParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/hotspot/HotSpotPidFileParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package compiler.lib.ir_framework.driver.irmatching.parser.hotspot; import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; -import compiler.lib.ir_framework.driver.irmatching.parser.IREncodingParser; +import compiler.lib.ir_framework.driver.irmatching.parser.ApplicableIRRulesParser; import compiler.lib.ir_framework.driver.irmatching.parser.TestMethods; import compiler.lib.ir_framework.shared.TestFrameworkException; @@ -34,10 +34,10 @@ import java.nio.file.Paths; /** * Class to parse the ideal compile phases and PrintOptoAssembly outputs of the test class from the hotspot_pid* file - * of all methods identified by {@link IREncodingParser}. + * of all methods identified by {@link ApplicableIRRulesParser}. * * @see IRMethod - * @see IREncodingParser + * @see ApplicableIRRulesParser */ public class HotSpotPidFileParser { private final State state; @@ -47,8 +47,8 @@ public class HotSpotPidFileParser { } /** - * Parse the hotspot_pid*.log file from the test VM. Read the ideal compile phase and PrintOptoAssembly outputs for - * all methods defined by the IR encoding. + * Parse the hotspot_pid*.log file from the Test VM. Read the ideal compile phase and PrintOptoAssembly outputs for + * all methods defined by the Applicable IR Rules. */ public LoggedMethods parse(String hotspotPidFileName) { try (var reader = Files.newBufferedReader(Paths.get(hotspotPidFileName))) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/flag/CompilePhaseCollector.java b/test/hotspot/jtreg/compiler/lib/ir_framework/flag/CompilePhaseCollector.java index 86ef31c6277..0488b3f58e6 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/flag/CompilePhaseCollector.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/flag/CompilePhaseCollector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ class CompilePhaseCollector { collectCompilePhases(method)); } } catch (TestFormatException e) { - // Create default map and let the IR matcher report the format failures later in the driver VM. + // Create default map and let the IR matcher report the format failures later in the Driver VM. return createDefaultMap(testClass); } return methodNameToCompilePhasesMap; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/flag/FlagVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/flag/FlagVM.java index 42e4c85a499..4b033eb2c0e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/flag/FlagVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/flag/FlagVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +38,8 @@ import java.util.ArrayList; import java.util.Arrays; /** - * This class' main method is called from {@link TestFramework} and represents the so-called "flag VM". It uses the - * Whitebox API to determine the necessary additional flags to run the test VM (e.g. to do IR matching). It returns + * This class' main method is called from {@link TestFramework} and represents the so-called "Flag VM". It uses the + * Whitebox API to determine the necessary additional flags to run the Test VM (e.g. to do IR matching). It returns * the flags over the dedicated TestFramework socket. */ public class FlagVM { @@ -79,12 +79,12 @@ public class FlagVM { private static final boolean VERIFY_IR = REQUESTED_VERIFY_IR && USE_COMPILER && !EXCLUDE_RANDOM && !FLIP_C1_C2 && !TEST_C1 && Platform.isServer(); /** - * Main entry point of the flag VM. + * Main entry point of the Flag VM. */ public static void main(String[] args) { String testClassName = args[0]; if (VERBOSE) { - System.out.println("FlagVM main() called. Prepare test VM flags to run class " + testClassName); + System.out.println("FlagVM main() called. Prepare Test VM flags to run class " + testClassName); } Class testClass; try { @@ -96,8 +96,8 @@ public class FlagVM { } /** - * Emit test VM flags to the dedicated test VM flags file to parse them from the TestFramework "driver" VM again - * which adds them to the test VM. + * Emit Test VM flags to the dedicated Test VM flags file to parse them from the TestFramework Driver VM again + * which adds them to the Test VM. */ private static void emitTestVMFlags(ArrayList flags) { try (var bw = Files.newBufferedWriter(Paths.get(TEST_VM_FLAGS_FILE))) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/NoTestsRunException.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/NoTestsRunException.java index 02afdd4ee4f..4b616f53e4d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/NoTestsRunException.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/NoTestsRunException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +24,17 @@ package compiler.lib.ir_framework.shared; /** - * Exception that is thrown by the test VM if no tests are run as a result of specifying {@code -DTest} and/or - * {@code -DExclude} defining an empty set with the used test VM flags. + * Exception that is thrown by the Test VM if no tests are run as a result of specifying {@code -DTest} and/or + * {@code -DExclude} defining an empty set with the used Test VM flags. */ public class NoTestsRunException extends RuntimeException { /** - * Default constructor used by test VM + * Default constructor used by Test VM */ public NoTestsRunException() {} /** - * Constructor used to eventually throw the exception in the driver VM. + * Constructor used to eventually throw the exception in the Driver VM. */ public NoTestsRunException(String message) { super(message); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java index 1fdcb34a6b8..f10540ebc5b 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** - * Dedicated socket to send data from the flag and test VM back to the driver VM. + * Dedicated socket to send data from the flag and Test VM back to the Driver VM. */ public class TestFrameworkSocket implements AutoCloseable { public static final String STDOUT_PREFIX = "[STDOUT]"; @@ -46,7 +46,7 @@ public class TestFrameworkSocket implements AutoCloseable { public static final String PRINT_TIMES_TAG = "[PRINT_TIMES]"; public static final String NOT_COMPILABLE_TAG = "[NOT_COMPILABLE]"; - // Static fields used for test VM only. + // Static fields used for Test VM only. private static final String SERVER_PORT_PROPERTY = "ir.framework.server.port"; private static final int SERVER_PORT = Integer.getInteger(SERVER_PORT_PROPERTY, -1); @@ -85,7 +85,7 @@ public class TestFrameworkSocket implements AutoCloseable { } /** - * Waits for a client (created by flag or test VM) to connect. Return the messages received from the client. + * Waits for a client (created by flag or Test VM) to connect. Return the messages received from the client. */ private FutureTask initSocketTask() { return new FutureTask<>(() -> { @@ -117,18 +117,18 @@ public class TestFrameworkSocket implements AutoCloseable { } /** - * Only called by test VM to write to server socket. + * Only called by Test VM to write to server socket. */ public static void write(String msg, String tag) { write(msg, tag, false); } /** - * Only called by test VM to write to server socket. + * Only called by Test VM to write to server socket. *

- * The test VM is spawned by the main jtreg VM. The stdout of the test VM is hidden + * The Test VM is spawned by the main jtreg VM. The stdout of the Test VM is hidden * unless the Verbose or ReportStdout flag is used. TestFrameworkSocket is used by the parent jtreg - * VM and the test VM to communicate. By sending the prints through the TestFrameworkSocket with the + * VM and the Test VM to communicate. By sending the prints through the TestFrameworkSocket with the * parameter stdout set to true, the parent VM will print the received messages to its stdout, making it * visible to the user. */ @@ -137,10 +137,10 @@ public class TestFrameworkSocket implements AutoCloseable { System.out.println("Debugging Test VM: Skip writing due to -DReproduce"); return; } - TestFramework.check(SERVER_PORT != -1, "Server port was not set correctly for flag and/or test VM " - + "or method not called from flag or test VM"); + TestFramework.check(SERVER_PORT != -1, "Server port was not set correctly for flag and/or Test VM " + + "or method not called from flag or Test VM"); try { - // Keep the client socket open until the test VM terminates (calls closeClientSocket before exiting main()). + // Keep the client socket open until the Test VM terminates (calls closeClientSocket before exiting main()). if (clientSocket == null) { clientSocket = new Socket(InetAddress.getLoopbackAddress(), SERVER_PORT); clientWriter = new PrintWriter(clientSocket.getOutputStream(), true); @@ -150,11 +150,11 @@ public class TestFrameworkSocket implements AutoCloseable { } clientWriter.println(msg); } catch (Exception e) { - // When the test VM is directly run, we should ignore all messages that would normally be sent to the - // driver VM. + // When the Test VM is directly run, we should ignore all messages that would normally be sent to the + // Driver VM. String failMsg = System.lineSeparator() + System.lineSeparator() + """ ########################################################### - Did you directly run the test VM (TestVM class) + Did you directly run the Test VM (TestVM class) to reproduce a bug? => Append the flag -DReproduce=true and try again! ########################################################### @@ -169,7 +169,7 @@ public class TestFrameworkSocket implements AutoCloseable { /** * Closes (and flushes) the printer to the socket and the socket itself. Is called as last thing before exiting - * the main() method of the flag and the test VM. + * the main() method of the flag and the Test VM. */ public static void closeClientSocket() { if (clientSocket != null) { @@ -183,7 +183,7 @@ public class TestFrameworkSocket implements AutoCloseable { } /** - * Get the socket output of the flag VM. + * Get the socket output of the Flag VM. */ public String getOutput() { try { @@ -197,7 +197,7 @@ public class TestFrameworkSocket implements AutoCloseable { } /** - * Return whether test VM sent messages to be put on stdout (starting with {@link ::STDOUT_PREFIX}). + * Return whether Test VM sent messages to be put on stdout (starting with {@link ::STDOUT_PREFIX}). */ public boolean hasStdOut() { return receivedStdOut; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java similarity index 96% rename from test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java rename to test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java index a24cfbd3e37..4fa1f8f3fe5 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +39,13 @@ import java.util.Objects; import java.util.function.Function; /** - * Prints an encoding to the dedicated test framework socket whether @IR rules of @Test methods should be applied or not. - * This is done during the execution of the test VM by checking the active VM flags. This encoding is eventually parsed - * and checked by the IRMatcher class in the driver VM after the termination of the test VM. IR rule indices start at 1. + * Prints all applicable IR rules to the dedicated test framework socket whether @IR rules of @Test methods should be + * applied or not. This is done during the execution of the Test VM by checking the active VM flags. This + * Applicable IR Rules message is eventually parsed and checked by the IRMatcher class in the Driver VM after the + * termination of the Test VM. IR rule indices start at 1. */ -public class IREncodingPrinter { - public static final String START = "##### IRMatchRulesEncoding - used by TestFramework #####"; +public class ApplicableIRRulesPrinter { + public static final String START = "##### ApplicableIRRules - used by TestFramework #####"; public static final String END = "----- END -----"; public static final int NO_RULE_APPLIED = -1; @@ -60,7 +61,7 @@ public class IREncodingPrinter { // Platforms for use in IR preconditions. Please verify that e.g. there is // a corresponding use in a jtreg @requires annotation before adding new platforms, // as adding non-existent platforms can lead to skipped tests. - private static final List irTestingPlatforms = new ArrayList(Arrays.asList( + private static final List irTestingPlatforms = new ArrayList<>(Arrays.asList( // os.family "aix", "linux", @@ -85,7 +86,7 @@ public class IREncodingPrinter { // Please verify new CPU features before adding them. If we allow non-existent features // on this list, we will ignore tests and never execute them. Consult CPU_FEATURE_FLAGS // in corresponding vm_version_.hpp file to find correct cpu feature's name. - private static final List verifiedCPUFeatures = new ArrayList( Arrays.asList( + private static final List verifiedCPUFeatures = new ArrayList<>( Arrays.asList( // x86 "fma", "f16c", @@ -126,7 +127,7 @@ public class IREncodingPrinter { "zvkn" )); - public IREncodingPrinter() { + public ApplicableIRRulesPrinter() { output.append(START).append(System.lineSeparator()); output.append(",{comma separated applied @IR rule ids}").append(System.lineSeparator()); } @@ -136,7 +137,7 @@ public class IREncodingPrinter { * - indices of all @IR rules that should be applied, separated by a comma * - "-1" if no @IR rule should not be applied */ - public void emitRuleEncoding(Method m, boolean skipped) { + public void emitApplicableIRRules(Method m, boolean skipped) { method = m; int i = 0; ArrayList validRules = new ArrayList<>(); @@ -170,7 +171,7 @@ public class IREncodingPrinter { private void printDisableReason(String method, String reason, String[] apply, int ruleIndex, int ruleMax) { TestFrameworkSocket.write("Disabling IR matching for rule " + ruleIndex + " of " + ruleMax + " in " + method + ": " + reason + ": " + String.join(", ", apply), - "[IREncodingPrinter]", true); + "[ApplicableIRRules]", true); } private boolean shouldApplyIrRule(IR irAnno, String m, int ruleIndex, int ruleMax) { @@ -521,7 +522,7 @@ public class IREncodingPrinter { public void emit() { output.append(END); - TestFrameworkSocket.write(output.toString(), "IR rule application encoding"); + TestFrameworkSocket.write(output.toString(), "ApplicableIRRules"); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index 8ccd0faa013..c5ab318d67d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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 java.util.stream.Stream; import static compiler.lib.ir_framework.shared.TestFrameworkSocket.PRINT_TIMES_TAG; /** - * This class' main method is called from {@link TestFramework} and represents the so-called "test VM". The class is + * This class' main method is called from {@link TestFramework} and represents the so-called "Test VM". The class is * the heart of the framework and is responsible for executing all the specified tests in the test class. It uses the * Whitebox API and reflection to achieve this task. */ @@ -58,7 +58,7 @@ public class TestVM { TestFramework in main() of your test? Make sure to only call setup/run methods and no checks or assertions from main() of your test! - - Are you rerunning the test VM (TestVM class) + - Are you rerunning the Test VM (TestVM class) directly after a JTreg run? Make sure to start it from within JTwork/scratch and with the flag -DReproduce=true! @@ -100,7 +100,7 @@ public class TestVM { private static final boolean DUMP_REPLAY = Boolean.getBoolean("DumpReplay"); private static final boolean GC_AFTER = Boolean.getBoolean("GCAfter"); private static final boolean SHUFFLE_TESTS = Boolean.parseBoolean(System.getProperty("ShuffleTests", "true")); - // Use separate flag as VERIFY_IR could have been set by user but due to other flags it was disabled by flag VM. + // Use separate flag as VERIFY_IR could have been set by user but due to other flags it was disabled by Flag VM. private static final boolean PRINT_VALID_IR_RULES = Boolean.getBoolean("ShouldDoIRVerification"); protected static final long PER_METHOD_TRAP_LIMIT = (Long)WHITE_BOX.getVMFlag("PerMethodTrapLimit"); protected static final boolean PROFILE_INTERPRETER = (Boolean)WHITE_BOX.getVMFlag("ProfileInterpreter"); @@ -114,7 +114,7 @@ public class TestVM { private final List excludeList; private final List testList; private Set> helperClasses = null; // Helper classes that contain framework annotations to be processed. - private final IREncodingPrinter irMatchRulePrinter; + private final ApplicableIRRulesPrinter irMatchRulePrinter; private final Class testClass; private final Map forceCompileMap = new HashMap<>(); @@ -125,7 +125,7 @@ public class TestVM { this.excludeList = createTestFilterList(EXCLUDELIST, testClass); if (PRINT_VALID_IR_RULES) { - irMatchRulePrinter = new IREncodingPrinter(); + irMatchRulePrinter = new ApplicableIRRulesPrinter(); } else { irMatchRulePrinter = null; } @@ -155,7 +155,7 @@ public class TestVM { } /** - * Main entry point of the test VM. + * Main entry point of the Test VM. */ public static void main(String[] args) { try { @@ -293,7 +293,7 @@ public class TestVM { BaseTest baseTest = new BaseTest(test, shouldExcludeTest(m.getName())); allTests.add(baseTest); if (PRINT_VALID_IR_RULES) { - irMatchRulePrinter.emitRuleEncoding(m, baseTest.isSkipped()); + irMatchRulePrinter.emitApplicableIRRules(m, baseTest.isSkipped()); } } catch (TestFormatException e) { // Failure logged. Continue and report later. @@ -687,7 +687,7 @@ public class TestVM { allTests.add(checkedTest); if (PRINT_VALID_IR_RULES) { // Only need to emit IR verification information if IR verification is actually performed. - irMatchRulePrinter.emitRuleEncoding(testMethod, checkedTest.isSkipped()); + irMatchRulePrinter.emitApplicableIRRules(testMethod, checkedTest.isSkipped()); } } @@ -755,7 +755,7 @@ public class TestVM { CustomRunTest customRunTest = new CustomRunTest(m, getAnnotation(m, Warmup.class), runAnno, tests, shouldExcludeTest); allTests.add(customRunTest); if (PRINT_VALID_IR_RULES) { - tests.forEach(test -> irMatchRulePrinter.emitRuleEncoding(test.getTestMethod(), customRunTest.isSkipped())); + tests.forEach(test -> irMatchRulePrinter.emitApplicableIRRules(test.getTestMethod(), customRunTest.isSkipped())); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java index 14636da4cbe..470569122dd 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import compiler.lib.ir_framework.shared.TestFrameworkSocket; import jdk.test.whitebox.WhiteBox; /** - * Prints some test VM info to the socket. + * Prints some Test VM info to the socket. */ public class VMInfoPrinter { public static final String START_VM_INFO = "##### IRMatchingVMInfo - used by TestFramework #####"; diff --git a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java index 6b0a536e4d4..3064b320c0d 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,9 +143,9 @@ public class TestCPUAwareness { // Expected active processor count can not exceed available CPU count - private static int adjustExpectedAPCForAvailableCPUs(int expectedAPC) { - if (expectedAPC > availableCPUs) { - expectedAPC = availableCPUs; + private static double adjustExpectedAPCForAvailableCPUs(double expectedAPC) { + if (expectedAPC > (double)availableCPUs) { + expectedAPC = (double)availableCPUs; System.out.println("Adjusted expectedAPC = " + expectedAPC); } return expectedAPC; @@ -158,7 +158,7 @@ public class TestCPUAwareness { System.out.println("quota = " + quota); System.out.println("period = " + period); - int expectedAPC = (int) Math.ceil((float) quota / (float) period); + double expectedAPC = (double) quota / (double) period; System.out.println("expectedAPC = " + expectedAPC); expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC); @@ -178,7 +178,7 @@ public class TestCPUAwareness { private static void testAPCCombo(String cpuset, int quota, int period, int shares, - int expectedAPC) throws Exception { + double expectedAPC) throws Exception { Common.logNewTestCase("test APC Combo"); System.out.println("cpuset = " + cpuset); System.out.println("quota = " + quota); diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java index e0491b4b89f..0684ad1aacc 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 by SAP AG, Walldorf, Germany. + * Copyright (c) 2018, 2026 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 diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java index 373ee584679..d13e5e5d3c1 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 by SAP AG, Walldorf, Germany. + * Copyright (c) 2018, 2026 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 diff --git a/test/hotspot/jtreg/runtime/execstack/Test.java b/test/hotspot/jtreg/runtime/execstack/Test.java index 67891a523aa..22063a56dd5 100644 --- a/test/hotspot/jtreg/runtime/execstack/Test.java +++ b/test/hotspot/jtreg/runtime/execstack/Test.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 SAP AG. All Rights Reserved. + * Copyright (c) 2011, 2026 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 diff --git a/test/hotspot/jtreg/runtime/execstack/TestMT.java b/test/hotspot/jtreg/runtime/execstack/TestMT.java index 0be1a461c0a..282b09f9a35 100644 --- a/test/hotspot/jtreg/runtime/execstack/TestMT.java +++ b/test/hotspot/jtreg/runtime/execstack/TestMT.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 SAP AG. All Rights Reserved. + * Copyright (c) 2011, 2026 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 diff --git a/test/hotspot/jtreg/runtime/execstack/libtest-rw.c b/test/hotspot/jtreg/runtime/execstack/libtest-rw.c index 7ad4b95d25e..52e1e8328a1 100644 --- a/test/hotspot/jtreg/runtime/execstack/libtest-rw.c +++ b/test/hotspot/jtreg/runtime/execstack/libtest-rw.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 SAP AG. All Rights Reserved. + * Copyright (c) 2011, 2026 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 diff --git a/test/hotspot/jtreg/runtime/execstack/libtest-rwx.c b/test/hotspot/jtreg/runtime/execstack/libtest-rwx.c index bce4f853106..e0d8e424809 100644 --- a/test/hotspot/jtreg/runtime/execstack/libtest-rwx.c +++ b/test/hotspot/jtreg/runtime/execstack/libtest-rwx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 SAP AG. All Rights Reserved. + * Copyright (c) 2011, 2026 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 diff --git a/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java b/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java new file mode 100644 index 00000000000..3ced98b616d --- /dev/null +++ b/test/hotspot/jtreg/runtime/os/TestTrimNativeHeapIntervalTablesCleanup.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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 8375125 + * @summary Trigger StringTable::clean_dead_entries or SymbolTable::clean_dead_entries + * with -XX:TrimNativeHeapInterval enabled,should not violate lock ordering. + * @requires vm.debug + * @requires vm.gc != "Epsilon" + * @library /test/lib + * @modules java.compiler + * @run main/othervm -Xms128m -Xmx128m + * -XX:TrimNativeHeapInterval=300000 + * TestTrimNativeHeapIntervalTablesCleanup string + * @run main/othervm -Xms128m -Xmx128m + * -XX:TrimNativeHeapInterval=300000 + * TestTrimNativeHeapIntervalTablesCleanup symbol + */ + +import java.util.LinkedList; +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +public class TestTrimNativeHeapIntervalTablesCleanup { + + public static void main(String[] args) throws Exception{ + if (args.length != 1) { + throw new IllegalArgumentException("Expected 1 argument: string|symbol"); + } + switch (args[0]) { + case "string": + testStringTableCleanup(); + break; + case "symbol": + testSymbolTableCleanup(); + break; + default: + throw new IllegalArgumentException("Unknown mode: " + args[0]); + } + System.out.println("passed: " + args[0]); + } + + static void testStringTableCleanup() throws Exception{ + final int rounds = 30; + final int maxSize = 200_000; + final int pruneEvery = 50_000; + final int pruneCount = 25_000; + long stringNum = 0; + + for (int round = 0; round < rounds; round++) { + LinkedList list = new LinkedList<>(); + for (int i = 0; i < maxSize; i++, stringNum++) { + if (i != 0 && (i % pruneEvery) == 0) { + int toRemove = Math.min(pruneCount, list.size()); + list.subList(0, toRemove).clear(); + } + list.push(Long.toString(stringNum).intern()); + } + System.gc(); + Thread.sleep(1000); + } + } + + static void testSymbolTableCleanup() throws Exception { + final int rounds = 10; + final int classesPerRound = 100; + + for (int r = 0; r < rounds; r++) { + for (int i = 0; i < classesPerRound; i++) { + String cn = "C" + r + "_" + i; + byte[] bytes = InMemoryJavaCompiler.compile( + cn, + "public class " + cn + " { int m" + i + "() { return " + i + "; } }" + ); + new ClassLoader(null) { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (!name.equals(cn)) throw new ClassNotFoundException(name); + return defineClass(name, bytes, 0, bytes.length); + } + }.loadClass(cn).getDeclaredConstructor().newInstance(); + } + System.gc(); + Thread.sleep(1000); + } + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java index 10888dce1b4..5b4a1c7e663 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java @@ -29,7 +29,8 @@ * vm.gc != "Epsilon" & * vm.flavor == "server" & * !vm.emulatedClient & - * (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) + * (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) & + * vm.compMode == "Xmixed" * @library /test/lib /test/hotspot/jtreg * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 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 142a30f34a9..07a6a03f2a6 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +38,13 @@ import java.util.regex.Pattern; /* * @test * @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler1.enabled & vm.compiler2.enabled & vm.flagless - * @summary Test IR matcher with different default IR node regexes. Use -DPrintIREncoding. + * @summary Test IR matcher with different default IR node regexes. Use -DPrintApplicableIRRules. * Normally, the framework should be called with driver. * @library /test/lib /testlibrary_tests / * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=240 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -DPrintIREncoding=true ir_framework.tests.TestIRMatching + * -XX:+WhiteBoxAPI -DPrintApplicableIRRules=true ir_framework.tests.TestIRMatching */ public class TestIRMatching { @@ -440,7 +440,8 @@ public class TestIRMatching { } } if (!output.contains(builder.toString())) { - addException(new RuntimeException("Could not find encoding: \"" + builder + System.lineSeparator())); + addException(new RuntimeException("Could not find line in Applicable IR Rules: \"" + builder + + System.lineSeparator())); } } } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java index fe21dce73b5..70e4c463c55 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +70,7 @@ public class TestPhaseIRMatching { TestVMProcess testVMProcess = new TestVMProcess(testVMFlags, testClass, null, -1, false, false); TestClassParser testClassParser = new TestClassParser(testClass, false); Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), - testVMProcess.getIrEncoding()); + testVMProcess.getApplicableIRRules()); MatchResult result = testClassMatchable.match(); List expectedFails = new ExpectedFailsBuilder().build(testClass); List foundFailures = new FailureBuilder().build(result); diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java index 8f8cfdcd541..1fd550d3571 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, but this number is less than the JVM * limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -57,10 +56,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xlog:gc* * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes @@ -79,6 +81,7 @@ import nsk.share.TestFailure; import nsk.share.gc.*; import nsk.share.*; +import jdk.test.whitebox.WhiteBox; public class large001 extends ThreadedGCTest { @@ -146,8 +149,8 @@ public class large001 extends ThreadedGCTest { List refs = new ArrayList(depth); addObjRef(loadedClassInstance, loadedClass, depth, refs); - // Drop all references to the class and try to unload it - Algorithms.eatMemory(getExecutionController()); + // Keep all references to the class and try to unload it + WhiteBox.getWhiteBox().fullGC(); log.debug(id + ": Testing non-null after GC force for: " + name); if (loadedClass == null || loadedClassInstance == null) { throw new Exception("Null class"); @@ -158,21 +161,14 @@ public class large001 extends ThreadedGCTest { throw new Exception("Unexpected null reference"); } } + // Drop all references to the class and try to unload it refs = null; loadedClass = null; loadedClassInstance = null; log.debug(id + ": Unloading class: " + name); - boolean result = unloader.unloadClass(getExecutionController()); - log.debug(id + ": Result of uloading " - + "class " + name + ": " + result); - } - } catch (OutOfMemoryError oome) { - // just skip if we eat memory in several threads... - // rethrow in the case of one thread - if (runParams.getNumberOfThreads() == 1) { - throw oome; + WhiteBox.getWhiteBox().fullGC(); } } catch (Throwable t) { throw new TestFailure("Unexpected exception: ", t); diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java index c207b80c059..834a5d71822 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +47,8 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, and the number of fields is more than * the JVM limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -58,10 +57,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes * -isOverLimitFields true diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java index fd7e1e5e8dd..d094776cb5d 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +47,8 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, but this number is less than the JVM * limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -62,10 +61,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes * -isOverLimitFields false diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java index 2301daba8d3..021170d7d7a 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +47,8 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, but this number is less than the JVM * limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -62,10 +61,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes * -isOverLimitFields true diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java index abf91f48dea..6ad629aa84e 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +47,8 @@ * generated by nsk.share.gc.Generator (see its javadoc for more details). * Each class has a huge number of fields, but this number is less than the JVM * limitation. - * The test loads the classes with nsk.share.gc.GCClassUnloader class that - * extends nsk.share.ClassUnloader and has a bit different algorith of eating - * heap. As soon as a class is loaded, the test creates an instance of + * The test loads the classes with nsk.share.gc.GCClassUnloader class. + * As soon as a class is loaded, the test creates an instance of * it - allocates an object of that type. Then it drops references to the * class and to the instance and tries to unload the class. The test does not * expect any exceptions to be thrown. @@ -62,10 +61,13 @@ * /test/lib * * @comment generate and compile nsk.share.gc.newclass.* classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.gc.GenClassesBuilder * * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes * -isOverLimitFields true diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java index 20584002f6e..efec917716a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ClassObjectReference.reflectedType.reflectype002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/className/classname001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/className/classname001/TestDescription.java index c967382ccfd..8f906d4d6b2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/className/classname001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/className/classname001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +42,7 @@ * debugger and debugee communicates with special commands. * The debugger forces debuggee to load checked class, creates and * enables ClassUnloadRequest. Next, debugger forces debuggee to - * unload class, using memory stressing techique, and waits for + * unload class, using whitebox full GC techique, and waits for * ClassUnloadEvent. * If expected ClassUnloadEvent occurs, debugger tests method * ClassUnloadEvent.className() and verifies that this event @@ -81,6 +81,8 @@ * nsk.jdi.ClassUnloadEvent.className.classname001a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -92,6 +94,6 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/classSignature/signature001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/classSignature/signature001/TestDescription.java index c83d6cdf0f3..6974e7077df 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/classSignature/signature001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadEvent/classSignature/signature001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * debugger and debugee communicates with special commands. * The debugger forces debugge to load checked classes, creates and * enables ClassUnloadRequest. Next, debugger forces debuggee to - * unload classes, using memory stressing techique, and waits for + * unload classes, using whitebox full GC techique, and waits for * ClassUnloadEvent. * If each expected ClassUnloadEvent occurs, debugger tests method * ClassUnloadEvent.classSignature() and verifies that this event @@ -87,6 +87,8 @@ * nsk.jdi.ClassUnloadEvent.classSignature.signature001a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -98,6 +100,6 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassExclusionFilter/exclfilter001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassExclusionFilter/exclfilter001/TestDescription.java index ad14def18dc..d449ed04f91 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassExclusionFilter/exclfilter001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassExclusionFilter/exclfilter001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,6 +67,8 @@ * nsk.jdi.ClassUnloadRequest.addClassExclusionFilter.exclfilter001a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -77,6 +79,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassFilter/filter001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassFilter/filter001/TestDescription.java index 6a388fbaea9..1783e44fa43 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassFilter/filter001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassUnloadRequest/addClassFilter/filter001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +65,8 @@ * nsk.jdi.ClassUnloadRequest.addClassFilter.filter001a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -75,6 +77,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java index 25196c3ae9b..053a6ff34c5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.allFields.allfields003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java index 149de042248..a0e8bd2b7f1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.allMethods.allmethods003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java index a639fe76ad8..ab751a1f29c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.classObject.classobj002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java index 1ccd1358c1c..e1c25e9dbdd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.equals.equals002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java index af68db9d869..703bb6c54aa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.failedToInitialize.failedtoinit002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java index bbd8998d3a1..fa5104cad55 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.fieldByName.fieldbyname003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java index d6379dfbdbf..ab6af3a98e1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.fields.fields003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java index f7a960746d9..693171c9dfe 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.hashCode.hashcode002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java index 6f9c0d5b18e..b61c14d3d4b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.isAbstract.isabstract002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java index c484851c178..c2b1eac7c1e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.isInitialized.isinit002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java index 867b7c45e81..9030c57a727 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.isPrepared.isprepared002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java index 5f638386da8..a766e7476f6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +57,8 @@ * nsk.jdi.ReferenceType.isVerified.isverified002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -67,6 +69,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java index df70528ffd9..5a37d7e66a4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @comment compile loadclassXX to bin/loadclassXX * @run driver nsk.share.ExtraClassesBuilder * loadclass - * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver * nsk.jdi.ReferenceType.methods.methods003 * -verbose @@ -65,6 +66,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java index fae4c67e986..6f70f225a14 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.methodsByName_s.methbyname_s003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java index 5d21a5c868f..baf8931a636 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +57,8 @@ * @comment compile loadclassXX to bin/loadclassXX * @run driver nsk.share.ExtraClassesBuilder * loadclass + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * * @run driver * nsk.jdi.ReferenceType.methodsByName_ss.methbyname_ss003 @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java index 91c37d75710..927e07929b4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.name.name002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java index 74427e9a8bc..543272a52f0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.sourceName.sourcename002a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java index db4ba02e457..f349deaad85 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.visibleFields.visibfield003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java index 11c4c3566bb..c6de37e2939 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ * nsk.jdi.ReferenceType.visibleMethods.visibmethod003a * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * @@ -65,6 +67,7 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" ./bin + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts} -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI" + * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java index f2150775916..4f4e83188b4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @build nsk.jdi.VirtualMachine.instanceCounts.instancecounts003.instancecounts003 * nsk.share.jdi.TestClass1 * nsk.share.jdi.TestInterfaceImplementer1 + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver * nsk.jdi.VirtualMachine.instanceCounts.instancecounts003.instancecounts003 * -verbose @@ -55,7 +57,9 @@ * -waittime=5 * -debugee.vmkind=java * -transport.address=dynamic - * -debugee.vmkeys="-Xmx256M ${test.vm.opts} ${test.java.opts}" + * -debugee.vmkeys="-Xmx256M ${test.vm.opts} ${test.java.opts} + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI" * -testClassPath ${test.class.path} */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001.java index e03c4ff4be2..09fdb1ae3f7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001.java @@ -47,7 +47,7 @@ public class compmethunload001 { private final static String CLS_TO_BE_UNLOADED = "nsk.jvmti.CompiledMethodUnload.compmethunload001u"; - private final static int MAX_ITERATIONS = 5; + private final static int MAX_ITERATIONS = 10; static { try { @@ -95,7 +95,6 @@ public class compmethunload001 { boolean clsUnloaded = clsUnLoader.unloadClass(); clsUnLoader = null; - System.gc(); } private int runThis(String argv[], PrintStream out) throws Exception { @@ -110,12 +109,13 @@ public class compmethunload001 { int num = unloaded(); int iter = 0; while (num == 0) { - System.gc(); - num = unloaded(); - iter++; - if (iter > MAX_ITERATIONS) { - throw new Failure("PRODUCT BUG: class was not unloaded in " + MAX_ITERATIONS); - } + // The unload is delayed because it happens async + Thread.sleep(1000); + num = unloaded(); + iter++; + if (iter > MAX_ITERATIONS) { + throw new Failure("PRODUCT BUG: class was not unloaded in " + MAX_ITERATIONS); + } } System.out.println("Number of unloaded events " + num + " number of iterations " + iter); return check(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001/TestDescription.java index 975f0fdee28..b3e43bf7d03 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/CompiledMethodUnload/compmethunload001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +46,14 @@ * @build nsk.jvmti.CompiledMethodUnload.compmethunload001 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:compmethunload001=-waittime=5 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.CompiledMethodUnload.compmethunload001 * ./bin */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ObjectFree/objfree001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ObjectFree/objfree001/TestDescription.java index 8da18b646c7..c7f5376e53c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ObjectFree/objfree001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ObjectFree/objfree001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +51,15 @@ * @build nsk.jvmti.ObjectFree.objfree001 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:objfree001=-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.ObjectFree.objfree001 * ./bin 5 ./bin */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/TestDescription.java index d3179b3c2c0..c32abdb635b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +71,15 @@ * @build nsk.jvmti.scenarios.events.EM02.em02t003 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:em02t003=-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.scenarios.events.EM02.em02t003 * ./bin/loadclass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/TestDescription.java index 5e8b186fe9d..35fc4ceacdb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +64,15 @@ * @build nsk.jvmti.scenarios.events.EM02.em02t005 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:em02t005=-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.scenarios.events.EM02.em02t005 * ./bin/loadclass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/TestDescription.java index aacc48a1e94..dea19222973 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +57,15 @@ * @build nsk.jvmti.scenarios.events.EM07.em07t002 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:em07t002=attempts=2,-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.scenarios.events.EM07.em07t002 * ./bin/loadclass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java index 0e63411b94b..76798c229f3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +55,15 @@ * @build nsk.jvmti.scenarios.extension.EX03.ex03t001 * * @comment compile loadclassXX to bin/loadclassXX + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.share.ExtraClassesBuilder * loadclass * * @run main/othervm/native * -agentlib:ex03t001=-waittime=5 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.jvmti.scenarios.extension.EX03.ex03t001 * ./bin/loadclass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002.cpp index 52459a7994f..8205729e4ef 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,7 +113,7 @@ static int prepare(JNIEnv* jni) { /** Agent algorithm. */ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { - jint dummy; + jint dummy = 0; if (!nsk_jvmti_waitForSync(timeout)) return; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002a.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002a.cpp index 7f716d009ce..f2cff01948b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002a.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA04/ma04t002/ma04t002a.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,7 +113,7 @@ static int prepare(JNIEnv* jni) { /** Agent algorithm. */ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { - jint dummy; + jint dummy = 0; if (!nsk_jvmti_waitForSync(timeout)) return; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load001/TestDescription.java index e93d0052423..979f51007a2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +43,14 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java index 563eb7500a0..e1dcaaf6946 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +46,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java index d972a74492c..41ffed813d1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -56,4 +59,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load004/TestDescription.java index 7789d6b70ce..b0470cca572 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +47,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -singleClassloaderClass * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load005/TestDescription.java index b6eba9ca652..d5be1a61e8a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -54,4 +57,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load006/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load006/TestDescription.java index af8f67362bf..eff574f05a2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load006/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load006/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -55,4 +58,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java index f8674cdbd21..ecd7e495fb9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +46,14 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=360 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java index f306fda9e02..9ebc7be7a72 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +44,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=420 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java index 50f8116f7c9..5355064e57a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=420 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -54,4 +57,3 @@ * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java index 4f477035cd2..fe0ec8c9b62 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +46,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -singleClassloaderClass * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java index 110f270daff..a5a1a5ae2a8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=360 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -54,4 +57,3 @@ * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java index 52c9d3e8ae7..ac3f8217a0d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.load001 * classes * -testMode=server @@ -55,4 +58,3 @@ * -loadableClassCount=100 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload001/TestDescription.java index cab8b333848..9690240caa5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +46,13 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload002/TestDescription.java index cf611e5eb05..52395f92b0c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +46,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java index 6c8d9f61e36..7e24f92dafd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -56,4 +59,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload004/TestDescription.java index 8f8e46e40be..8dedf5c1f61 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +47,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -singleClassloaderClass * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload005/TestDescription.java index 73aa31b3ff3..e4236d40e58 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -54,4 +57,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload006/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload006/TestDescription.java index 1b3d309a7fd..ef6e3d996d9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload006/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload006/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +44,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -55,4 +58,3 @@ * -loadableClassCount=1 * -loadersCount=100 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java index 62eaaa6c40a..cbe155bc77e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +48,14 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload008/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload008/TestDescription.java index f87f913b769..41894adaed7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload008/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload008/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +46,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java index 27c19980411..5999a8c7f7c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -56,4 +59,3 @@ * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload010/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload010/TestDescription.java index afc3cbb026c..683bca7ab93 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload010/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload010/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +48,15 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -singleClassloaderClass * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload011/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload011/TestDescription.java index 037d4c2affe..26227644431 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload011/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload011/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -56,4 +59,3 @@ * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload012/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload012/TestDescription.java index 256b0f91d1f..446db1d6e28 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload012/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload012/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 @@ * @library /vmTestbase * /test/lib * @comment generate and compile LoadableClassXXX classes + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver nsk.monitoring.stress.classload.GenClassesBuilder * @run main/othervm * -XX:-UseGCOverheadLimit + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * nsk.monitoring.stress.classload.unload001 * classes * -testMode=server @@ -57,4 +60,3 @@ * -loadableClassCount=100 * -loadersCount=12 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java index e3b6693657c..94b086f5757 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +33,14 @@ import java.util.*; import nsk.share.gc.gp.*; import nsk.share.test.ExecutionController; import nsk.share.test.Stresser; +import jdk.test.whitebox.WhiteBox; /** * The ClassUnloader class allows to force VM to unload class(es) - * using memory stressing technique. + * using WhiteBox.fullGC technique. * - *

The method unloadClass() is provided which eats memory - * to enforce GC to cleanup the heap. So, if all references to a class + *

The method unloadClass() is provided which calls + * WhiteBox.fullGC to cleanup the heap. So, if all references to a class * and its loader are canceled, this may result in unloading the class. * *

ClassUnloader mainly intends to unload a class which was loaded @@ -228,24 +229,24 @@ public class ClassUnloader { /** * Forces GC to unload previously loaded classes by cleaning all references - * to class loader with its loaded classes and eating memory. + * to class loader with its loaded classes. * * @return true if classes unloading has been detected or false otherwise * * @throws Failure if exception other than OutOfMemoryError - * is thrown while eating memory + * is thrown while triggering full GC * - * @see #eatMemory() + * @see WhiteBox.getWhiteBox().fullGC() */ - public boolean unloadClass(ExecutionController stresser) { + public boolean unloadClass() { // free references to class and class loader to be able for collecting by GC classObjects.removeAllElements(); customClassLoader = null; - // force class unloading by eating memory pool - eatMemory(stresser); + // force class unloading by triggering full GC + WhiteBox.getWhiteBox().fullGC(); // force GC to unload marked class loader and its classes if (isClassLoaderReclaimed()) { @@ -256,34 +257,4 @@ public class ClassUnloader { // class loader has not been reclaimed return false; } - - public boolean unloadClass() { - Stresser stresser = new Stresser() { - - @Override - public boolean continueExecution() { - return true; - } - - }; - return unloadClass(stresser); - } - - // Stresses memory by allocating arrays of bytes. - public static void eatMemory(ExecutionController stresser) { - GarbageUtils.eatMemory(stresser, 50, 1024, 2); - } - - // Stresses memory by allocating arrays of bytes. - public static void eatMemory() { - Stresser stresser = new Stresser() { - - @Override - public boolean continueExecution() { - return true; - } - - }; - eatMemory(stresser); - } } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 9cfc23ea8da..291b2163b0d 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -710,7 +710,6 @@ jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows- # jdk_jfr jdk/jfr/event/compiler/TestCodeSweeper.java 8338127 generic-all -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 diff --git a/test/jdk/build/CheckFiles.java b/test/jdk/build/CheckFiles.java index 412e66ebf01..eb903c0a224 100644 --- a/test/jdk/build/CheckFiles.java +++ b/test/jdk/build/CheckFiles.java @@ -60,6 +60,8 @@ public class CheckFiles { System.out.println("Main directory to scan:" + mainDirToScan); Path binDir = mainDirToScan.resolve("bin"); Path libDir = mainDirToScan.resolve("lib"); + Path includeDir = mainDirToScan.resolve("include"); + Path jmodsDir = mainDirToScan.resolve("jmods"); System.out.println("Bin directory to scan:" + binDir); ArrayList allowedEndingsBinDir = new ArrayList<>(); @@ -108,13 +110,44 @@ public class CheckFiles { } boolean libDirRes = scanFiles(libDir, allowedEndingsLibDir); - if (!binDirRes) { + if (binDirRes) { + System.out.println("Bin directory scan successful."); + } else { throw new Error("bin dir scan failed"); } - if (!libDirRes) { + if (libDirRes) { + System.out.println("Lib directory scan successful."); + } else { throw new Error("lib dir scan failed"); } + + if (Files.isDirectory(includeDir)) { + System.out.println("Include directory to scan:" + includeDir); + ArrayList allowedEndingsIncludeDir = new ArrayList<>(); + allowedEndingsIncludeDir.add(".h"); + allowedEndingsIncludeDir.add(".hpp"); + boolean includeDirRes = scanFiles(includeDir, allowedEndingsIncludeDir); + if (includeDirRes) { + System.out.println("Include directory scan successful."); + } else { + throw new Error("include dir scan failed"); + } + } + + // when enabling "JEP 493: Linking Run-Time Images without JMODs" we do not + // have the jmods folder at all, so first test the presence of the folder + if (Files.isDirectory(jmodsDir)) { + System.out.println("Jmods directory to scan:" + jmodsDir); + ArrayList allowedEndingsJmodsDir = new ArrayList<>(); + allowedEndingsJmodsDir.add(".jmod"); + boolean jmodsDirRes = scanFiles(jmodsDir, allowedEndingsJmodsDir); + if (jmodsDirRes) { + System.out.println("Jmods directory scan successful."); + } else { + throw new Error("jmods dir scan failed"); + } + } } private static boolean scanFiles(Path root, ArrayList allowedEndings) throws IOException { diff --git a/test/jdk/com/sun/tools/attach/TestWithoutDumpableProcess.java b/test/jdk/com/sun/tools/attach/TestWithoutDumpableProcess.java new file mode 100644 index 00000000000..be9d0c8790c --- /dev/null +++ b/test/jdk/com/sun/tools/attach/TestWithoutDumpableProcess.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, NTT DATA + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; + +import com.sun.tools.attach.VirtualMachine; + +import jdk.test.lib.Asserts; +import jdk.test.lib.thread.ProcessThread; +import jdk.test.lib.process.ProcessTools; + +/* + * @test + * @bug 8226919 8373867 + * @summary Test to make sure attach target process which is not dumpable. + * @library /test/lib + * @modules jdk.attach + * @requires os.family == "linux" + * + * @run main/timeout=200 TestWithoutDumpableProcess + */ +public class TestWithoutDumpableProcess { + + private static final String EXPECTED_PROP_KEY = "attach.test"; + private static final String EXPECTED_PROP_VALUE = "true"; + + public static class Debuggee { + + // Disable dumpable attribute via prctl(2) + private static void disableDumpable() throws Throwable { + var linker = Linker.nativeLinker(); + var prctl = linker.downcallHandle(linker.defaultLookup().findOrThrow("prctl"), + FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG), + Linker.Option.firstVariadicArg(1), Linker.Option.captureCallState("errno")); + var errnoSeg = Arena.global().allocate(Linker.Option.captureStateLayout()); + final int PR_SET_DUMPABLE = 4; // from linux/prctl.h + + int ret = (int)prctl.invoke(errnoSeg, PR_SET_DUMPABLE, 0L); + if (ret == -1){ + var hndErrno = Linker.Option + .captureStateLayout() + .varHandle(MemoryLayout.PathElement.groupElement("errno")); + int errno = (int)hndErrno.get(errnoSeg, 0L); + throw new RuntimeException("prctl: errno=" + errno); + } + } + + public static void main(String[] args) throws Throwable { + disableDumpable(); + IO.println(Application.READY_MSG); + + while (IO.readln().equals(Application.SHUTDOWN_MSG)); + } + + public static ProcessThread start() { + var args = new String[]{ + "--enable-native-access=ALL-UNNAMED", + String.format("-D%s=%s", EXPECTED_PROP_KEY, EXPECTED_PROP_VALUE), Debuggee.class.getName() + }; + var pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); + var pt = new ProcessThread("runApplication", Application.READY_MSG::equals, pb); + pt.start(); + return pt; + } + + } + + public static void main(String[] args) throws Exception { + var pt = Debuggee.start(); + var vm = VirtualMachine.attach(Long.toString(pt.getPid())); + var val = vm.getSystemProperties().getProperty(EXPECTED_PROP_KEY); + + Asserts.assertNotNull(val, "Expected sysprop not found"); + Asserts.assertEquals(val, "true", "Unexpected sysprop value"); + } + +} diff --git a/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java b/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java index 19bc6d95c39..9694043d1bb 100644 --- a/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java +++ b/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +29,14 @@ * @run main XBMDecoderTest */ +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.PrintStream; +import java.util.Arrays; import javax.swing.ImageIcon; public class XBMDecoderTest { @@ -57,21 +61,39 @@ public class XBMDecoderTest { ImageIcon icon = new ImageIcon(fis.readAllBytes()); boolean isErrEmpty = errContent.toString().isEmpty(); + if (!isErrEmpty) { System.out.println("Expected ImageFormatException occurred."); System.out.print(errContent); } - if (validCase && !isErrEmpty) { throw new RuntimeException("Test failed: Error stream not empty"); - } else if (!validCase && isErrEmpty) { + } else if (!validCase && isErrEmpty && hasPixelData(icon.getImage())) { throw new RuntimeException("Test failed: ImageFormatException" + " expected but not thrown"); } + if (validCase && !hasPixelData(icon.getImage())) { + throw new RuntimeException("Test failed: the parsed image " + + "does not contain any pixel data"); + } System.out.println("PASSED\n"); } finally { System.setErr(originalErr); } } } + + private static boolean hasPixelData(Image img) { + int w = img.getWidth(null); + int h = img.getHeight(null); + BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = bi.createGraphics(); + g.drawImage(img, 0, 0, null); + g.dispose(); + int[] pixels = bi.getRGB(0, 0, w, h, null, 0, w); + if (Arrays.stream(pixels).allMatch(i -> i == 0)) { + return false; + } + return true; + } } diff --git a/test/jdk/java/awt/image/XBMDecoder/invalid_empty.xbm b/test/jdk/java/awt/image/XBMDecoder/invalid_empty.xbm new file mode 100644 index 00000000000..5cfb8e21cf8 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/invalid_empty.xbm @@ -0,0 +1,6 @@ +#define test_width 16 +#define test_height 3 +#define ht_x 1 +#define ht_y 2 +static unsigned char test_bits[] = { +}; diff --git a/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm b/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm index c6f819582d0..1286eee1d9b 100644 --- a/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm +++ b/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm @@ -1,3 +1,3 @@ -#define k_wt 16 -#define k_ht 1 +#define k_width 16 +#define k_height 1 k[] = { 0x10, 1234567890}; diff --git a/test/jdk/java/awt/image/XBMDecoder/invalid_plus.xbm b/test/jdk/java/awt/image/XBMDecoder/invalid_plus.xbm new file mode 100644 index 00000000000..714907084f2 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/invalid_plus.xbm @@ -0,0 +1,3 @@ +#define test_width 16 +#define test_height 2 +static unsigned char test_bits[] = { 0x13, 0x11, 0xAB+, 0xff }; \ No newline at end of file diff --git a/test/jdk/java/awt/image/XBMDecoder/valid_multiline.xbm b/test/jdk/java/awt/image/XBMDecoder/valid_multiline.xbm new file mode 100644 index 00000000000..e24bc10e9b0 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/valid_multiline.xbm @@ -0,0 +1,8 @@ +#define test_width 16 +#define test_height 3 +#define ht_x 1 +#define ht_y 2 +static unsigned char test_bits[] = { +0x20, 0x10, +0x25, 0x01, +0xAC, 0xab }; diff --git a/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java b/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java index 7b91222d737..2b3f1c6aa45 100644 --- a/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.java +++ b/test/jdk/java/io/Serializable/GetField/ReadFieldsCNF.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 @@ -27,8 +27,8 @@ * @summary Verify that ObjectInputStream ReadFields correctly reports ClassNotFoundException * while getting the field value. The test uses Vector that calls ReadFields from its readObject. * @library /test/lib - * @run testng ReadFieldsCNF - * @run testng/othervm -Djdk.serialGetFieldCnfeReturnsNull=true ReadFieldsCNF + * @run junit ReadFieldsCNF + * @run junit/othervm -Djdk.serialGetFieldCnfeReturnsNull=true ReadFieldsCNF */ import java.io.ByteArrayInputStream; @@ -41,12 +41,12 @@ import java.io.StreamCorruptedException; import java.nio.charset.StandardCharsets; import java.util.Vector; -import org.testng.annotations.Test; -import org.testng.Assert; - import jdk.test.lib.hexdump.HexPrinter; import jdk.test.lib.hexdump.ObjectStreamPrinter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + public class ReadFieldsCNF { private static final boolean GETFIELD_CNFE_RETURNS_NULL = @@ -58,7 +58,7 @@ public class ReadFieldsCNF { * @throws IOException If any other exception occurs */ @Test - private static void testVectorWithRole() throws IOException { + void testVectorWithRole() throws IOException { System.out.println("Property GETFIELD_CNFE_RETURNS_NULL: " + GETFIELD_CNFE_RETURNS_NULL); Role role = new Role(); @@ -75,7 +75,7 @@ public class ReadFieldsCNF { System.out.printf("Role offset: %d (0x%x) : %s%n", off, off, Role.class.getName()); if (off < 0) { HexPrinter.simple().formatter(ObjectStreamPrinter.formatter()).format(bytes); - Assert.fail("classname not found"); + Assertions.fail("classname not found"); } bytes[off] = (byte) 'X'; // replace R with X -> Class not found @@ -85,18 +85,18 @@ public class ReadFieldsCNF { try { Object obj = in.readObject(); System.out.println("Read: " + obj); - Assert.fail("Should not reach here, an exception should always occur"); + Assertions.fail("Should not reach here, an exception should always occur"); } catch (ClassNotFoundException cnfe) { // Expected ClassNotFoundException String expected = "XeadFieldsCNF$Role"; - Assert.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); + Assertions.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); if (GETFIELD_CNFE_RETURNS_NULL) { - Assert.fail("Expected IOException got ClassNotFoundException", cnfe); + Assertions.fail("Expected IOException got ClassNotFoundException", cnfe); } System.out.println("Normal: OIS.readObject: " + cnfe); } catch (StreamCorruptedException ioe) { if (!GETFIELD_CNFE_RETURNS_NULL) { - Assert.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); + Assertions.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); } System.out.println("Normal: " + ioe); } @@ -108,7 +108,7 @@ public class ReadFieldsCNF { * @throws IOException If any other exception occurs */ @Test - private static void testHolderWithRole() throws IOException { + void testHolderWithRole() throws IOException { System.out.println("Property GETFIELD_CNFE_RETURNS_NULL: " + GETFIELD_CNFE_RETURNS_NULL); Role role = new Role(); Holder holder = new Holder(role); @@ -123,7 +123,7 @@ public class ReadFieldsCNF { System.out.printf("Role offset: %d (0x%x)%n", off, off); if (off < 0) { HexPrinter.simple().formatter(ObjectStreamPrinter.formatter()).format(bytes); - Assert.fail("classname found at index: " + off + " (0x" + Integer.toHexString(off) + ")"); + Assertions.fail("classname found at index: " + off + " (0x" + Integer.toHexString(off) + ")"); } bytes[off] = (byte) 'X'; // replace R with X -> Class not found @@ -133,15 +133,15 @@ public class ReadFieldsCNF { try { Holder obj = (Holder)in.readObject(); System.out.println("Read: " + obj); - Assert.fail("Should not reach here, an exception should always occur"); + Assertions.fail("Should not reach here, an exception should always occur"); } catch (ClassNotFoundException cnfe) { // Expected ClassNotFoundException String expected = "XeadFieldsCNF$Role"; - Assert.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); + Assertions.assertEquals(expected, cnfe.getMessage(), "Wrong classname"); System.out.println("Normal: OIS.readObject: " + cnfe); } catch (StreamCorruptedException ioe) { if (!GETFIELD_CNFE_RETURNS_NULL) { - Assert.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); + Assertions.fail("Expected ClassNotFoundException got StreamCorruptedException ", ioe); } System.out.println("Normal: " + ioe); } diff --git a/test/jdk/java/io/Serializable/class/NonSerializableTest.java b/test/jdk/java/io/Serializable/class/NonSerializableTest.java index fa81b3e3ce7..2a36380aae7 100644 --- a/test/jdk/java/io/Serializable/class/NonSerializableTest.java +++ b/test/jdk/java/io/Serializable/class/NonSerializableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,79 +32,84 @@ * jdk.test.lib.JDKToolLauncher * jdk.test.lib.Platform * jdk.test.lib.process.* - * @run testng/timeout=300 NonSerializableTest + * @run junit/timeout=300 NonSerializableTest * @summary Enable serialize of nonSerializable Class descriptor. */ import java.nio.file.Paths; import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; -import org.testng.annotations.DataProvider; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.process.ProcessTools; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class NonSerializableTest { - @BeforeClass - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { boolean b = CompilerUtils.compile( Paths.get(System.getProperty("test.src"), "TestEntry.java"), Paths.get(System.getProperty("user.dir"))); assertTrue(b, "Compilation failed"); } - @DataProvider - public Object[][] provider() { - return new String[][][] { + // Test cases to compile and run + public static Stream> provider() { + return Stream.of( // Write NonSerial1, Read NonSerial1 - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-d"}}, + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-d"), // Write NonSerial1, Read NonSerial2 - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"NonSerialA_2", "-cp", ".", "TestEntry", "-d"}}, + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("NonSerialA_2", "-cp", ".", "TestEntry", "-d"), // Write NonSerial1, Read Serial1 - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_1", "-cp", ".", "TestEntry", "-d"}}, + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_1", "-cp", ".", "TestEntry", "-d"), // Write Serial1, Read NonSerial1 - {{"SerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"NonSerialA_1", "-cp", ".", "TestEntry", "-doe"}}, + List.of("SerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("NonSerialA_1", "-cp", ".", "TestEntry", "-doe"), // Write Serial1, Read Serial2 - {{"SerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_2", "-cp", ".", "TestEntry", "-d"}}, + List.of("SerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_2", "-cp", ".", "TestEntry", "-d"), // Write Serial2, Read Serial1 - {{"SerialA_2", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_1", "-cp", ".", "TestEntry", "-d"}}, + List.of("SerialA_2", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_1", "-cp", ".", "TestEntry", "-d"), // Write Serial1, Read Serial3 - {{"SerialA_1", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_3", "-cp", ".", "TestEntry", "-de"}}, + List.of("SerialA_1", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_3", "-cp", ".", "TestEntry", "-de"), // Write Serial3, Read Serial1 - {{"SerialA_3", "-cp", ".", "TestEntry", "-s", "A"}}, - {{"SerialA_1", "-cp", ".", "TestEntry", "-de"}}, - }; + List.of("SerialA_3", "-cp", ".", "TestEntry", "-s", "A"), + List.of("SerialA_1", "-cp", ".", "TestEntry", "-de")); } - @Test(dataProvider="provider") - public void test(String[] args) throws Exception { + @ParameterizedTest + @MethodSource("provider") + public void test(List argList) throws Exception { + String[] args = argList.toArray(new String[0]); boolean b = CompilerUtils.compile(Paths.get(System.getProperty("test.src"), args[0]), Paths.get(System.getProperty("user.dir"))); assertTrue(b, "Compilation failed"); - String params[] = Arrays.copyOfRange(args, 1, args.length); + String[] params = Arrays.copyOfRange(args, 1, args.length); ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(params); - Process p = ProcessTools.startProcess("Serializable Test", pb); - int exitValue = p.waitFor(); - assertEquals(exitValue, 0, "Test failed"); + try (Process p = ProcessTools.startProcess("Serializable Test", pb)) { + int exitValue = p.waitFor(); + assertEquals(0, exitValue, "Test failed"); + } } } diff --git a/test/jdk/java/io/Serializable/records/RecordClassTest.java b/test/jdk/java/io/Serializable/records/RecordClassTest.java index ba920ce92e5..951dd2f44dc 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, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; +import java.io.Serial; import java.io.Serializable; import static java.lang.System.out; @@ -49,12 +50,12 @@ 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 { } record Bar (int x) implements Serializable { + @Serial private static final long serialVersionUID = 987654321L; } @@ -70,6 +71,7 @@ public class RecordClassTest { } record Wibble () implements ThrowingExternalizable { + @Serial private static final long serialVersionUID = 12345678L; } @@ -77,7 +79,7 @@ public class RecordClassTest { record Wubble (Wobble wobble, Wibble wibble, String s) implements ThrowingExternalizable { } - public Object[][] recordClasses() { + public static Object[][] recordClasses() { return new Object[][] { new Object[] { Foo.class , 0L }, new Object[] { Bar.class , 987654321L }, @@ -124,7 +126,7 @@ public class RecordClassTest { record NotSerializable3(T t) { } - public Object[][] notSerRecordClasses() { + public static Object[][] notSerRecordClasses() { return new Object[][] { new Object[] { NotSerializable1.class }, new Object[] { NotSerializable2.class }, diff --git a/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java b/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java index 2c133392dcb..f313e8a44a3 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, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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.io.DataOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serial; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -44,18 +45,18 @@ import static java.lang.System.out; 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 { + @Serial private static final long serialVersionUID = 1L; } record R2 (int x, int y) implements Serializable { + @Serial private static final long serialVersionUID = 0L; } @@ -64,10 +65,11 @@ public class SerialVersionUIDTest { record R4 (String s) implements Serializable { } record R5 (long l) implements Serializable { + @Serial private static final long serialVersionUID = 5678L; } - public Object[][] recordObjects() { + public static Object[][] recordObjects() { return new Object[][] { new Object[] { new R1(), 1L }, new Object[] { new R2(1, 2), 0L }, @@ -103,7 +105,7 @@ public class SerialVersionUIDTest { assertEquals(expectedUID, dis.readLong()); } - public Object[][] recordClasses() { + public static Object[][] recordClasses() { List list = new ArrayList<>(); List> recordClasses = List.of(R1.class, R2.class, R3.class, R4.class, R5.class); LongStream.of(0L, 1L, 100L, 10_000L, 1_000_000L).forEach(suid -> diff --git a/test/jdk/java/io/Serializable/serialFilter/CheckArrayTest.java b/test/jdk/java/io/Serializable/serialFilter/CheckArrayTest.java index d00c670bd15..2081375ca59 100644 --- a/test/jdk/java/io/Serializable/serialFilter/CheckArrayTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/CheckArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +30,15 @@ import java.io.InvalidClassException; import jdk.internal.access.SharedSecrets; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.testng.Assert; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @build CheckArrayTest SerialFilterTest * @bug 8203368 * @modules java.base/jdk.internal.access - * @run testng CheckArrayTest + * @run junit CheckArrayTest * * @summary Test the SharedSecret access to ObjectInputStream.checkArray works * with overridden subclasses. @@ -53,8 +53,8 @@ import org.testng.Assert; */ public class CheckArrayTest { - @DataProvider(name = "Patterns") - Object[][] patterns() { + // Test patterns for arrays + private static Object[][] patterns() { return new Object[][]{ new Object[]{"maxarray=10", 10, new String[10]}, // successful new Object[]{"maxarray=10", 11, new String[11]}, // exception expected @@ -64,7 +64,8 @@ public class CheckArrayTest { /** * Test SharedSecrets checkArray with unmodified ObjectInputStream. */ - @Test(dataProvider = "Patterns") + @ParameterizedTest + @MethodSource("patterns") public void normalOIS(String pattern, int arraySize, Object[] array) throws IOException { ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); byte[] bytes = SerialFilterTest.writeObjects(array); @@ -75,10 +76,10 @@ public class CheckArrayTest { ois.setObjectInputFilter(filter); SharedSecrets.getJavaObjectInputStreamAccess() .checkArray(ois, array.getClass(), arraySize); - Assert.assertTrue(array.length >= arraySize, + Assertions.assertTrue(array.length >= arraySize, "Should have thrown InvalidClassException due to array size"); } catch (InvalidClassException ice) { - Assert.assertFalse(array.length > arraySize, + Assertions.assertFalse(array.length > arraySize, "Should NOT have thrown InvalidClassException due to array size"); } } @@ -88,7 +89,8 @@ public class CheckArrayTest { * Test SharedSecrets checkArray with an ObjectInputStream subclassed to * handle all input stream functions. */ - @Test(dataProvider = "Patterns") + @ParameterizedTest + @MethodSource("patterns") public void subclassedOIS(String pattern, int arraySize, Object[] array) throws IOException { byte[] bytes = SerialFilterTest.writeObjects(array); try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes); @@ -98,10 +100,10 @@ public class CheckArrayTest { ois.setObjectInputFilter(filter); SharedSecrets.getJavaObjectInputStreamAccess() .checkArray(ois, array.getClass(), arraySize); - Assert.assertTrue(array.length >= arraySize, + Assertions.assertTrue(array.length >= arraySize, "Should have thrown InvalidClassException due to array size"); } catch (InvalidClassException ice) { - Assert.assertFalse(array.length > arraySize, + Assertions.assertFalse(array.length > arraySize, "Should NOT have thrown InvalidClassException due to array size"); } } diff --git a/test/jdk/java/io/Serializable/serialFilter/CheckInputOrderTest.java b/test/jdk/java/io/Serializable/serialFilter/CheckInputOrderTest.java index 0230eb653ce..d824c947ece 100644 --- a/test/jdk/java/io/Serializable/serialFilter/CheckInputOrderTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/CheckInputOrderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,28 +25,28 @@ import java.io.ByteArrayInputStream; import java.io.InvalidClassException; import java.io.ObjectInputFilter; import java.io.ObjectInputStream; +import java.io.Serial; import java.io.Serializable; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @build CheckInputOrderTest SerialFilterTest - * @run testng/othervm CheckInputOrderTest + * @run junit/othervm CheckInputOrderTest * * @summary Test that when both global filter and specific filter are set, * global filter will not affect specific filter. */ public class CheckInputOrderTest implements Serializable { + @Serial private static final long serialVersionUID = 12345678901L; - @DataProvider(name="Patterns") - Object[][] patterns() { + // Test cases for serial filter strings + static Object[][] patterns() { return new Object[][] { new Object[] { SerialFilterTest.genTestObject("maxarray=1", true), "java.**;java.lang.*;java.lang.Long;maxarray=0", false }, new Object[] { SerialFilterTest.genTestObject("maxarray=1", true), "java.**;java.lang.*;java.lang.Long", true }, @@ -75,7 +75,8 @@ public class CheckInputOrderTest implements Serializable { * "global filter reject" + "specific ObjectInputStream filter is empty" => should reject * "global filter reject" + "specific ObjectInputStream filter allow" => should allow */ - @Test(dataProvider="Patterns") + @ParameterizedTest + @MethodSource("patterns") public void testRejectedInGlobal(Object toDeserialized, String pattern, boolean allowed) throws Exception { byte[] bytes = SerialFilterTest.writeObjects(toDeserialized); ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); diff --git a/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java b/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java index 9e38d6c499d..18bbf265e43 100644 --- a/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * questions. */ -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.EOFException; @@ -35,39 +34,40 @@ import java.io.ObjectInputStream; import java.security.Security; import java.util.Objects; -import org.testng.Assert; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @bug 8231422 * @build GlobalFilterTest SerialFilterTest - * @run testng/othervm GlobalFilterTest - * @run testng/othervm -Djdk.serialFilter=java.** + * @run junit/othervm GlobalFilterTest + * @run junit/othervm -Djdk.serialFilter=java.** * -Dexpected-jdk.serialFilter=java.** GlobalFilterTest * @summary Test Global Filters */ -@Test public class GlobalFilterTest { private static final String serialPropName = "jdk.serialFilter"; private static final String badSerialFilter = "java.lang.StringBuffer;!*"; private static final String origSerialFilterProperty = System.setProperty(serialPropName, badSerialFilter); + private static final String EXPECTED_GLOBAL_FILTER = System.getProperty("expected-" + serialPropName, + Security.getProperty(serialPropName)); + + static boolean hasGlobalFilter() { + return EXPECTED_GLOBAL_FILTER != null && !EXPECTED_GLOBAL_FILTER.isEmpty(); + } + /** * DataProvider of patterns and objects derived from the configured process-wide filter. * @return Array of arrays of pattern, object, allowed boolean, and API factory */ - @DataProvider(name="globalPatternElements") - Object[][] globalPatternElements() { - String globalFilter = - System.getProperty("expected-" + serialPropName, - Security.getProperty(serialPropName)); - if (globalFilter == null) { - return new Object[0][]; - } + static Object[][] globalPatternElements() { - String[] patterns = globalFilter.split(";"); + String[] patterns = EXPECTED_GLOBAL_FILTER.split(";"); Object[][] objects = new Object[patterns.length][]; for (int i = 0; i < patterns.length; i++) { @@ -83,7 +83,7 @@ public class GlobalFilterTest { ? SerialFilterTest.genTestObject(pattern, true) : SerialFilterTest.genTestObject(pattern.substring(1), false); - Assert.assertNotNull(o, "fail generation failed"); + Assertions.assertNotNull(o, "fail generation failed"); } objects[i] = new Object[3]; objects[i][0] = pattern; @@ -98,13 +98,13 @@ public class GlobalFilterTest { * and has the toString matching the configured pattern. */ @Test() - static void globalFilter() { + void globalFilter() { ObjectInputFilter filter = ObjectInputFilter.Config.getSerialFilter(); // Check that the System.setProperty(jdk.serialFilter) DOES NOT affect the filter. String asSetSystemProp = System.getProperty(serialPropName, Security.getProperty(serialPropName)); - Assert.assertNotEquals(Objects.toString(filter, null), asSetSystemProp, + Assertions.assertNotEquals(asSetSystemProp, Objects.toString(filter, null), "System.setProperty(\"jdk.serialfilter\", ...) should not change filter: " + asSetSystemProp); @@ -112,7 +112,7 @@ public class GlobalFilterTest { System.getProperty("expected-" + serialPropName, Security.getProperty(serialPropName)); System.out.printf("global pattern: %s, filter: %s%n", pattern, filter); - Assert.assertEquals(Objects.toString(filter, null), pattern, + assertEquals(pattern, Objects.toString(filter, null), "process-wide filter pattern does not match"); } @@ -120,16 +120,15 @@ public class GlobalFilterTest { * If the Global filter is already set, it should always refuse to be * set again. */ - @Test() - @SuppressWarnings("removal") - static void setGlobalFilter() { + @Test + void setGlobalFilter() { ObjectInputFilter filter = new SerialFilterTest.Validator(); ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter(); if (global != null) { // once set, can never be re-set try { ObjectInputFilter.Config.setSerialFilter(filter); - Assert.fail("set only once process-wide filter"); + Assertions.fail("set only once process-wide filter"); } catch (IllegalStateException ise) { // Normal, once set can never be re-set } @@ -141,7 +140,7 @@ public class GlobalFilterTest { try { // Try to set it again, expecting it to throw ObjectInputFilter.Config.setSerialFilter(filter); - Assert.fail("set only once process-wide filter"); + Assertions.fail("set only once process-wide filter"); } catch (IllegalStateException ise) { // Normal case } @@ -154,8 +153,10 @@ public class GlobalFilterTest { * * @param pattern a pattern extracted from the configured global pattern */ - @Test(dataProvider = "globalPatternElements") - static void globalFilterElements(String pattern, boolean allowed,Object obj) { + @ParameterizedTest + @EnabledIf("hasGlobalFilter") + @MethodSource("globalPatternElements") + void globalFilterElements(String pattern, boolean allowed,Object obj) { testGlobalPattern(pattern, obj, allowed); } @@ -177,15 +178,15 @@ public class GlobalFilterTest { } catch (EOFException eof) { // normal completion } catch (ClassNotFoundException cnf) { - Assert.fail("Deserializing", cnf); + Assertions.fail("Deserializing", cnf); } - Assert.assertTrue(allowed, "filter should have thrown an exception"); + assertTrue(allowed, "filter should have thrown an exception"); } catch (IllegalArgumentException iae) { - Assert.fail("bad format pattern", iae); + Assertions.fail("bad format pattern", iae); } catch (InvalidClassException ice) { - Assert.assertFalse(allowed, "filter should not have thrown an exception: " + ice); + Assertions.assertFalse(allowed, "filter should not have thrown an exception: " + ice); } catch (IOException ioe) { - Assert.fail("Unexpected IOException", ioe); + Assertions.fail("Unexpected IOException", ioe); } } } diff --git a/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java b/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java index a017354b103..b924a96c86c 100644 --- a/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/InvalidGlobalFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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.ByteArrayInputStream; import java.io.IOException; @@ -31,18 +28,22 @@ import java.io.ObjectInputFilter; import java.io.ObjectInputStream; import java.util.Map; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* * @test * @bug 8278087 * @summary Test that an invalid pattern value for the jdk.serialFilter system property causes an * exception to be thrown when an attempt is made to use the filter or deserialize. * A subset of invalid filter patterns is tested. - * @run testng/othervm -Djdk.serialFilter=.* InvalidGlobalFilterTest - * @run testng/othervm -Djdk.serialFilter=! InvalidGlobalFilterTest - * @run testng/othervm -Djdk.serialFilter=/ InvalidGlobalFilterTest + * @run junit/othervm -Djdk.serialFilter=.* InvalidGlobalFilterTest + * @run junit/othervm -Djdk.serialFilter=! InvalidGlobalFilterTest + * @run junit/othervm -Djdk.serialFilter=/ InvalidGlobalFilterTest * */ -@Test public class InvalidGlobalFilterTest { private static final String serialPropName = "jdk.serialFilter"; private static final String serialFilter = System.getProperty(serialPropName); @@ -64,13 +65,13 @@ public class InvalidGlobalFilterTest { "java.base/", "Invalid jdk.serialFilter: class or package missing in: \"java.base/\"", "/", "Invalid jdk.serialFilter: module name is missing in: \"/\""); - @DataProvider(name = "MethodsToCall") - private Object[][] cases() { + // Test cases for exceptions + private static Object[][] cases() { return new Object[][] { - {serialFilter, "getSerialFilter", (Assert.ThrowingRunnable) () -> ObjectInputFilter.Config.getSerialFilter()}, - {serialFilter, "setSerialFilter", (Assert.ThrowingRunnable) () -> ObjectInputFilter.Config.setSerialFilter(new NoopFilter())}, - {serialFilter, "new ObjectInputStream(is)", (Assert.ThrowingRunnable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, - {serialFilter, "new OISSubclass()", (Assert.ThrowingRunnable) () -> new OISSubclass()}, + {serialFilter, "getSerialFilter", (Executable) () -> ObjectInputFilter.Config.getSerialFilter()}, + {serialFilter, "setSerialFilter", (Executable) () -> ObjectInputFilter.Config.setSerialFilter(new NoopFilter())}, + {serialFilter, "new ObjectInputStream(is)", (Executable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, + {serialFilter, "new OISSubclass()", (Executable) () -> new OISSubclass()}, }; } @@ -78,18 +79,19 @@ public class InvalidGlobalFilterTest { * Test each method that should throw IllegalStateException based on * the invalid arguments it was launched with. */ - @Test(dataProvider = "MethodsToCall") - public void initFaultTest(String pattern, String method, Assert.ThrowingRunnable runnable) { + @ParameterizedTest + @MethodSource("cases") + public void initFaultTest(String pattern, String method, Executable runnable) { - IllegalStateException ex = Assert.expectThrows(IllegalStateException.class, + IllegalStateException ex = Assertions.assertThrows(IllegalStateException.class, runnable); String expected = invalidMessages.get(serialFilter); if (expected == null) { - Assert.fail("No expected message for filter: " + serialFilter); + Assertions.fail("No expected message for filter: " + serialFilter); } System.out.println(ex.getMessage()); - Assert.assertEquals(ex.getMessage(), expected, "wrong message"); + Assertions.assertEquals(expected, ex.getMessage(), "wrong message"); } private static class NoopFilter implements ObjectInputFilter { diff --git a/test/jdk/java/io/Serializable/serialFilter/MixedFiltersTest.java b/test/jdk/java/io/Serializable/serialFilter/MixedFiltersTest.java index 8e24f27f598..5af5f4d15ed 100644 --- a/test/jdk/java/io/Serializable/serialFilter/MixedFiltersTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/MixedFiltersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,21 @@ import java.io.ByteArrayInputStream; import java.io.InvalidClassException; import java.io.ObjectInputFilter; import java.io.ObjectInputStream; +import java.io.Serial; import java.io.Serializable; import java.security.Security; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @build MixedFiltersTest SerialFilterTest - * @run testng/othervm -Djdk.serialFilter=!java.**;!java.lang.Long;maxdepth=5;maxarray=5;maxbytes=90;maxrefs=5 MixedFiltersTest - * @run testng/othervm -Djdk.serialFilter=java.**;java.lang.Long;maxdepth=1000;maxarray=1000;maxbytes=1000;maxrefs=1000 MixedFiltersTest + * @run junit/othervm -Djdk.serialFilter=!java.**;!java.lang.Long;maxdepth=5;maxarray=5;maxbytes=90;maxrefs=5 MixedFiltersTest + * @run junit/othervm -Djdk.serialFilter=java.**;java.lang.Long;maxdepth=1000;maxarray=1000;maxbytes=1000;maxrefs=1000 MixedFiltersTest * * @summary Test that when both global filter and specific filter are set, * global filter will not affect specific filter. @@ -46,23 +47,17 @@ import static org.testng.Assert.fail; public class MixedFiltersTest implements Serializable { + @Serial private static final long serialVersionUID = 1234567890L; + private static final String JDK_SERIAL_FILTER = System.getProperty("jdk.serialFilter", + Security.getProperty("jdk.serialFilter")); - boolean globalRejected; - - @BeforeClass - public void setup() { - String pattern = System.getProperty("jdk.serialFilter", - Security.getProperty("jdk.serialFilter")); - globalRejected = pattern.startsWith("!"); + private static boolean globalRejected() { + return JDK_SERIAL_FILTER.startsWith("!"); } - @DataProvider(name="RejectedInGlobal") - Object[][] rejectedInGlobal() { - if (!globalRejected) { - return new Object[0][]; - } + static Object[][] rejectedInGlobal() { return new Object[][] { new Object[] { Long.MAX_VALUE, "java.**" }, new Object[] { Long.MAX_VALUE, "java.lang.Long" }, @@ -79,7 +74,9 @@ public class MixedFiltersTest implements Serializable { * "global filter reject" + "specific ObjectInputStream filter is empty" => should reject * "global filter reject" + "specific ObjectInputStream filter allow" => should allow */ - @Test(dataProvider="RejectedInGlobal") + @ParameterizedTest + @EnabledIf("globalRejected") + @MethodSource("rejectedInGlobal") public void testRejectedInGlobal(Object toDeserialized, String pattern) throws Exception { byte[] bytes = SerialFilterTest.writeObjects(toDeserialized); try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes); @@ -96,12 +93,7 @@ public class MixedFiltersTest implements Serializable { } } - @DataProvider(name="AllowedInGlobal") - Object[][] allowedInGlobal() { - if (globalRejected) { - return new Object[0][]; - } - + static Object[][] allowedInGlobal() { return new Object[][] { new Object[] { Long.MAX_VALUE, "!java.**" }, new Object[] { Long.MAX_VALUE, "!java.lang.Long" }, @@ -118,7 +110,9 @@ public class MixedFiltersTest implements Serializable { * "global filter allow" + "specific ObjectInputStream filter is empty" => should allow * "global filter allow" + "specific ObjectInputStream filter reject" => should reject */ - @Test(dataProvider="AllowedInGlobal") + @ParameterizedTest + @DisabledIf("globalRejected") + @MethodSource("allowedInGlobal") public void testAllowedInGlobal(Object toDeserialized, String pattern) throws Exception { byte[] bytes = SerialFilterTest.writeObjects(toDeserialized); try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes); diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryExample.java b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryExample.java index 45b1872bae0..271c22b917c 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryExample.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryExample.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -46,9 +42,13 @@ import static java.io.ObjectInputFilter.Status.ALLOWED; import static java.io.ObjectInputFilter.Status.REJECTED; import static java.io.ObjectInputFilter.Status.UNDECIDED; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* @test - * @run testng/othervm SerialFactoryExample - * @run testng/othervm -Djdk.serialFilterFactory=SerialFactoryExample$FilterInThread SerialFactoryExample + * @run junit/othervm SerialFactoryExample + * @run junit/othervm -Djdk.serialFilterFactory=SerialFactoryExample$FilterInThread SerialFactoryExample * @summary Test SerialFactoryExample */ @@ -76,10 +76,9 @@ import static java.io.ObjectInputFilter.Status.UNDECIDED; * * The `doWithSerialFilter` calls can be nested. When nested, the filters are concatenated. */ -@Test public class SerialFactoryExample { - @DataProvider(name = "Examples") + // Test cases for filters static Object[][] examples() { return new Object[][]{ {new Point(1, 2), null, @@ -108,7 +107,8 @@ public class SerialFactoryExample { } - @Test(dataProvider = "Examples") + @ParameterizedTest + @MethodSource("examples") void examples(Serializable obj, ObjectInputFilter filter, Status expected) { // Establish FilterInThread as the application-wide filter factory FilterInThread filterInThread; @@ -128,11 +128,11 @@ public class SerialFactoryExample { Object o = deserializeObject(bytes); }); if (expected.equals(REJECTED)) - Assert.fail("IllegalClassException should have occurred"); + Assertions.fail("IllegalClassException should have occurred"); } catch (UncheckedIOException uioe) { IOException ioe = uioe.getCause(); - Assert.assertEquals(ioe.getClass(), InvalidClassException.class, "Wrong exception"); - Assert.assertEquals(REJECTED, expected, "Exception should not have occurred"); + Assertions.assertEquals(InvalidClassException.class, ioe.getClass(), "Wrong exception"); + Assertions.assertEquals(expected, REJECTED, "Exception should not have occurred"); } } @@ -142,7 +142,8 @@ public class SerialFactoryExample { * @param filter a filter * @param expected status */ - @Test(dataProvider = "Examples") + @ParameterizedTest + @MethodSource("examples") void checkStatus(Serializable obj, ObjectInputFilter filter, Status expected) { // Establish FilterInThread as the application-wide filter factory FilterInThread filterInThread; @@ -166,12 +167,12 @@ public class SerialFactoryExample { System.out.println(" filter in effect: " + filterInThread.currFilter); if (compositeFilter != null) { Status actualStatus = compositeFilter.checkInput(info); - Assert.assertEquals(actualStatus, expected, "Wrong Status"); + Assertions.assertEquals(expected, actualStatus, "Wrong Status"); } }); } catch (Exception ex) { - Assert.fail("unexpected exception", ex); + Assertions.fail("unexpected exception", ex); } } diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java index 1d35306a426..add9f3557da 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFactoryFaults.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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.ByteArrayInputStream; import java.io.IOException; @@ -32,15 +29,19 @@ import java.io.ObjectInputFilter.Config; import java.io.ObjectInputStream; import java.util.function.BinaryOperator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* @test - * @run testng/othervm -Djdk.serialFilterFactory=ForcedError_NoSuchClass SerialFactoryFaults - * @run testng/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$NoPublicConstructor SerialFactoryFaults - * @run testng/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$ConstructorThrows SerialFactoryFaults - * @run testng/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$FactorySetsFactory SerialFactoryFaults + * @run junit/othervm -Djdk.serialFilterFactory=ForcedError_NoSuchClass SerialFactoryFaults + * @run junit/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$NoPublicConstructor SerialFactoryFaults + * @run junit/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$ConstructorThrows SerialFactoryFaults + * @run junit/othervm -Djdk.serialFilterFactory=SerialFactoryFaults$FactorySetsFactory SerialFactoryFaults * @summary Check cases where the Filter Factory initialization from properties fails */ -@Test public class SerialFactoryFaults { // Sample the serial factory class name @@ -52,13 +53,13 @@ public class SerialFactoryFaults { System.getProperty("test.src", ".") + "/logging.properties"); } - @DataProvider(name = "MethodsToCall") - private Object[][] cases() { + // Test cases of faults + private static Object[][] cases() { return new Object[][] { - {"getSerialFilterFactory", (Assert.ThrowingRunnable) () -> Config.getSerialFilterFactory()}, - {"setSerialFilterFactory", (Assert.ThrowingRunnable) () -> Config.setSerialFilterFactory(new NoopFactory())}, - {"new ObjectInputStream(is)", (Assert.ThrowingRunnable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, - {"new OISSubclass()", (Assert.ThrowingRunnable) () -> new OISSubclass()}, + {"getSerialFilterFactory", (Executable) () -> Config.getSerialFilterFactory()}, + {"setSerialFilterFactory", (Executable) () -> Config.setSerialFilterFactory(new NoopFactory())}, + {"new ObjectInputStream(is)", (Executable) () -> new ObjectInputStream(new ByteArrayInputStream(new byte[0]))}, + {"new OISSubclass()", (Executable) () -> new OISSubclass()}, }; } @@ -66,26 +67,23 @@ public class SerialFactoryFaults { * Test each method that should throw IllegalStateException based on * the invalid arguments it was launched with. */ - @Test(dataProvider = "MethodsToCall") - public void initFaultTest(String name, Assert.ThrowingRunnable runnable) { - IllegalStateException ex = Assert.expectThrows(IllegalStateException.class, + @ParameterizedTest + @MethodSource("cases") + public void initFaultTest(String name, Executable runnable) { + IllegalStateException ex = Assertions.assertThrows(IllegalStateException.class, runnable); final String msg = ex.getMessage(); if (factoryName.equals("ForcedError_NoSuchClass")) { - Assert.assertEquals(msg, - "invalid jdk.serialFilterFactory: ForcedError_NoSuchClass: java.lang.ClassNotFoundException: ForcedError_NoSuchClass", "wrong exception"); + Assertions.assertEquals("invalid jdk.serialFilterFactory: ForcedError_NoSuchClass: java.lang.ClassNotFoundException: ForcedError_NoSuchClass", msg, "wrong exception"); } else if (factoryName.equals("SerialFactoryFaults$NoPublicConstructor")) { - Assert.assertEquals(msg, - "invalid jdk.serialFilterFactory: SerialFactoryFaults$NoPublicConstructor: java.lang.NoSuchMethodException: SerialFactoryFaults$NoPublicConstructor.()", "wrong exception"); + Assertions.assertEquals("invalid jdk.serialFilterFactory: SerialFactoryFaults$NoPublicConstructor: java.lang.NoSuchMethodException: SerialFactoryFaults$NoPublicConstructor.()", msg, "wrong exception"); } else if (factoryName.equals("SerialFactoryFaults$ConstructorThrows")) { - Assert.assertEquals(msg, - "invalid jdk.serialFilterFactory: SerialFactoryFaults$ConstructorThrows: java.lang.RuntimeException: constructor throwing a runtime exception", "wrong exception"); + Assertions.assertEquals("invalid jdk.serialFilterFactory: SerialFactoryFaults$ConstructorThrows: java.lang.RuntimeException: constructor throwing a runtime exception", msg, "wrong exception"); } else if (factoryName.equals("SerialFactoryFaults$FactorySetsFactory")) { - Assert.assertEquals(msg, - "invalid jdk.serialFilterFactory: SerialFactoryFaults$FactorySetsFactory: java.lang.IllegalStateException: Serial filter factory initialization incomplete", "wrong exception"); + Assertions.assertEquals("invalid jdk.serialFilterFactory: SerialFactoryFaults$FactorySetsFactory: java.lang.IllegalStateException: Serial filter factory initialization incomplete", msg, "wrong exception"); } else { - Assert.fail("No test for filter factory: " + factoryName); + Assertions.fail("No test for filter factory: " + factoryName); } } diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFilterFactoryTest.java b/test/jdk/java/io/Serializable/serialFilter/SerialFilterFactoryTest.java index 6842eabe9b0..f34f95a72b3 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFilterFactoryTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFilterFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -38,17 +35,26 @@ import java.io.Serial; import java.io.Serializable; import java.util.function.BinaryOperator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* @test * @build SerialFilterFactoryTest - * @run testng/othervm SerialFilterFactoryTest - * @run testng/othervm -Djdk.serialFilterFactory=SerialFilterFactoryTest$PropertyFilterFactory + * @run junit/othervm SerialFilterFactoryTest + * @run junit/othervm -Djdk.serialFilterFactory=SerialFilterFactoryTest$PropertyFilterFactory * -Djava.util.logging.config.file=${test.src}/logging.properties SerialFilterFactoryTest - * @run testng/othervm -Djdk.serialFilterFactory=SerialFilterFactoryTest$NotMyFilterFactory + * @run junit/othervm -Djdk.serialFilterFactory=SerialFilterFactoryTest$NotMyFilterFactory * -Djava.util.logging.config.file=${test.src}/logging.properties SerialFilterFactoryTest * * @summary Test Context-specific Deserialization Filters */ -@Test +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class SerialFilterFactoryTest { // A stream with just the header, enough to create a OIS @@ -70,7 +76,7 @@ public class SerialFilterFactoryTest { ois.writeObject(new Dummy("Here")); return boas.toByteArray(); } catch (IOException ioe) { - Assert.fail("unexpected IOE", ioe); + Assertions.fail("unexpected IOE", ioe); } throw new RuntimeException("should not reach here"); } @@ -109,7 +115,7 @@ public class SerialFilterFactoryTest { return !(ObjectInputFilter.Config.getSerialFilterFactory() instanceof NotMyFilterFactory); } - @DataProvider(name="FilterCases") + // Test cases for filter factory static Object[][] filterCases() { if (isValidFilterFactory()) { return new Object[][]{ @@ -124,9 +130,11 @@ public class SerialFilterFactoryTest { } // Setting the filter factory to null is not allowed. - @Test(expectedExceptions=NullPointerException.class) + @Test void testNull() { - Config.setSerialFilterFactory(null); + Assertions.assertThrows(NullPointerException.class, () -> { + Config.setSerialFilterFactory(null); + }); } /** @@ -136,7 +144,6 @@ public class SerialFilterFactoryTest { * Try to set it again, the second should throw. */ @Test - @SuppressWarnings("removal") void testSecondSetShouldThrow() { var currFF = Config.getSerialFilterFactory(); if (currFF.getClass().getClassLoader() == null) { @@ -145,14 +152,14 @@ public class SerialFilterFactoryTest { Config.setSerialFilterFactory(contextFilterFactory); currFF = contextFilterFactory; } catch (IllegalStateException ise) { - Assert.fail("First setSerialFilterFactory should not throw"); + Assertions.fail("First setSerialFilterFactory should not throw"); } } // Setting it again will throw - Assert.expectThrows(IllegalStateException.class, + Assertions.assertThrows(IllegalStateException.class, () -> Config.setSerialFilterFactory(new MyFilterFactory("f11"))); var resetFF = Config.getSerialFilterFactory(); - Assert.assertEquals(resetFF, currFF, "Setting again should not change filter factory"); + Assertions.assertEquals(currFF, resetFF, "Setting again should not change filter factory"); } /** @@ -167,8 +174,10 @@ public class SerialFilterFactoryTest { * @throws IOException if an I/O error occurs (should not occur) * @throws ClassNotFoundException for class not found (should not occur) */ - @Test(dataProvider="FilterCases") - @SuppressWarnings("removal") + @ParameterizedTest + @EnabledIf("isValidFilterFactory") + @MethodSource("filterCases") + @Order(1) void testCase(MyFilterFactory dynFilterFactory, Validator dynFilter, Validator streamFilter) throws IOException, ClassNotFoundException { @@ -182,32 +191,32 @@ public class SerialFilterFactoryTest { InputStream is = new ByteArrayInputStream(simpleStream); ObjectInputStream ois = new ObjectInputStream(is); - Assert.assertNull(factory.current(), "initially current should be null"); - Assert.assertEquals(factory.next(), configFilter, "initially next should be the configured filter"); + Assertions.assertNull(factory.current(), "initially current should be null"); + Assertions.assertEquals(configFilter, factory.next(), "initially next should be the configured filter"); var currFilter = ois.getObjectInputFilter(); if (currFilter != null && currFilter.getClass().getClassLoader() == null) { // Builtin loader; defaults to configured filter - Assert.assertEquals(currFilter, configFilter, "getObjectInputFilter should be configured filter"); + Assertions.assertEquals(configFilter, currFilter, "getObjectInputFilter should be configured filter"); } else { - Assert.assertEquals(currFilter, configFilter, "getObjectInputFilter should be null"); + Assertions.assertEquals(configFilter, currFilter, "getObjectInputFilter should be null"); } if (streamFilter != null) { ois.setObjectInputFilter(streamFilter); // MyFilterFactory is called when the stream filter is changed; verify values passed it - Assert.assertEquals(factory.current(), currFilter, "when setObjectInputFilter, current should be current filter"); - Assert.assertEquals(factory.next(), streamFilter, "next should be stream specific filter"); + Assertions.assertEquals(currFilter, factory.current(), "when setObjectInputFilter, current should be current filter"); + Assertions.assertEquals(streamFilter, factory.next(), "next should be stream specific filter"); // Check the OIS filter after the factory has updated it. currFilter = ois.getObjectInputFilter(); - Assert.assertEquals(currFilter, streamFilter, "getObjectInputFilter should be set"); + Assertions.assertEquals(streamFilter, currFilter, "getObjectInputFilter should be set"); // Verify that it can not be set again - Assert.assertThrows(IllegalStateException.class, () -> ois.setObjectInputFilter(streamFilter)); + Assertions.assertThrows(IllegalStateException.class, () -> ois.setObjectInputFilter(streamFilter)); } if (currFilter instanceof Validator validator) { validator.reset(); Object o = ois.readObject(); // Invoke only for the side effect of calling the Filter - Assert.assertEquals(validator.count, 1, "Wrong number of calls to the stream filter"); + Assertions.assertEquals(1, validator.count, "Wrong number of calls to the stream filter"); } else { Object o = ois.readObject(); // Invoke only for the side effect of calling the filter } @@ -217,18 +226,19 @@ public class SerialFilterFactoryTest { @Test void testPropertyFilterFactory() { if (jdkSerialFilterFactoryProp != null) { - Assert.assertEquals(jdkSerialFilterFactory.getClass().getName(), jdkSerialFilterFactoryProp, + Assertions.assertEquals(jdkSerialFilterFactoryProp, jdkSerialFilterFactory.getClass().getName(), "jdk.serialFilterFactory property classname mismatch"); } } // Test that setting the filter factory after any deserialization (any testCase) // throws IllegalStateException with the specific message - @Test(dependsOnMethods="testCase") + @Test + @Order(99) void testSetFactoryAfterDeserialization() { BinaryOperator factory = Config.getSerialFilterFactory(); - IllegalStateException ise = Assert.expectThrows(IllegalStateException.class, () -> Config.setSerialFilterFactory(factory)); - Assert.assertTrue(ise.getMessage().startsWith("Cannot replace filter factory: ")); + IllegalStateException ise = Assertions.assertThrows(IllegalStateException.class, () -> Config.setSerialFilterFactory(factory)); + Assertions.assertTrue(ise.getMessage().startsWith("Cannot replace filter factory: ")); } @@ -243,11 +253,11 @@ public class SerialFilterFactoryTest { // Try to set the filter to null ois.setObjectInputFilter(null); if (curr != null) { - Assert.fail("setting filter to null after a non-null filter should throw"); + Assertions.fail("setting filter to null after a non-null filter should throw"); } } catch (IllegalStateException ise) { if (curr == null) { - Assert.fail("setting filter to null after a null filter should not throw"); + Assertions.fail("setting filter to null after a null filter should not throw"); } } } diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFilterFunctionTest.java b/test/jdk/java/io/Serializable/serialFilter/SerialFilterFunctionTest.java index 41832d583c2..8930c2dfa9d 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFilterFunctionTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFilterFunctionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +21,6 @@ * questions. */ - -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.ObjectInputFilter; import java.io.ObjectInputFilter.FilterInfo; import java.util.function.Predicate; @@ -35,12 +30,16 @@ import static java.io.ObjectInputFilter.Status.ALLOWED; import static java.io.ObjectInputFilter.Status.REJECTED; import static java.io.ObjectInputFilter.Status.UNDECIDED; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* @test - * @run testng/othervm -Djava.util.logging.config.file=${test.src}/logging.properties + * @run junit/othervm -Djava.util.logging.config.file=${test.src}/logging.properties * SerialFilterFunctionTest * @summary ObjectInputFilter.Config Function Tests */ -@Test public class SerialFilterFunctionTest { @Test @@ -53,10 +52,10 @@ public class SerialFilterFunctionTest { ObjectInputFilter filter2 = getFilter(st2); ObjectInputFilter f = ObjectInputFilter.merge(filter1, filter2); Status r = f.checkInput(info); - Assert.assertEquals(merge(st1, st2), r, "merge"); + Assertions.assertEquals(r, merge(st1, st2), "merge"); } - Assert.assertSame(ObjectInputFilter.merge(filter1, null), filter1, "merge with null fail"); - Assert.assertThrows(NullPointerException.class, () -> ObjectInputFilter.merge(null, filter1)); + Assertions.assertSame(ObjectInputFilter.merge(filter1, null), filter1, "merge with null fail"); + Assertions.assertThrows(NullPointerException.class, () -> ObjectInputFilter.merge(null, filter1)); } } @@ -84,7 +83,7 @@ public class SerialFilterFunctionTest { return (cl) -> cl.equals(Integer.class); } - @DataProvider(name = "AllowPredicateCases") + // Test cases of filter strings static Object[][] allowPredicateCases() { return new Object[][]{ { Integer.class, isInteger(), REJECTED, ALLOWED}, @@ -95,18 +94,17 @@ public class SerialFilterFunctionTest { }; } - @Test(dataProvider = "AllowPredicateCases") + @ParameterizedTest + @MethodSource("allowPredicateCases") void testAllowPredicates(Class clazz, Predicate> predicate, Status otherStatus, Status expected) { ObjectInputFilter.FilterInfo info = new SerialInfo(clazz); if (predicate == null || expected == null) { - Assert.assertThrows(NullPointerException.class, () -> ObjectInputFilter.allowFilter(predicate, expected)); + Assertions.assertThrows(NullPointerException.class, () -> ObjectInputFilter.allowFilter(predicate, expected)); } else { - Assert.assertEquals(ObjectInputFilter.allowFilter(predicate, otherStatus).checkInput(info), - expected, "Predicate result"); + Assertions.assertEquals( expected, ObjectInputFilter.allowFilter(predicate, otherStatus).checkInput(info), "Predicate result"); } } - @DataProvider(name = "RejectPredicateCases") static Object[][] rejectPredicateCases() { return new Object[][]{ { Integer.class, isInteger(), REJECTED, REJECTED}, @@ -117,14 +115,15 @@ public class SerialFilterFunctionTest { }; } - @Test(dataProvider = "RejectPredicateCases") + @ParameterizedTest + @MethodSource("rejectPredicateCases") void testRejectPredicates(Class clazz, Predicate> predicate, Status otherStatus, Status expected) { ObjectInputFilter.FilterInfo info = new SerialInfo(clazz); if (predicate == null || expected == null) { - Assert.assertThrows(NullPointerException.class, () -> ObjectInputFilter.allowFilter(predicate, expected)); + Assertions.assertThrows(NullPointerException.class, () -> ObjectInputFilter.allowFilter(predicate, expected)); } else { - Assert.assertEquals(ObjectInputFilter.rejectFilter(predicate, otherStatus) - .checkInput(info), expected, "Predicate result"); + Assertions.assertEquals(expected, ObjectInputFilter.rejectFilter(predicate, otherStatus) + .checkInput(info), "Predicate result"); } } @@ -133,11 +132,11 @@ public class SerialFilterFunctionTest { FilterInfo info = new SerialInfo(Object.class); // an info structure, unused ObjectInputFilter undecided = getFilter(UNDECIDED); - Assert.assertEquals(ObjectInputFilter.rejectUndecidedClass(undecided).checkInput(info), REJECTED, "undecided -> rejected"); + Assertions.assertEquals(REJECTED, ObjectInputFilter.rejectUndecidedClass(undecided).checkInput(info), "undecided -> rejected"); ObjectInputFilter allowed = getFilter(ALLOWED); - Assert.assertEquals(ObjectInputFilter.rejectUndecidedClass(allowed).checkInput(info), ALLOWED, "allowed -> rejected"); + Assertions.assertEquals(ALLOWED, ObjectInputFilter.rejectUndecidedClass(allowed).checkInput(info), "allowed -> rejected"); ObjectInputFilter rejected = getFilter(REJECTED); - Assert.assertEquals(ObjectInputFilter.rejectUndecidedClass(rejected).checkInput(info), REJECTED, "rejected -> rejected"); + Assertions.assertEquals(REJECTED, ObjectInputFilter.rejectUndecidedClass(rejected).checkInput(info), "rejected -> rejected"); // Specific cases of Classes the result in allowed, rejected, and undecided status ObjectInputFilter numberFilter = ObjectInputFilter.Config.createFilter("java.lang.Integer;!java.lang.Double"); @@ -164,9 +163,9 @@ public class SerialFilterFunctionTest { while (clazz.isArray()) clazz = clazz.getComponentType(); Status expected = (clazz.isPrimitive()) ? UNDECIDED : REJECTED; - Assert.assertEquals(st, expected, "Wrong status for class: " + obj.getClass()); + Assertions.assertEquals(expected, st, "Wrong status for class: " + obj.getClass()); } else { - Assert.assertEquals(rawSt, st, "raw filter and rejectUndecided filter disagree"); + Assertions.assertEquals(st, rawSt, "raw filter and rejectUndecided filter disagree"); } } } diff --git a/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java b/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java index fb02cd02268..3b2ecc3d1b1 100644 --- a/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java +++ b/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,20 +46,20 @@ import java.util.concurrent.atomic.LongAdder; import javax.net.ssl.SSLEngineResult; -import org.testng.Assert; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* @test * @bug 8234836 * @build SerialFilterTest - * @run testng/othervm -Djava.util.logging.config.file=${test.src}/logging.properties + * @run junit/othervm -Djava.util.logging.config.file=${test.src}/logging.properties * SerialFilterTest - * @run testng/othervm -Djdk.serialSetFilterAfterRead=true SerialFilterTest + * @run junit/othervm -Djdk.serialSetFilterAfterRead=true SerialFilterTest * * @summary Test ObjectInputFilters using Builtin Filter Factory */ -@Test public class SerialFilterTest implements Serializable { @Serial @@ -89,9 +89,8 @@ public class SerialFilterTest implements Serializable { * Expand the patterns into cases for each of the Std and Compatibility APIs. * @return an array of arrays of the parameters including factories */ - @DataProvider(name="Patterns") static Object[][] patterns() { - Object[][] patterns = new Object[][]{ + return new Object[][]{ {"java.util.Hashtable"}, {"java.util.Hash*"}, {"javax.net.ssl.*"}, @@ -105,10 +104,8 @@ public class SerialFilterTest implements Serializable { {"maxbytes=+1024"}, {"java.base/java.util.Hashtable"}, }; - return patterns; } - @DataProvider(name="InvalidPatterns") static Object[][] invalidPatterns() { return new Object [][] { {".*"}, @@ -120,7 +117,6 @@ public class SerialFilterTest implements Serializable { }; } - @DataProvider(name="Limits") static Object[][] limits() { // The numbers are arbitrary > 1 return new Object[][] { @@ -133,7 +129,6 @@ public class SerialFilterTest implements Serializable { }; } - @DataProvider(name="InvalidLimits") static Object[][] invalidLimits() { return new Object[][] { {"maxrefs=-1"}, @@ -157,7 +152,6 @@ public class SerialFilterTest implements Serializable { * available to the filter. * @return Arrays of parameters with objects */ - @DataProvider(name="Objects") static Object[][] objects() { byte[] byteArray = new byte[0]; Object[] objArray = new Object[7]; @@ -168,7 +162,7 @@ public class SerialFilterTest implements Serializable { try { serClass = Class.forName(className); } catch (Exception e) { - Assert.fail("missing class: " + className, e); + Assertions.fail("missing class: " + className, e); } Class[] interfaces = {Runnable.class}; @@ -213,7 +207,6 @@ public class SerialFilterTest implements Serializable { return objects; } - @DataProvider(name="Arrays") static Object[][] arrays() { return new Object[][]{ {new Object[16], 16}, @@ -244,21 +237,22 @@ public class SerialFilterTest implements Serializable { * @param classes the expected (unique) classes * @throws IOException */ - @Test(dataProvider="Objects") + @ParameterizedTest + @MethodSource("objects") void t1(Object object, long count, long maxArray, long maxRefs, long maxDepth, long maxBytes, List> classes) throws IOException { byte[] bytes = writeObjects(object); Validator validator = new Validator(); validate(bytes, validator); - System.out.printf("v: %s%n", validator); + System.err.printf("v: %s%n", validator); - Assert.assertEquals(validator.count, count, "callback count wrong"); - Assert.assertEquals(validator.classes, classes, "classes mismatch"); - Assert.assertEquals(validator.maxArray, maxArray, "maxArray mismatch"); - Assert.assertEquals(validator.maxRefs, maxRefs, "maxRefs wrong"); - Assert.assertEquals(validator.maxDepth, maxDepth, "depth wrong"); - Assert.assertEquals(validator.maxBytes, maxBytes, "maxBytes wrong"); + Assertions.assertEquals(count, validator.count, "callback count wrong"); + Assertions.assertEquals(classes, validator.classes, "classes mismatch"); + Assertions.assertEquals(maxArray, validator.maxArray, "maxArray mismatch"); + Assertions.assertEquals(maxRefs, validator.maxRefs, "maxRefs wrong"); + Assertions.assertEquals(maxDepth, validator.maxDepth, "depth wrong"); + Assertions.assertEquals(maxBytes, validator.maxBytes, "maxBytes wrong"); } /** @@ -269,7 +263,8 @@ public class SerialFilterTest implements Serializable { * * @param pattern a pattern */ - @Test(dataProvider="Patterns") + @ParameterizedTest + @MethodSource("patterns") void testPatterns(String pattern) { evalPattern(pattern, (p, o, neg) -> testPatterns(p, o, neg)); } @@ -297,23 +292,23 @@ public class SerialFilterTest implements Serializable { // Check the initial filter is the global filter; may be null ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter(); ObjectInputFilter initial = ois.getObjectInputFilter(); - Assert.assertEquals(global, initial, "initial filter should be the global filter"); + Assertions.assertEquals(initial, global, "initial filter should be the global filter"); ois.setObjectInputFilter(validator); Object o = ois.readObject(); try { ois.setObjectInputFilter(validator2); - Assert.fail("Should not be able to set filter twice"); + Assertions.fail("Should not be able to set filter twice"); } catch (IllegalStateException ise) { // success, the exception was expected } } catch (EOFException eof) { - Assert.fail("Should not reach end-of-file", eof); + Assertions.fail("Should not reach end-of-file", eof); } catch (ClassNotFoundException cnf) { - Assert.fail("Deserializing", cnf); + Assertions.fail("Deserializing", cnf); } } catch (IOException ex) { - Assert.fail("Unexpected IOException", ex); + Assertions.fail("Unexpected IOException", ex); } } } @@ -336,7 +331,7 @@ public class SerialFilterTest implements Serializable { try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bais)) { Object actual1 = toggle ? ois.readObject() : ois.readUnshared(); - Assert.assertEquals(actual1, expected1, "unexpected string"); + Assertions.assertEquals(expected1, actual1, "unexpected string"); // Attempt to set filter ois.setObjectInputFilter(new ObjectInputFilter() { @Override @@ -345,14 +340,14 @@ public class SerialFilterTest implements Serializable { } }); if (!SET_FILTER_AFTER_READ) - Assert.fail("Should not be able to set filter after readObject has been called"); + Assertions.fail("Should not be able to set filter after readObject has been called"); } catch (IllegalStateException ise) { // success, the exception was expected if (SET_FILTER_AFTER_READ) - Assert.fail("With jdk.serialSetFilterAfterRead property set = true; " + + Assertions.fail("With jdk.serialSetFilterAfterRead property set = true; " + "should be able to set the filter after a read"); } catch (EOFException eof) { - Assert.fail("Should not reach end-of-file", eof); + Assertions.fail("Should not reach end-of-file", eof); } } } @@ -362,12 +357,13 @@ public class SerialFilterTest implements Serializable { * that the callback to the filter includes the proper array length. * @throws IOException if an error occurs */ - @Test(dataProvider="Arrays") + @ParameterizedTest + @MethodSource("arrays") void testReadResolveToArray(Object array, int length) throws IOException { ReadResolveToArray object = new ReadResolveToArray(array, length); byte[] bytes = writeObjects(object); Object o = validate(bytes, object); // the object is its own filter - Assert.assertEquals(o.getClass(), array.getClass(), "Filter not called with the array"); + Assertions.assertEquals(array.getClass(), o.getClass(), "Filter not called with the array"); } @@ -379,18 +375,17 @@ public class SerialFilterTest implements Serializable { * @param name the name of the limit to test * @param value a test value */ - @Test(dataProvider="Limits") + @ParameterizedTest + @MethodSource("limits") void testLimits(String name, long value) { Class arrayClass = new int[0].getClass(); String pattern = String.format("%s=%d;%s=%d", name, value, name, value - 1); ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); - Assert.assertEquals( + Assertions.assertEquals(ObjectInputFilter.Status.REJECTED, filter.checkInput(new FilterValues(arrayClass, value, value, value, value)), - ObjectInputFilter.Status.REJECTED, "last limit value not used: " + filter); - Assert.assertEquals( + Assertions.assertEquals(ObjectInputFilter.Status.UNDECIDED, filter.checkInput(new FilterValues(arrayClass, value-1, value-1, value-1, value-1)), - ObjectInputFilter.Status.UNDECIDED, "last limit value not used: " + filter); } @@ -399,46 +394,36 @@ public class SerialFilterTest implements Serializable { * Construct a filter with the limit, it should throw IllegalArgumentException. * @param pattern a pattern to test */ - @Test(dataProvider="InvalidLimits", expectedExceptions=java.lang.IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("invalidLimits") void testInvalidLimits(String pattern) { - try { - ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); - } catch (IllegalArgumentException iae) { - System.out.printf(" success exception: %s%n", iae); - throw iae; - } + var iae = Assertions.assertThrows(IllegalArgumentException.class, + () -> ObjectInputFilter.Config.createFilter(pattern)); + System.err.printf(" success exception: %s%n", iae); } /** * Test that returning null from a filter causes deserialization to fail. */ - @Test(expectedExceptions=InvalidClassException.class) + @Test void testNullStatus() throws IOException { - byte[] bytes = writeObjects(0); // an Integer - try { - Object o = validate(bytes, new ObjectInputFilter() { - public ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo f) { - return null; - } - }); - } catch (InvalidClassException ice) { - System.out.printf(" success exception: %s%n", ice); - throw ice; - } + var ice = Assertions.assertThrows(InvalidClassException.class, () -> { + byte[] bytes = writeObjects(0); // an Integer + validate(bytes, f -> null); + }); + System.err.printf(" success exception: %s%n", ice); } /** * Verify that malformed patterns throw IAE. * @param pattern pattern from the data source */ - @Test(dataProvider="InvalidPatterns", expectedExceptions=IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("invalidPatterns") void testInvalidPatterns(String pattern) { - try { - ObjectInputFilter.Config.createFilter(pattern); - } catch (IllegalArgumentException iae) { - System.out.printf(" success exception: %s%n", iae); - throw iae; - } + var iae = Assertions.assertThrows(IllegalArgumentException.class, + () -> ObjectInputFilter.Config.createFilter(pattern)); + System.err.printf(" success exception: %s%n", iae); } /** @@ -447,10 +432,10 @@ public class SerialFilterTest implements Serializable { @Test() void testEmptyPattern() { ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(""); - Assert.assertNull(filter, "empty pattern did not return null"); + Assertions.assertNull(filter, "empty pattern did not return null"); filter = ObjectInputFilter.Config.createFilter(";;;;"); - Assert.assertNull(filter, "pattern with only delimiters did not return null"); + Assertions.assertNull(filter, "pattern with only delimiters did not return null"); } /** @@ -472,7 +457,7 @@ public class SerialFilterTest implements Serializable { } catch (EOFException eof) { // normal completion } catch (ClassNotFoundException cnf) { - Assert.fail("Deserializing", cnf); + Assertions.fail("Deserializing", cnf); } return null; } @@ -514,7 +499,7 @@ public class SerialFilterTest implements Serializable { @Override public ObjectInputFilter.Status checkInput(FilterInfo filter) { Class serialClass = filter.serialClass(); - System.out.printf(" checkInput: class: %s, arrayLen: %d, refs: %d, depth: %d, bytes; %d%n", + System.err.printf(" checkInput: class: %s, arrayLen: %d, refs: %d, depth: %d, bytes; %d%n", serialClass, filter.arrayLength(), filter.references(), filter.depth(), filter.streamBytes()); count++; @@ -561,13 +546,13 @@ public class SerialFilterTest implements Serializable { byte[] bytes = SerialFilterTest.writeObjects(object); ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern); validate(bytes, filter); - Assert.assertTrue(allowed, "filter should have thrown an exception"); + Assertions.assertTrue(allowed, "filter should have thrown an exception"); } catch (IllegalArgumentException iae) { - Assert.fail("bad format pattern", iae); + Assertions.fail("bad format pattern", iae); } catch (InvalidClassException ice) { - Assert.assertFalse(allowed, "filter should not have thrown an exception: " + ice); + Assertions.assertFalse(allowed, "filter should not have thrown an exception: " + ice); } catch (IOException ioe) { - Assert.fail("Unexpected IOException", ioe); + Assertions.fail("Unexpected IOException", ioe); } } @@ -578,12 +563,12 @@ public class SerialFilterTest implements Serializable { */ static void evalPattern(String pattern, TriConsumer action) { Object o = genTestObject(pattern, true); - Assert.assertNotNull(o, "success generation failed"); + Assertions.assertNotNull(o, "success generation failed"); action.accept(pattern, o, true); // Test the negative pattern o = genTestObject(pattern, false); - Assert.assertNotNull(o, "fail generation failed"); + Assertions.assertNotNull(o, "fail generation failed"); String negPattern = pattern.contains("=") ? pattern : "!" + pattern; action.accept(negPattern, o, false); } @@ -616,12 +601,12 @@ public class SerialFilterTest implements Serializable { Constructor cons = clazz.getConstructor(); return cons.newInstance(); } catch (ClassNotFoundException ex) { - Assert.fail("no such class available: " + pattern); + Assertions.fail("no such class available: " + pattern); } catch (InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException ex1) { - Assert.fail("newInstance: " + ex1); + Assertions.fail("newInstance: " + ex1); } } return null; @@ -661,7 +646,7 @@ public class SerialFilterTest implements Serializable { return new Hashtable(); } } - Assert.fail("Object could not be generated for pattern: " + Assertions.fail("Object could not be generated for pattern: " + pattern + ", allowed: " + allowed); return null; @@ -677,7 +662,7 @@ public class SerialFilterTest implements Serializable { */ static Object genTestLimit(String pattern, boolean allowed) { int ndx = pattern.indexOf('='); - Assert.assertNotEquals(ndx, -1, "missing value in limit"); + Assertions.assertNotEquals(-1, ndx, "missing value in limit"); long value = Long.parseUnsignedLong(pattern.substring(ndx+1)); if (pattern.startsWith("maxdepth=")) { // Return an object with the requested depth (or 1 greater) @@ -703,7 +688,7 @@ public class SerialFilterTest implements Serializable { } else if (pattern.startsWith("maxarray=")) { return allowed ? new int[(int)value] : new int[(int)value+1]; } - Assert.fail("Object could not be generated for pattern: " + Assertions.fail("Object could not be generated for pattern: " + pattern + ", allowed: " + allowed); return null; @@ -736,7 +721,7 @@ public class SerialFilterTest implements Serializable { os.flush(); actualSize = baos.size(); } catch (IOException ie) { - Assert.fail("exception generating stream", ie); + Assertions.fail("exception generating stream", ie); } } while (actualSize != desiredSize); return holder; diff --git a/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java b/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java index d3c44bc9279..2b4cdfa9bdd 100644 --- a/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java +++ b/test/jdk/java/lang/ProcessBuilder/PipelineLeaksFD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,32 +21,42 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.*; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.Writer; +import java.lang.ProcessHandle; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; /* * @test - * @bug 8289643 8291760 - * @requires (os.family == "linux" & !vm.musl) + * @bug 8289643 8291760 8291986 + * @requires os.family == "mac" | (os.family == "linux" & !vm.musl) * @summary File descriptor leak detection with ProcessBuilder.startPipeline - * @run testng/othervm PipelineLeaksFD + * @run junit/othervm PipelineLeaksFD */ -@Test public class PipelineLeaksFD { - @DataProvider - public Object[][] builders() { + + private static final String OS_NAME = System.getProperty("os.name", "Unknown"); + + private static final long MY_PID = ProcessHandle.current().pid(); + + private static final boolean LSOF_AVAILABLE = checkForLSOF(); + + // Test cases for pipelines with a number of pipeline sequences + public static Object[][] builders() { return new Object[][]{ {List.of(new ProcessBuilder("cat"))}, {List.of(new ProcessBuilder("cat"), @@ -59,20 +69,43 @@ public class PipelineLeaksFD { }; } - @Test(dataProvider = "builders") + // True if lsof is runnable and collect pipe usage. + private static boolean lsofAvailable() { + return LSOF_AVAILABLE; + } + + // Check if lsof is available + private static boolean checkForLSOF() { + try { + lsofForAll(); + return true; + } catch (IOException ioe) { + System.err.println("Skipping: " + ioe); + return false; + } + } + + @EnabledIf("lsofAvailable") + @ParameterizedTest + @MethodSource("builders") void checkForLeaks(List builders) throws IOException { - Set pipesBefore = myPipes(); + List lsofLines = lsofForAll(); + Set pipesBefore = pipesFromLSOF(lsofLines, MY_PID); if (pipesBefore.size() < 3) { - System.out.println(pipesBefore); - Assert.fail("There should be at least 3 pipes before, (0, 1, 2)"); + // Dump all lsof output to aid debugging + System.out.println("Output from lsof"); + lsofLines.forEach(System.err::println); + System.err.println(pipesBefore); + fail("There should be at least 3 pipes before, (0, 1, 2)"); } + printPipes(pipesBefore, "Before start"); List processes = ProcessBuilder.startPipeline(builders); // Write something through the pipeline final String text = "xyz"; - try (Writer out = processes.get(0).outputWriter()) { + try (Writer out = processes.getFirst().outputWriter()) { out.write(text); } @@ -84,16 +117,17 @@ public class PipelineLeaksFD { try (BufferedReader inputStream = p.inputReader(); BufferedReader errorStream = p.errorReader()) { String outActual = inputStream.readLine(); - Assert.assertEquals(outActual, expectedOut, "stdout, process[ " + i + "]: " + p); + assertEquals(expectedOut, outActual, "stdout, process[ " + i + "]: " + p); String errActual = errorStream.readLine(); - Assert.assertEquals(errActual, expectedErr, "stderr, process[ " + i + "]: " + p); + assertEquals(expectedErr, errActual, "stderr, process[ " + i + "]: " + p); } } - processes.forEach(p -> waitForQuiet(p)); + processes.forEach(PipelineLeaksFD::waitForQuiet); - Set pipesAfter = myPipes(); + lsofLines = lsofForAll(); + Set pipesAfter = pipesFromLSOF(lsofLines, MY_PID); if (!pipesBefore.equals(pipesAfter)) { Set missing = new HashSet<>(pipesBefore); missing.removeAll(pipesAfter); @@ -101,46 +135,191 @@ public class PipelineLeaksFD { Set extra = new HashSet<>(pipesAfter); extra.removeAll(pipesBefore); printPipes(extra, "Extra pipes in pipesAfter"); - Assert.fail("More or fewer pipes than expected"); + // Dump all lsof output to aid debugging + System.out.println("\nOutput from lsof"); + lsofLines.forEach(System.err::println); + fail("More or fewer pipes than expected"); + } + } + + // Test redirectErrorStream, both true and false + public static Object[][] redirectCases() { + return new Object[][] { + {true}, + {false}, + }; + } + + // Test redirectErrorStream (true/false) has the right number of pipes in use + @EnabledIf("lsofAvailable") + @ParameterizedTest() + @MethodSource("redirectCases") + void checkRedirectErrorStream(boolean redirectError) throws IOException { + try (Process p = new ProcessBuilder("cat") + .redirectErrorStream(redirectError) + .start()) { + System.err.printf("Parent PID; %d, Child Pid: %d\n", MY_PID, p.pid()); + List lsofLines = lsofForAll(); + final Set pipes = pipesFromLSOF(lsofLines, p.pid()); + printPipes(pipes, "Parent and waiting child pipes"); + int uniquePipes = redirectError ? 8 : 9; + if (uniquePipes != pipes.size()) { + // Dump all lsof output to aid debugging + System.out.println("\nOutput from lsof"); + lsofLines.forEach(System.err::println); + } + assertEquals(uniquePipes, pipes.size(), + "wrong number of pipes for redirect: " + redirectError); + String expectedTypeName = redirectError + ? "java.lang.ProcessBuilder$NullInputStream" + : "java.lang.ProcessImpl$ProcessPipeInputStream"; + assertEquals(expectedTypeName, p.getErrorStream().getClass().getName(), + "errorStream type is incorrect"); + } catch (IOException ioe) { + fail("Process start", ioe); } } static void printPipes(Set pipes, String label) { - System.out.printf("%s: [%d]%n", label, pipes.size()); - pipes.forEach(r -> System.out.printf("%-20s: %s%n", r.fd(), r.link())); + System.err.printf("%s: [%d]%n", label, pipes.size()); + pipes.forEach(System.err::println); } static void waitForQuiet(Process p) { try { int st = p.waitFor(); if (st != 0) { - System.out.println("non-zero exit status: " + p); + System.err.println("non-zero exit status: " + p); } } catch (InterruptedException ie) { } } /** - * Collect a Set of pairs of /proc fd paths and the symbol links that are pipes. + * Collect a Set of file descriptors and identifying information. + * To identify the pipes in use the `lsof` command is invoked and output scrapped for + * fd's, pids, unique identities of the pipes (to match with parent). * @return A set of PipeRecords, possibly empty */ - static Set myPipes() { - Path path = Path.of("/proc/" + ProcessHandle.current().pid() + "/fd"); - Set pipes = new HashSet<>(); - File[] files = path.toFile().listFiles(f -> Files.isSymbolicLink(f.toPath())); - if (files != null) { - for (File file : files) { - try { - Path link = Files.readSymbolicLink(file.toPath()); - if (link.toString().startsWith("pipe:")) { - pipes.add(new PipeRecord(file.toPath(), link)); - } - } catch (IOException ioe) { - } - } - } - return pipes; + private static Set pipesForPid(long pid) throws IOException { + var lines = lsofForAll(); + return pipesFromLSOF(lines, pid); } - record PipeRecord(Path fd, Path link) { }; + /** + * Extract the PipeRecords from the `lsof` output for this process and a designated child process. + * + * @param lines lines of lsof output + * @param pid pid of child process of interest + * @return a Set of PipeRecords for parent and child + */ + private static LinkedHashSet pipesFromLSOF(List lines, long pid) { + return lines.stream() + .map(PipelineLeaksFD::pipeFromLSOF) + .filter(pr -> pr != null && + (pr.pid() == pid || pr.pid() == MY_PID)) + .collect(Collectors.toCollection(LinkedHashSet::new)); + } + + /** + * Collect the output of `lsof` for all files. + * Files are used for `lsof` input and output to avoid creating pipes. + * @return a List of lines output from `lsof`. + */ + private static List lsofForAll() throws IOException { + Path tmpDir = Path.of("."); + String tmpPrefix = "lsof-"; + Path lsofEmptyInput = Files.createTempFile(tmpDir, tmpPrefix, ".empty"); + Path lsofOutput = Files.createTempFile(tmpDir, tmpPrefix, ".tmp"); + try (Process p = new ProcessBuilder("lsof") + .redirectOutput(lsofOutput.toFile()) + .redirectInput(lsofEmptyInput.toFile()) // empty input + .redirectError(ProcessBuilder.Redirect.DISCARD) // ignored output + .start()) { + int status = p.waitFor(); + assertEquals(0, status, "Process 'lsof' failed"); + + return Files.readAllLines(lsofOutput); + } catch (InterruptedException ie) { + throw new IOException("Waiting for lsof exit interrupted", ie); + } + } + + // Return pipe records by parsing the appropriate platform specific `lsof` output. + static PipeRecord pipeFromLSOF(String s) { + return switch (OS_NAME) { + case "Linux" -> pipeFromLinuxLSOF(s); + case "Mac OS X" -> pipeFromMacLSOF(s); + default -> throw new RuntimeException("lsof not supported on platform: " + OS_NAME); + }; + } + + // Return Pipe from lsof output put, or null (on Mac OS X) + // lsof 55221 rriggs 0 PIPE 0xc76402237956a5cb 16384 ->0xfcb0c07ae447908c + // lsof 55221 rriggs 1 PIPE 0xb486e02f86da463e 16384 ->0xf94eacc85896b4e6 + static PipeRecord pipeFromMacLSOF(String s) { + String[] fields = s.split("\\s+"); + if ("PIPE".equals(fields[4])) { + final int pid = Integer.parseInt(fields[1]); + final String myKey = (fields.length > 5) ? fields[5] : ""; + final String otherKey = (fields.length > 7) ? fields[7].substring(2) : ""; + return PipeRecord.lookup(Integer.parseInt(fields[3]), myKey, otherKey, pid); + } + return null; + } + + // Return Pipe from lsof output put, or null (on Linux) + // java 7612 rriggs 14w FIFO 0,12 0t0 117662267 pipe + // java 7612 rriggs 15r FIFO 0,12 0t0 117662268 pipe + static PipeRecord pipeFromLinuxLSOF(String s) { + String[] fields = s.split("\\s+"); + if ("FIFO".equals(fields[4])) { + final int pid = Integer.parseInt(fields[1]); + final String key = (fields.length > 7) ? fields[7] : ""; + final int fdNum = Integer.parseInt(fields[3].substring(0, fields[3].length() - 1)); + return PipeRecord.lookup(fdNum, key, null, pid); + } + return null; + } + + // Identify a pipe by pid, fd, and a key (unique across processes) + // Mac OS X has separate keys for read and write sides, both are matched to the same "name" + record PipeRecord(long pid, int fd, KeyedString myKey) { + static PipeRecord lookup(int fd, String myKey, String otherKey, int pid) { + return new PipeRecord(pid, fd, KeyedString.getKey(myKey, otherKey)); + } + } + + // A unique name for a string with a count of uses + // Used to associate pipe between parent and child. + static class KeyedString { + private static final HashMap map = new HashMap<>(); + private static int nextInt = 1; + private final String key; + private final String name; + private int count; + KeyedString(String key, String name) { + this.key = key; + this.name = name; + this.count = 0; + } + + KeyedString(String s) { + String k = "p" + nextInt++; + this(s, k); + } + + static KeyedString getKey(String key, String otherKey) { + var k = map.computeIfAbsent(key, KeyedString::new); + k.count++; + if (otherKey != null) { + map.putIfAbsent(otherKey, k); + } + return k; + } + + public String toString() { + return name + "(" + count + ")"; + } + } } diff --git a/test/jdk/java/lang/ProcessBuilder/TEST.properties b/test/jdk/java/lang/ProcessBuilder/TEST.properties new file mode 100644 index 00000000000..c7e8a6850ca --- /dev/null +++ b/test/jdk/java/lang/ProcessBuilder/TEST.properties @@ -0,0 +1 @@ +maxOutputSize=6000000 diff --git a/test/jdk/java/lang/String/IndexOf.java b/test/jdk/java/lang/String/IndexOf.java index b4fd17105a8..48f23de79b0 100644 --- a/test/jdk/java/lang/String/IndexOf.java +++ b/test/jdk/java/lang/String/IndexOf.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Intel Corporation. All rights reserved. + * Copyright (c) 2024, 2026, 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 @@ -37,6 +37,15 @@ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:-TieredCompilation -XX:UseAVX=2 -XX:+UnlockDiagnosticVMOptions -XX:+EnableX86ECoreOpts IndexOf */ +/* + * @test + * @bug 8360271 + * @summary test String indexOf() intrinsic + * @requires vm.cpu.features ~= ".*avx2.*" + * @requires vm.compiler2.enabled + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:-TieredCompilation -XX:UseAVX=2 -XX:+UnlockDiagnosticVMOptions -XX:+EnableX86ECoreOpts -XX:-CompactStrings IndexOf + */ + public class IndexOf { final int scope = 32*2+16+8; final char a, aa, b, c, d; @@ -56,11 +65,11 @@ d = 'd'; break; case UU: - a = '\u0061'; + a = '\u1061'; aa = a; - b = '\u0062'; + b = '\u1062'; c = '\u1063'; - d = '\u0064'; + d = '\u1064'; break; default: //case UL: a = 'a'; @@ -73,7 +82,7 @@ } // needle =~ /ab*d/ - // badNeedle =~ /ab*db*d/ + // badNeedle =~ /ab*cb*d/ interface Append {void append(int pos, char cc);} String newNeedle(int size, int badPosition) { if (size<2) {throw new RuntimeException("Fix testcase "+size);} diff --git a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java index 3cea9073199..ded087d35e8 100644 --- a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java +++ b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,8 @@ import java.net.MulticastSocket; import java.nio.channels.DatagramChannel; import java.util.Random; +import static java.net.StandardSocketOptions.SO_RCVBUF; +import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.expectThrows; @@ -102,6 +104,10 @@ public class SendReceiveMaxSize { DatagramSocketSupplier supplier, Class exception) throws IOException { try (var receiver = new DatagramSocket(new InetSocketAddress(HOST_ADDR, 0))) { + assertTrue(receiver.getOption(SO_RCVBUF) >= capacity, + receiver.getOption(SO_RCVBUF) + + " for UDP receive buffer too small to hold capacity " + + capacity); var port = receiver.getLocalPort(); var addr = new InetSocketAddress(HOST_ADDR, port); try (var sender = supplier.open()) { diff --git a/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java index 67b993eef0b..2d8ff05dbd2 100644 --- a/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java +++ b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +75,8 @@ public class TimeoutResponseTestSupport { private static final SSLContext SSL_CONTEXT = SimpleSSLContext.findSSLContext(); protected static final Duration REQUEST_TIMEOUT = - Duration.ofMillis(Long.parseLong(System.getProperty("test.requestTimeoutMillis"))); + Duration.ofMillis(jdk.test.lib.Utils.adjustTimeout( + Long.parseLong(System.getProperty("test.requestTimeoutMillis")))); static { assertTrue( @@ -87,7 +88,8 @@ public class TimeoutResponseTestSupport { 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")); + jdk.test.lib.Utils.adjustTimeout( + Long.parseLong(System.getProperty("test.responseFailureWaitDurationMillis", "0"))); static { if (RETRY_LIMIT > 0) { diff --git a/test/jdk/java/security/CodeSource/CodeSourceNoInputs.java b/test/jdk/java/security/CodeSource/CodeSourceNoInputs.java new file mode 100644 index 00000000000..e1d2497667b --- /dev/null +++ b/test/jdk/java/security/CodeSource/CodeSourceNoInputs.java @@ -0,0 +1,110 @@ +/* + * 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.security.CodeSigner; +import java.security.CodeSource; +import java.security.PublicKey; +import java.security.cert.Certificate; + +/** + * @test + * @bug 8366522 + * @summary Verify that getCertificates() and getCodeSigners() return correct + * results when CodeSource is created with empty or null Certificate[] + * or CodeSigner[] arguments, or there are no X509 certificates in + * certs. Make sure that NPE is not thrown from + * CodeSource.getCodeSigners() + */ +public class CodeSourceNoInputs { + private static final Certificate NON_X509_CERT = new Certificate("") { + @Override + public byte[] getEncoded() { + return new byte[0]; + } + + @Override + public void verify(PublicKey key) { + } + + @Override + public void verify(PublicKey key, String sigProvider) { + } + + @Override + public String toString() { + return ""; + } + + @Override + public PublicKey getPublicKey() { + return null; + } + }; + + public static void main(String[] args) throws Exception { + CodeSource cs; + + cs = new CodeSource(null, (Certificate[]) null); + if (cs.getCodeSigners() != null || cs.getCertificates() != null) { + + throw new SecurityException("Both CodeSource.getCodeSigners() " + + "and CodeSource.getCertificates() should return null for " + + "new CodeSource(null, (Certificate[]) null)"); + } + + cs = new CodeSource(null, (CodeSigner[]) null); + if (cs.getCodeSigners() != null || cs.getCertificates() != null) { + + throw new SecurityException("Both CodeSource.getCodeSigners() " + + "and CodeSource.getCertificates() should return null for " + + "new CodeSource(null, (CodeSigners[]) null)"); + } + + cs = new CodeSource(null, new Certificate[0]); + if (cs.getCodeSigners().length != 0 + || cs.getCertificates().length != 0) { + + throw new SecurityException("Both CodeSource.getCodeSigners()" + + "and CodeSource.getCertificates() should return empty arrays " + + "for new CodeSource(null, new Certificate[0])"); + + } + + cs = new CodeSource(null, new CodeSigner[0]); + if (cs.getCodeSigners().length != 0 + || cs.getCertificates().length != 0) { + + throw new SecurityException("Both CodeSource.getCodeSigners() and" + + " CodeSource.getCertificates() should return empty arrays for" + + " new CodeSource(null, new CodeSigners[0])"); + } + + cs = new CodeSource(null, new Certificate[]{NON_X509_CERT}); + if (cs.getCodeSigners().length != 0 || cs.getCertificates() == null) { + + throw new SecurityException("Both CodeSource.getCodeSigners() and" + + " CodeSource.getCertificates() should return arrays for new" + + " CodeSource(null, new CodeSigners[1]{NON-X509-CERTIFICATE})"); + } + } +} diff --git a/test/jdk/java/util/ServiceLoader/BadProvidersTest.java b/test/jdk/java/util/ServiceLoader/BadProvidersTest.java index 8560126eb00..0a734a2b214 100644 --- a/test/jdk/java/util/ServiceLoader/BadProvidersTest.java +++ b/test/jdk/java/util/ServiceLoader/BadProvidersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @modules jdk.compiler * @build jdk.test.lib.compiler.CompilerUtils - * @run testng/othervm BadProvidersTest + * @run junit/othervm BadProvidersTest * @summary Basic test of ServiceLoader with bad provider and bad provider * factories deployed on the module path */ @@ -50,8 +50,6 @@ import java.util.stream.Collectors; import jdk.test.lib.compiler.CompilerUtils; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; import static java.lang.classfile.ClassFile.ACC_PUBLIC; import static java.lang.classfile.ClassFile.ACC_STATIC; @@ -59,13 +57,16 @@ import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.INIT_NAME; import static java.lang.constant.ConstantDescs.MTD_void; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; /** * Basic test of `provides S with PF` and `provides S with P` where the provider * factory or provider */ - public class BadProvidersTest { private static final String TEST_SRC = System.getProperty("test.src"); @@ -137,22 +138,10 @@ public class BadProvidersTest { assertTrue(p != null); } - - @DataProvider(name = "badfactories") - public Object[][] createBadFactories() { - return new Object[][] { - { "classnotpublic", null }, - { "methodnotpublic", null }, - { "badreturntype", null }, - { "returnsnull", null }, - { "throwsexception", null }, - }; - } - - - @Test(dataProvider = "badfactories", - expectedExceptions = ServiceConfigurationError.class) - public void testBadFactory(String testName, String ignore) throws Exception { + @ParameterizedTest + @ValueSource(strings = { "classnotpublic", "methodnotpublic", "badreturntype", + "returnsnull", "throwsexception" }) + public void testBadFactory(String testName) throws Exception { Path mods = compileTest(TEST1_MODULE); // compile the bad factory @@ -164,28 +153,18 @@ public class BadProvidersTest { // copy the compiled class into the module Path classFile = Paths.get("p", "ProviderFactory.class"); Files.copy(output.resolve(classFile), - mods.resolve(TEST1_MODULE).resolve(classFile), - StandardCopyOption.REPLACE_EXISTING); + mods.resolve(TEST1_MODULE).resolve(classFile), + StandardCopyOption.REPLACE_EXISTING); - // load providers and instantiate each one - loadProviders(mods, TEST1_MODULE).forEach(Provider::get); + Assertions.assertThrows(ServiceConfigurationError.class, + // load providers and instantiate each one + () -> loadProviders(mods, TEST1_MODULE).forEach(Provider::get) + ); } - - @DataProvider(name = "badproviders") - public Object[][] createBadProviders() { - return new Object[][] { - { "notpublic", null }, - { "ctornotpublic", null }, - { "notasubtype", null }, - { "throwsexception", null } - }; - } - - - @Test(dataProvider = "badproviders", - expectedExceptions = ServiceConfigurationError.class) - public void testBadProvider(String testName, String ignore) throws Exception { + @ParameterizedTest + @ValueSource(strings = { "notpublic", "ctornotpublic", "notasubtype", "throwsexception" }) + public void testBadProvider(String testName) throws Exception { Path mods = compileTest(TEST2_MODULE); // compile the bad provider @@ -197,11 +176,13 @@ public class BadProvidersTest { // copy the compiled class into the module Path classFile = Paths.get("p", "Provider.class"); Files.copy(output.resolve(classFile), - mods.resolve(TEST2_MODULE).resolve(classFile), - StandardCopyOption.REPLACE_EXISTING); + mods.resolve(TEST2_MODULE).resolve(classFile), + StandardCopyOption.REPLACE_EXISTING); - // load providers and instantiate each one - loadProviders(mods, TEST2_MODULE).forEach(Provider::get); + Assertions.assertThrows(ServiceConfigurationError.class, + // load providers and instantiate each one + () -> loadProviders(mods, TEST2_MODULE).forEach(Provider::get) + ); } @@ -209,7 +190,7 @@ public class BadProvidersTest { * Test a service provider that defines more than one no-args * public static "provider" method. */ - @Test(expectedExceptions = ServiceConfigurationError.class) + @Test public void testWithTwoFactoryMethods() throws Exception { Path mods = compileTest(TEST1_MODULE); @@ -244,8 +225,10 @@ public class BadProvidersTest { .resolve("ProviderFactory.class"); Files.write(classFile, bytes); - // load providers and instantiate each one - loadProviders(mods, TEST1_MODULE).forEach(Provider::get); + Assertions.assertThrows(ServiceConfigurationError.class, + // load providers and instantiate each one + () -> loadProviders(mods, TEST1_MODULE).forEach(Provider::get) + ); } } diff --git a/test/jdk/java/util/ServiceLoader/CachingTest.java b/test/jdk/java/util/ServiceLoader/CachingTest.java index 264c646b5af..138b6b6862f 100644 --- a/test/jdk/java/util/ServiceLoader/CachingTest.java +++ b/test/jdk/java/util/ServiceLoader/CachingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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 Test ServiceLoader caches - * @run testng CachingTest + * @run junit CachingTest */ import java.nio.file.Files; @@ -38,9 +38,9 @@ import java.util.ServiceLoader.Provider; import java.util.Spliterator; import java.util.stream.Collectors; -import org.testng.annotations.BeforeClass; -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; public class CachingTest { @@ -52,17 +52,17 @@ public class CachingTest { public static class S2 implements S { } - private ClassLoader testClassLoader; + private static ClassLoader testClassLoader; // creates the services configuration file and sets the ClassLoader - @BeforeClass - void setup() throws Exception { + @BeforeAll + static void setup() throws Exception { String classes = System.getProperty("test.classes"); Path dir = Paths.get(classes, "META-INF", "services"); Files.createDirectories(dir); Path config = dir.resolve(S.class.getName()); Files.write(config, List.of(S1.class.getName(), S2.class.getName())); - this.testClassLoader = CachingTest.class.getClassLoader(); + testClassLoader = CachingTest.class.getClassLoader(); } private void checkLists(List list1, List list2) { diff --git a/test/jdk/java/util/ServiceLoader/ModulesTest.java b/test/jdk/java/util/ServiceLoader/ModulesTest.java index 002b8458865..d265ce18f60 100644 --- a/test/jdk/java/util/ServiceLoader/ModulesTest.java +++ b/test/jdk/java/util/ServiceLoader/ModulesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @build jdk.test.lib.util.JarUtils * @compile classpath/pearscript/org/pear/PearScriptEngineFactory.java * classpath/pearscript/org/pear/PearScript.java - * @run testng/othervm ModulesTest + * @run junit/othervm ModulesTest * @summary Basic test for ServiceLoader with a provider deployed as a module. */ @@ -55,9 +55,10 @@ import javax.script.ScriptEngineFactory; import jdk.test.lib.util.JarUtils; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeTest; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; /** * Basic test for ServiceLoader. The test make use of two service providers: @@ -67,12 +68,11 @@ import static org.testng.Assert.*; * 2. PearScriptEngine - a ScriptEngineFactory deployed on the class path * with a service configuration file. */ - public class ModulesTest { // Copy the services configuration file for "pearscript" into place. - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { Path src = Paths.get(System.getProperty("test.src")); Path classes = Paths.get(System.getProperty("test.classes")); String st = ScriptEngineFactory.class.getName(); @@ -428,30 +428,36 @@ public class ModulesTest { // -- nulls -- - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull1() { - ServiceLoader.load(null); + Assertions.assertThrows(NullPointerException.class, + () -> ServiceLoader.load(null)); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull2() { - ServiceLoader.load((Class) null, ClassLoader.getSystemClassLoader()); + Assertions.assertThrows(NullPointerException.class, + () -> ServiceLoader.load((Class) null, ClassLoader.getSystemClassLoader())); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull3() { class S { } - ServiceLoader.load((ModuleLayer) null, S.class); + Assertions.assertThrows(NullPointerException.class, () -> { + ServiceLoader.load((ModuleLayer) null, S.class); + }); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull4() { - ServiceLoader.load(ModuleLayer.empty(), null); + Assertions.assertThrows(NullPointerException.class, + () -> ServiceLoader.load(ModuleLayer.empty(), null)); } - @Test(expectedExceptions = { NullPointerException.class }) + @Test public void testLoadNull5() { - ServiceLoader.loadInstalled(null); + Assertions.assertThrows(NullPointerException.class, + () -> ServiceLoader.loadInstalled(null)); } /** diff --git a/test/jdk/java/util/ServiceLoader/NoInterferenceTest.java b/test/jdk/java/util/ServiceLoader/NoInterferenceTest.java index ff83b836e20..d91bc9c759f 100644 --- a/test/jdk/java/util/ServiceLoader/NoInterferenceTest.java +++ b/test/jdk/java/util/ServiceLoader/NoInterferenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @modules jdk.compiler * @build jdk.test.lib.compiler.CompilerUtils - * @run testng NoInterferenceTest + * @run junit NoInterferenceTest * @summary Basic test of ServiceLoader that ensures there is no interference * when there are two service interfaces of the same name in a layer * or overridden in a child layer. @@ -46,9 +46,9 @@ import java.util.Set; 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; public class NoInterferenceTest { @@ -57,8 +57,8 @@ public class NoInterferenceTest { private static final Path MODS_DIR = Paths.get("mods"); private static final List MODULES = Arrays.asList("s1", "p1", "s2", "p2"); - @BeforeTest - void compile() throws Exception { + @BeforeAll + static void compile() throws Exception { Files.createDirectory(MODS_DIR); for (String name : MODULES) { Path src = SRC_DIR.resolve(name); diff --git a/test/jdk/java/util/ServiceLoader/ReloadTest.java b/test/jdk/java/util/ServiceLoader/ReloadTest.java index d48b5c29f4d..be2c0d68773 100644 --- a/test/jdk/java/util/ServiceLoader/ReloadTest.java +++ b/test/jdk/java/util/ServiceLoader/ReloadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @modules java.scripting * @library modules classpath/pearscript * @build ReloadTest org.pear.PearScript org.pear.PearScriptEngineFactory bananascript/* - * @run testng/othervm ReloadTest + * @run junit/othervm ReloadTest * @summary Basic test of ServiceLoader.reload */ @@ -40,12 +40,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static java.util.ServiceLoader.*; import javax.script.ScriptEngineFactory; -import org.testng.annotations.Test; -import static org.testng.Assert.*; -@Test +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + public class ReloadTest { + @Test public void testReload() { ServiceLoader sl = load(ScriptEngineFactory.class); List names1 = sl.stream() @@ -58,41 +60,42 @@ public class ReloadTest { .map(Provider::get) .map(ScriptEngineFactory::getEngineName) .collect(Collectors.toList()); - assertEquals(names1, names2); + assertEquals(names2, names1); } - @Test(expectedExceptions = { ConcurrentModificationException.class }) + @Test public void testIteratorHasNext() { ServiceLoader sl = load(ScriptEngineFactory.class); Iterator iterator = sl.iterator(); sl.reload(); - iterator.hasNext(); + Assertions.assertThrows(ConcurrentModificationException.class, iterator::hasNext); } - @Test(expectedExceptions = { ConcurrentModificationException.class }) + @Test public void testIteratorNext() { ServiceLoader sl = load(ScriptEngineFactory.class); Iterator iterator = sl.iterator(); assertTrue(iterator.hasNext()); sl.reload(); - iterator.next(); + Assertions.assertThrows(ConcurrentModificationException.class, iterator::next); } - @Test(expectedExceptions = { ConcurrentModificationException.class }) + @Test public void testStreamFindAny() { ServiceLoader sl = load(ScriptEngineFactory.class); Stream> stream = sl.stream(); sl.reload(); - stream.findAny(); + Assertions.assertThrows(ConcurrentModificationException.class, stream::findAny); } - @Test(expectedExceptions = { ConcurrentModificationException.class }) + @Test public void testSpliteratorTryAdvance() { ServiceLoader sl = load(ScriptEngineFactory.class); Stream> stream = sl.stream(); Spliterator> spliterator = stream.spliterator(); sl.reload(); - spliterator.tryAdvance(System.out::println); + Assertions.assertThrows(ConcurrentModificationException.class, + () -> spliterator.tryAdvance(System.out::println)); } } diff --git a/test/jdk/java/util/ServiceLoader/TwoIterators.java b/test/jdk/java/util/ServiceLoader/TwoIterators.java index ddb9cc09508..b86cc45f17f 100644 --- a/test/jdk/java/util/ServiceLoader/TwoIterators.java +++ b/test/jdk/java/util/ServiceLoader/TwoIterators.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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 * @summary Test ServiceLoader with two iterators, interleaving their use * to test that they don't interfere with each other - * @run testng TwoIterators + * @run junit TwoIterators */ import java.nio.file.Files; @@ -35,9 +35,9 @@ import java.util.Arrays; import java.util.Iterator; import java.util.ServiceLoader; -import org.testng.annotations.BeforeClass; -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; public class TwoIterators { @@ -48,18 +48,17 @@ public class TwoIterators { public static class S1 implements S { } public static class S2 implements S { } - private ClassLoader testClassLoader; + private static ClassLoader testClassLoader; // creates the services configuration file and sets the ClassLoader - @BeforeClass - void setup() throws Exception { + @BeforeAll + static void setup() throws Exception { String classes = System.getProperty("test.classes"); Path dir = Paths.get(classes, "META-INF", "services"); Files.createDirectories(dir); Path config = dir.resolve(S.class.getName()); Files.write(config, Arrays.asList(S1.class.getName(), S2.class.getName())); - - this.testClassLoader = TwoIterators.class.getClassLoader(); + testClassLoader = TwoIterators.class.getClassLoader(); } @Test diff --git a/test/jdk/java/util/ServiceLoader/basic/ServiceLoaderBasicTest.java b/test/jdk/java/util/ServiceLoader/basic/ServiceLoaderBasicTest.java index 91aba564cd1..4a9bc808851 100644 --- a/test/jdk/java/util/ServiceLoader/basic/ServiceLoaderBasicTest.java +++ b/test/jdk/java/util/ServiceLoader/basic/ServiceLoaderBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @build jdk.test.lib.process.* * jdk.test.lib.util.JarUtils * Basic Load FooService FooProvider1 FooProvider2 FooProvider3 BarProvider - * @run testng ServiceLoaderBasicTest + * @run junit ServiceLoaderBasicTest */ @@ -44,14 +44,16 @@ import jdk.test.lib.Utils; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.util.JarUtils; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static java.util.Arrays.asList; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + public class ServiceLoaderBasicTest { private static final String METAINFO = "META-INF/services/FooService"; @@ -79,8 +81,8 @@ public class ServiceLoaderBasicTest { private static final String XTESTXMETA_CP = XTEST_CP + XMETA; private static final String XTESTXMETAP2_CP = XTESTXMETA_CP + P2; - @BeforeClass - public void initialize() throws Exception { + @BeforeAll + public static void initialize() throws Exception { createProviderConfig(XTEST_CONFIG, "FooProvider1"); createProviderConfig(XMETA_CONFIG, "FooProvider42"); createJar(P2JAR, "FooProvider2", List.of("FooProvider2")); @@ -88,8 +90,7 @@ public class ServiceLoaderBasicTest { Files.copy(P2JAR, P2DUPJAR, REPLACE_EXISTING); } - @DataProvider - public Object[][] testCases() { + private static Object[][] testCases() { return new Object[][]{ // CLI options, Test, Runtime arguments // Success cases @@ -110,23 +111,14 @@ public class ServiceLoaderBasicTest { }; } - @DataProvider - public Object[][] negativeTestCases() { - return new Object[][]{ - {"blah blah"}, - {"9234"}, - {"X!"}, - {"BarProvider"}, - {"FooProvider42"} - }; - } - - @Test(dataProvider = "testCases") + @ParameterizedTest + @MethodSource("testCases") public void testProvider(List args) throws Throwable { runJava(args); } - @Test(dataProvider = "negativeTestCases") + @ParameterizedTest // negative test cases + @ValueSource(strings = { "blah blah", "9234", "X!", "BarProvider", "FooProvider42" }) public void testBadProvider(String providerName) throws Throwable { Files.write(XMETA_CONFIG, providerName.getBytes()); runJava(List.of("-cp", XMETA_CP, "Load", "fail")); @@ -144,12 +136,12 @@ public class ServiceLoaderBasicTest { .shouldHaveExitValue(0); } - private void createProviderConfig(Path config, String providerName) throws Exception { + private static void createProviderConfig(Path config, String providerName) throws Exception { Files.createDirectories(config.getParent()); Files.write(config, providerName.getBytes(), CREATE); } - private void createJar(Path jar, String provider, List files) throws Exception { + private static void createJar(Path jar, String provider, List files) throws Exception { Path xdir = Path.of(provider); createProviderConfig(xdir.resolve(METAINFO), provider); diff --git a/test/jdk/java/util/StringJoiner/MergeTest.java b/test/jdk/java/util/StringJoiner/MergeTest.java index f47ed3ee094..574124b9bdd 100644 --- a/test/jdk/java/util/StringJoiner/MergeTest.java +++ b/test/jdk/java/util/StringJoiner/MergeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 @@ * @summary test StringJoiner::merge * @modules java.base/jdk.internal.util * @requires vm.bits == "64" & os.maxMemory > 4G - * @run testng/othervm -Xmx4g -XX:+CompactStrings MergeTest + * @run junit/othervm -Xmx4g -XX:+CompactStrings MergeTest */ import java.util.StringJoiner; import java.util.stream.Stream; -import org.testng.annotations.Test; import static jdk.internal.util.ArraysSupport.SOFT_MAX_ARRAY_LENGTH; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; -@Test +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; + public class MergeTest { private static final String[] PREFIXES = {"", "{", "@#$%"}; private static final String[] SUFFIXES = {"", "}", "*&%$"}; @@ -69,12 +70,13 @@ public class MergeTest { return builder.build(); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void testNull() { StringJoiner sj = new StringJoiner(",", "{", "}"); - sj.merge(null); + Assertions.assertThrows(NullPointerException.class, () -> sj.merge(null)); } + @Test public void testSimple() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -83,10 +85,11 @@ public class MergeTest { Stream.of("d", "e", "f").forEachOrdered(other::add); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "a,b,c,d,e,f" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,c,d,e,f" + fixes.suf0, sj.toString()); }); } + @Test public void testEmptyOther() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -94,14 +97,15 @@ public class MergeTest { Stream.of("a", "b", "c").forEachOrdered(sj::add); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "a,b,c" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,c" + fixes.suf0, sj.toString()); other.setEmptyValue("EMPTY"); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "a,b,c" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,c" + fixes.suf0, sj.toString()); }); } + @Test public void testEmptyThis() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -109,34 +113,36 @@ public class MergeTest { Stream.of("d", "e", "f").forEachOrdered(other::add); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "d:e:f" + fixes.suf0); + assertEquals(fixes.pre0 + "d:e:f" + fixes.suf0, sj.toString()); sj = new StringJoiner(",", fixes.pre0, fixes.suf0).setEmptyValue("EMPTY"); - assertEquals(sj.toString(), "EMPTY"); + assertEquals("EMPTY", sj.toString()); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "d:e:f" + fixes.suf0); + assertEquals(fixes.pre0 + "d:e:f" + fixes.suf0, sj.toString()); }); } + @Test public void testEmptyBoth() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); StringJoiner other = new StringJoiner(":", fixes.pre1, fixes.suf1); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + fixes.suf0); + assertEquals(fixes.pre0 + fixes.suf0, sj.toString()); other.setEmptyValue("NOTHING"); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + fixes.suf0); + assertEquals(fixes.pre0 + fixes.suf0, sj.toString()); sj = new StringJoiner(",", fixes.pre0, fixes.suf0).setEmptyValue("EMPTY"); - assertEquals(sj.toString(), "EMPTY"); + assertEquals("EMPTY", sj.toString()); sj.merge(other); - assertEquals(sj.toString(), "EMPTY"); + assertEquals("EMPTY", sj.toString()); }); } + @Test public void testCascadeEmpty() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -144,13 +150,14 @@ public class MergeTest { StringJoiner o2 = new StringJoiner(",", "<", ">").setEmptyValue("Empty2"); o1.merge(o2); - assertEquals(o1.toString(), "Empty1"); + assertEquals("Empty1", o1.toString()); sj.merge(o1); - assertEquals(sj.toString(), fixes.pre0 + fixes.suf0); + assertEquals(fixes.pre0 + fixes.suf0, sj.toString()); }); } + @Test public void testDelimiter() { fixesStream().forEach(fixes -> { StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0); @@ -159,18 +166,20 @@ public class MergeTest { Stream.of("d", "e", "f").forEachOrdered(other::add); sj.merge(other); - assertEquals(sj.toString(), fixes.pre0 + "a,b,c,d:e:f" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,c,d:e:f" + fixes.suf0, sj.toString()); }); } + @Test public void testMergeSelf() { fixesStream().forEach(fixes -> { final StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0).add("a").add("b"); - assertEquals(sj.merge(sj).toString(), fixes.pre0 + "a,b,a,b" + fixes.suf0); - assertEquals(sj.merge(sj).toString(), fixes.pre0 + "a,b,a,b,a,b,a,b" + fixes.suf0); + assertEquals(fixes.pre0 + "a,b,a,b" + fixes.suf0, sj.merge(sj).toString()); + assertEquals(fixes.pre0 + "a,b,a,b,a,b,a,b" + fixes.suf0, sj.merge(sj).toString()); }); } + @Test public void OOM() { String maxString = "*".repeat(SOFT_MAX_ARRAY_LENGTH); diff --git a/test/jdk/java/util/StringJoiner/StringJoinerOomUtf16Test.java b/test/jdk/java/util/StringJoiner/StringJoinerOomUtf16Test.java index b45e66b4d8b..7fde8b36ffa 100644 --- a/test/jdk/java/util/StringJoiner/StringJoinerOomUtf16Test.java +++ b/test/jdk/java/util/StringJoiner/StringJoinerOomUtf16Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +26,23 @@ * @summary tests StringJoiner OOME when joining sub-max-length Strings * @modules java.base/jdk.internal.util * @requires vm.bits == "64" & os.maxMemory > 4G - * @run testng/othervm -Xmx4g -XX:+CompactStrings StringJoinerOomUtf16Test + * @run junit/othervm -Xmx4g -XX:+CompactStrings StringJoinerOomUtf16Test */ -import org.testng.annotations.Test; import static jdk.internal.util.ArraysSupport.SOFT_MAX_ARRAY_LENGTH; -import static org.testng.Assert.fail; + +import static org.junit.jupiter.api.Assertions.fail; import java.util.StringJoiner; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; -@Test(groups = {"unit","string","util","libs"}) +@Tag("unit") +@Tag("string") +@Tag("util") +@Tag("libs") public class StringJoinerOomUtf16Test { // the sum of lengths of the following two strings is way less than @@ -48,6 +53,7 @@ public class StringJoinerOomUtf16Test { private static final String OVERFLOW_UTF16_STRING = "\u017D".repeat(((Integer.MAX_VALUE - SOFT_MAX_ARRAY_LENGTH) >> 1) + 1); + @Test public void OOM1() { try { new StringJoiner("") @@ -60,6 +66,7 @@ public class StringJoinerOomUtf16Test { } } + @Test public void OOM2() { try { new StringJoiner(HALF_MAX_LATIN1_STRING) @@ -72,6 +79,7 @@ public class StringJoinerOomUtf16Test { } } + @Test public void OOM3() { try { new StringJoiner(OVERFLOW_UTF16_STRING) @@ -84,6 +92,7 @@ public class StringJoinerOomUtf16Test { } } + @Test public void OOM4() { try { new StringJoiner("", HALF_MAX_LATIN1_STRING, OVERFLOW_UTF16_STRING) diff --git a/test/jdk/java/util/StringJoiner/StringJoinerTest.java b/test/jdk/java/util/StringJoiner/StringJoinerTest.java index 25948fb8e55..aa25623dbc3 100644 --- a/test/jdk/java/util/StringJoiner/StringJoinerTest.java +++ b/test/jdk/java/util/StringJoiner/StringJoinerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +26,25 @@ * @summary tests StringJoinerTest * @modules java.base/jdk.internal.util * @requires vm.bits == "64" & os.maxMemory > 4G - * @run testng/othervm -Xmx4g -XX:+CompactStrings StringJoinerTest + * @run junit/othervm -Xmx4g -XX:+CompactStrings StringJoinerTest * @author Jim Gish */ + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + import java.util.ArrayList; import java.util.StringJoiner; -import org.testng.annotations.Test; + import static jdk.internal.util.ArraysSupport.SOFT_MAX_ARRAY_LENGTH; -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; - -@Test(groups = {"unit","string","util","libs"}) +@Tag("unit") +@Tag("string") +@Tag("util") +@Tag("libs") public class StringJoinerTest { private static final String EMPTY = "EMPTY"; @@ -51,6 +58,7 @@ public class StringJoinerTest { private static final String DASH = "-"; private static final String MAX_STRING = "*".repeat(SOFT_MAX_ARRAY_LENGTH); + @Test public void addAddAll() { StringJoiner sj = new StringJoiner(DASH, "{", "}"); sj.add(ONE); @@ -61,7 +69,7 @@ public class StringJoinerTest { nextOne.stream().forEachOrdered(sj::add); String expected = "{"+ONE+DASH+TWO+DASH+THREE+"}"; - assertEquals(sj.toString(), expected); + assertEquals(expected, sj.toString()); } void addAlladd() { @@ -75,10 +83,11 @@ public class StringJoinerTest { sj.add(THREE); String expected = "{"+ONE+DASH+TWO+DASH+THREE+"}"; - assertEquals(sj.toString(), expected); + assertEquals(expected, sj.toString()); } // The following tests do two successive adds of different types + @Test public void addAlladdAll() { StringJoiner sj = new StringJoiner(DASH, "{", "}"); ArrayList firstOne = new ArrayList<>(); @@ -93,9 +102,10 @@ public class StringJoinerTest { nextOne.stream().forEachOrdered(sj::add); String expected = "{"+ONE+DASH+TWO+DASH+THREE+DASH+FOUR+DASH+FIVE+"}"; - assertEquals(sj.toString(), expected); + assertEquals(expected, sj.toString()); } + @Test public void addCharSequence() { StringJoiner sj = new StringJoiner(","); CharSequence cs_one = ONE; @@ -104,13 +114,13 @@ public class StringJoinerTest { sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), ONE + "," + TWO); + assertEquals(ONE + "," + TWO, sj.toString()); sj = new StringJoiner(DASH, "{", "}"); sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}"); + assertEquals("{" + ONE + DASH + TWO + "}", sj.toString()); StringBuilder builder = new StringBuilder(ONE); StringBuffer buffer = new StringBuffer(THREE); @@ -118,13 +128,14 @@ public class StringJoinerTest { sj.add(builder).add(buffer); builder.append(TWO); buffer.append(FOUR); - assertEquals(sj.toString(), "{ " + ONE + ", " + THREE + " }", + assertEquals("{ " + ONE + ", " + THREE + " }", sj.toString(), "CharSequence is copied when add"); sj.add(builder); - assertEquals(sj.toString(), "{ " + ONE + ", " + THREE + ", " + ONE + - TWO + " }"); + assertEquals("{ " + ONE + ", " + THREE + ", " + ONE + + TWO + " }", sj.toString()); } + @Test public void addCharSequenceWithEmptyValue() { StringJoiner sj = new StringJoiner(",").setEmptyValue(EMPTY); CharSequence cs_one = ONE; @@ -133,189 +144,200 @@ public class StringJoinerTest { sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), ONE + "," + TWO); + assertEquals(ONE + "," + TWO, sj.toString()); sj = new StringJoiner(DASH, "{", "}"); sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}"); + assertEquals("{" + ONE + DASH + TWO + "}", sj.toString()); sj = new StringJoiner(DASH, "{", "}"); - assertEquals(sj.toString(), "{}"); + assertEquals("{}", sj.toString()); sj = new StringJoiner("=", "{", "}").setEmptyValue(""); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(DASH, "{", "}").setEmptyValue(EMPTY); - assertEquals(sj.toString(), EMPTY); + assertEquals(EMPTY, sj.toString()); sj.add(cs_one); sj.add(cs_two); - assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}"); + assertEquals("{" + ONE + DASH + TWO + "}", sj.toString()); } + @Test public void addString() { StringJoiner sj = new StringJoiner(DASH); sj.add(ONE); - assertEquals(sj.toString(), ONE); + assertEquals(ONE, sj.toString()); sj = new StringJoiner(DASH, "{", "}"); sj.add(ONE); - assertEquals(sj.toString(), "{" + ONE + "}"); + assertEquals("{" + ONE + "}", sj.toString()); sj.add(TWO); - assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}"); + assertEquals("{" + ONE + DASH + TWO + "}", sj.toString()); } + @Test public void lengthWithCustomEmptyValue() { StringJoiner sj = new StringJoiner(DASH, "<", ">").setEmptyValue(EMPTY); - assertEquals(sj.length(), EMPTY.length()); + assertEquals(EMPTY.length(), sj.length()); sj.add(""); - assertEquals(sj.length(), "<>".length()); + assertEquals("<>".length(), sj.length()); sj.add(""); - assertEquals(sj.length(), "<->".length()); + assertEquals("<->".length(), sj.length()); sj.add(ONE); - assertEquals(sj.length(), 4 + ONE_LEN); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(4 + ONE_LEN, sj.length()); + assertEquals(sj.length(), sj.toString().length()); sj.add(TWO); - assertEquals(sj.length(), 5 + ONE_LEN + TWO_LEN); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(5 + ONE_LEN + TWO_LEN, sj.length()); + assertEquals(sj.length(), sj.toString().length()); sj = new StringJoiner("||", "<", "-->"); - assertEquals(sj.length(), 4); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(4, sj.length()); + assertEquals(sj.length(), sj.toString().length()); sj.add("abcdef"); - assertEquals(sj.length(), 10); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(10, sj.length()); + assertEquals(sj.length(), sj.toString().length()); sj.add("xyz"); - assertEquals(sj.length(), 15); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(15, sj.length()); + assertEquals(sj.length(), sj.toString().length()); } + @Test public void noAddAndEmptyValue() { StringJoiner sj = new StringJoiner(DASH, "", "").setEmptyValue(EMPTY); - assertEquals(sj.toString(), EMPTY); + assertEquals(EMPTY, sj.toString()); sj = new StringJoiner(DASH, "<..", ""); - assertEquals(sj.toString(), "<.."); + assertEquals("<..", sj.toString()); sj = new StringJoiner(DASH, "<..", ""); - assertEquals(sj.toString(), "<.."); + assertEquals("<..", sj.toString()); sj = new StringJoiner(DASH, "", "==>"); - assertEquals(sj.toString(), "==>"); + assertEquals("==>", sj.toString()); sj = new StringJoiner(DASH, "{", "}"); - assertEquals(sj.toString(), "{}"); + assertEquals("{}", sj.toString()); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void setEmptyValueNull() { - new StringJoiner(DASH, "{", "}").setEmptyValue(null); + Assertions.assertThrows(NullPointerException.class, + () -> new StringJoiner(DASH, "{", "}").setEmptyValue(null)); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void setDelimiterNull() { - new StringJoiner(null); + Assertions.assertThrows(NullPointerException.class, + () -> new StringJoiner(null)); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void setPrefixNull() { - new StringJoiner(DASH, null, "}"); + Assertions.assertThrows(NullPointerException.class, + () -> new StringJoiner(DASH, null, "}")); } - @Test(expectedExceptions = {NullPointerException.class}) + @Test public void setSuffixNull() { - new StringJoiner(DASH, "{", null); + Assertions.assertThrows(NullPointerException.class, + () -> new StringJoiner(DASH, "{", null)); } + @Test public void stringFromtoString() { StringJoiner sj = new StringJoiner(", "); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(",", "{", "}"); - assertEquals(sj.toString(), "{}"); + assertEquals("{}", sj.toString()); sj = new StringJoiner(","); sj.add(ONE); - assertEquals(sj.toString(), ONE); + assertEquals(ONE, sj.toString()); sj.add(TWO); - assertEquals(sj.toString(), ONE + "," + TWO); + assertEquals(ONE + "," + TWO, sj.toString()); sj = new StringJoiner(",", "{--", "--}"); sj.add(ONE); sj.add(TWO); - assertEquals(sj.toString(), "{--" + ONE + "," + TWO + "--}"); + assertEquals("{--" + ONE + "," + TWO + "--}", sj.toString()); } + @Test public void stringFromtoStringWithEmptyValue() { StringJoiner sj = new StringJoiner(" ", "", ""); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(", "); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(",", "{", "}"); - assertEquals(sj.toString(), "{}"); + assertEquals("{}", sj.toString()); sj = new StringJoiner(",", "{", "}").setEmptyValue(""); - assertEquals(sj.toString(), ""); + assertEquals("", sj.toString()); sj = new StringJoiner(","); sj.add(ONE); - assertEquals(sj.toString(), ONE); + assertEquals(ONE, sj.toString()); sj.add(TWO); - assertEquals(sj.toString(), ONE + "," + TWO); + assertEquals(ONE + "," + TWO, sj.toString()); sj = new StringJoiner(",", "{--", "--}"); sj.add(ONE); - assertEquals(sj.toString(), "{--" + ONE + "--}" ); + assertEquals("{--" + ONE + "--}", sj.toString() ); sj.add(TWO); - assertEquals(sj.toString(), "{--" + ONE + "," + TWO + "--}"); + assertEquals("{--" + ONE + "," + TWO + "--}", sj.toString()); } + @Test public void toStringWithCustomEmptyValue() { StringJoiner sj = new StringJoiner(DASH, "<", ">").setEmptyValue(EMPTY); - assertEquals(sj.toString(), EMPTY); + assertEquals(EMPTY, sj.toString()); sj.add(""); - assertEquals(sj.toString(), "<>"); + assertEquals("<>", sj.toString()); sj.add(""); - assertEquals(sj.toString(), "<->"); + assertEquals("<->", sj.toString()); } private void testCombos(String infix, String prefix, String suffix) { StringJoiner sj = new StringJoiner(infix, prefix, suffix); - assertEquals(sj.toString(), prefix + suffix); - assertEquals(sj.toString().length(), sj.length()); + assertEquals(prefix + suffix, sj.toString()); + assertEquals(sj.length(), sj.toString().length()); // EmptyValue sj = new StringJoiner(infix, prefix, suffix).setEmptyValue(""); - assertEquals(sj.toString(), ""); - assertEquals(sj.toString().length(), sj.length()); + assertEquals("", sj.toString()); + assertEquals(sj.length(), sj.toString().length()); // empty in front sj.add(""); - assertEquals(sj.toString(), prefix + suffix); + assertEquals(prefix + suffix, sj.toString()); // empty in middle sj.add(""); - assertEquals(sj.toString(), prefix + infix + suffix); + assertEquals(prefix + infix + suffix, sj.toString()); sj.add("1"); - assertEquals(sj.toString(), prefix + infix + infix + "1" + suffix); + assertEquals(prefix + infix + infix + "1" + suffix, sj.toString()); // empty at end sj.add(""); - assertEquals(sj.toString(), prefix + infix + infix + "1" + infix + suffix); + assertEquals(prefix + infix + infix + "1" + infix + suffix, sj.toString()); sj = new StringJoiner(infix, prefix, suffix).setEmptyValue(""); sj.add("1"); - assertEquals(sj.toString(), prefix + "1" + suffix); + assertEquals(prefix + "1" + suffix, sj.toString()); sj.add("2"); - assertEquals(sj.toString(), prefix + "1" + infix + "2" + suffix); + assertEquals(prefix + "1" + infix + "2" + suffix, sj.toString()); sj.add(""); - assertEquals(sj.toString(), prefix + "1" + infix + "2" + infix + suffix); + assertEquals(prefix + "1" + infix + "2" + infix + suffix, sj.toString()); sj.add("3"); - assertEquals(sj.toString(), prefix + "1" + infix + "2" + infix + infix + "3" + suffix); + assertEquals(prefix + "1" + infix + "2" + infix + infix + "3" + suffix, sj.toString()); } + @Test public void testDelimiterCombinations() { testCombos("", "", ""); testCombos("", "<", ""); @@ -327,6 +349,7 @@ public class StringJoinerTest { testCombos(",", "<", ">"); } + @Test public void OOM1() { try { new StringJoiner(MAX_STRING, MAX_STRING, MAX_STRING).toString(); @@ -336,6 +359,7 @@ public class StringJoinerTest { } } + @Test public void OOM2() { try { new StringJoiner(MAX_STRING, MAX_STRING, "").toString(); @@ -345,6 +369,7 @@ public class StringJoinerTest { } } + @Test public void OOM3() { try { new StringJoiner(MAX_STRING, "", MAX_STRING).toString(); @@ -354,6 +379,7 @@ public class StringJoinerTest { } } + @Test public void OOM4() { try { new StringJoiner("", MAX_STRING, MAX_STRING).toString(); diff --git a/test/jdk/java/util/Vector/ArrayManagement.java b/test/jdk/java/util/Vector/ArrayManagement.java index ce4e695487c..c1fa6d1c9bc 100644 --- a/test/jdk/java/util/Vector/ArrayManagement.java +++ b/test/jdk/java/util/Vector/ArrayManagement.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * Copyright 2016 Google, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,7 +26,7 @@ * @test * @bug 8148174 * @summary brittle white box test of internal array management - * @run testng ArrayManagement + * @run junit ArrayManagement */ import java.lang.reflect.Field; @@ -35,8 +36,8 @@ import java.util.Collections; import java.util.List; import java.util.SplittableRandom; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class ArrayManagement { @@ -61,9 +62,9 @@ public class ArrayManagement { super.ensureCapacity(minCapacity); assertTrue(capacity() >= minCapacity); if (minCapacity <= oldCapacity) - assertEquals(capacity(), oldCapacity); + assertEquals(oldCapacity, capacity()); if (minCapacity > 0) - assertEquals(modCount(), oldModCount + 1); + assertEquals(oldModCount + 1, modCount()); } } @@ -89,117 +90,117 @@ public class ArrayManagement { case 3: assertTrue(list.addAll(size, singletonList())); break; default: throw new AssertionError(); } - assertEquals(list.modCount(), modCount + 1); - assertEquals(list.size(), size + 1); + assertEquals(modCount + 1, list.modCount()); + assertEquals(size + 1, list.size()); } @Test public void defaultCapacity() { PublicVector list = new PublicVector<>(); - assertEquals(new PublicVector().capacity(), DEFAULT_CAPACITY); + assertEquals(DEFAULT_CAPACITY, new PublicVector().capacity()); for (int i = 0; i < DEFAULT_CAPACITY; i++) { addOneElement(list); - assertEquals(list.capacity(), DEFAULT_CAPACITY); + assertEquals(DEFAULT_CAPACITY, list.capacity()); } addOneElement(list); - assertEquals(list.capacity(), newCapacity(DEFAULT_CAPACITY)); + assertEquals(newCapacity(DEFAULT_CAPACITY), list.capacity()); } @Test public void defaultCapacityEnsureCapacity() { PublicVector list = new PublicVector<>(); for (int i = 0; i <= DEFAULT_CAPACITY; i++) { list.ensureCapacity(i); // no-op! - assertEquals(list.capacity(), DEFAULT_CAPACITY); + assertEquals(DEFAULT_CAPACITY, list.capacity()); } for (int i = 0; i < DEFAULT_CAPACITY; i++) { addOneElement(list); - assertEquals(list.capacity(), DEFAULT_CAPACITY); + assertEquals(DEFAULT_CAPACITY, list.capacity()); } addOneElement(list); - assertEquals(list.capacity(), newCapacity(DEFAULT_CAPACITY)); + assertEquals(newCapacity(DEFAULT_CAPACITY), list.capacity()); { int capacity = list.capacity(); list.ensureCapacity(capacity + 1); - assertEquals(list.capacity(), newCapacity(capacity)); + assertEquals(newCapacity(capacity), list.capacity()); } { int capacity = list.capacity(); list.ensureCapacity(3 * capacity); - assertEquals(list.capacity(), 3 * capacity); + assertEquals(3 * capacity, list.capacity()); } } @Test public void ensureCapacityBeyondDefaultCapacity() { PublicVector list = new PublicVector<>(); list.ensureCapacity(DEFAULT_CAPACITY + 1); - assertEquals(list.capacity(), newCapacity(DEFAULT_CAPACITY)); + assertEquals(newCapacity(DEFAULT_CAPACITY), list.capacity()); } @Test public void explicitZeroCapacity() { PublicVector list = new PublicVector<>(0); - assertEquals(list.capacity(), 0); + assertEquals(0, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 1); + assertEquals(1, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 2); + assertEquals(2, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 4); + assertEquals(4, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 4); + assertEquals(4, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); list.clear(); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); } @Test public void explicitZeroCapacityWithCapacityIncrement() { PublicVector list = new PublicVector<>(0, 2); - assertEquals(list.capacity(), 0); + assertEquals(0, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 2); + assertEquals(2, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 2); + assertEquals(2, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 4); + assertEquals(4, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 4); + assertEquals(4, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 6); + assertEquals(6, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 6); + assertEquals(6, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); list.clear(); - assertEquals(list.capacity(), 8); + assertEquals(8, list.capacity()); } @Test public void explicitLargeCapacity() { int n = DEFAULT_CAPACITY * 3; PublicVector list = new PublicVector<>(n); - assertEquals(list.capacity(), n); + assertEquals(n, list.capacity()); list.ensureCapacity(0); list.ensureCapacity(n); for (int i = 0; i < n; i++) addOneElement(list); - assertEquals(list.capacity(), n); + assertEquals(n, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), newCapacity(n)); + assertEquals(newCapacity(n), list.capacity()); } @Test public void explicitLargeCapacityWithCapacityIncrement() { int n = DEFAULT_CAPACITY * 3; PublicVector list = new PublicVector<>(n, 2); - assertEquals(list.capacity(), n); + assertEquals(n, list.capacity()); list.ensureCapacity(0); list.ensureCapacity(n); for (int i = 0; i < n; i++) addOneElement(list); - assertEquals(list.capacity(), n); + assertEquals(n, list.capacity()); addOneElement(list); - assertEquals(list.capacity(), n + 2); + assertEquals(n + 2, list.capacity()); } @Test public void emptyArraysAreNotShared() { diff --git a/test/jdk/javax/swing/JSplitPane/TestSplitPaneCompResize.java b/test/jdk/javax/swing/JSplitPane/TestSplitPaneCompResize.java new file mode 100644 index 00000000000..07d9b77f90e --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/TestSplitPaneCompResize.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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 4765299 + * @key headful + * @summary Verifies componentResized() is called with nested JSplitPanes + * @run main TestSplitPaneCompResize + */ + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.InputEvent; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JPanel; +import javax.swing.ListSelectionModel; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; +import javax.swing.SwingUtilities; + +public class TestSplitPaneCompResize { + + private static JFrame frame; + private JSplitPane outer; + private static JButton leftOneTouchButton; + private static volatile Point leftBtnPos; + private static volatile boolean resized; + + public TestSplitPaneCompResize() { + + // set up a simple list embedded inside a scroll pane + String[] listItems = {"Item1", "Item2"}; + JList list = new JList<>(listItems); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + list.setSelectedIndex(0); + + JScrollPane comp = new JScrollPane(list); + JSplitPane inner = new JSplitPane(JSplitPane.VERTICAL_SPLIT, + comp, new JPanel()); + JPanel rightPanel = new JPanel(); + + outer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + inner, rightPanel); + outer.setDividerLocation(150); + + //Provide minimum sizes for the two components in the split pane + Dimension minimumSize = new Dimension(100, 50); + comp.setMinimumSize(minimumSize); + inner.setMinimumSize(minimumSize); + rightPanel.setMinimumSize(minimumSize); + + //Provide a preferred size for the split pane + outer.setPreferredSize(new Dimension(400, 200)); + inner.addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent e) { + System.out.println("inner resized"); + } + }); + comp.addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent e) { + resized = true; + System.out.println("comp resized"); + } + }); + } + + public JSplitPane getSplitPane() { + return outer; + } + + + public static void main(String[] s) throws Exception { + Robot robot = new Robot(); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("SplitPaneDemo"); + + TestSplitPaneCompResize sp = new TestSplitPaneCompResize(); + JSplitPane jsp = sp.getSplitPane(); + frame.getContentPane().add(jsp); + jsp.setUI(new MySplitPaneUI()); + jsp.setOneTouchExpandable(true); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + leftBtnPos = leftOneTouchButton.getLocationOnScreen(); + leftBtnPos.x += leftOneTouchButton.getWidth() / 2; + leftBtnPos.y += leftOneTouchButton.getHeight() / 2; + }); + + resized = false; + robot.mouseMove(leftBtnPos.x, leftBtnPos.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(1000); + + if (!resized) { + throw new RuntimeException("ComponentResized not called"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + + static class MySplitPaneUI extends BasicSplitPaneUI { + + public MySplitPaneUI() { + super(); + } + + public BasicSplitPaneDivider createDefaultDivider() { + return new MySplitPaneDivider(this); + } + } + + static class MySplitPaneDivider extends BasicSplitPaneDivider { + + public MySplitPaneDivider(BasicSplitPaneUI ui) { + super(ui); + } + + protected JButton createLeftOneTouchButton() { + leftOneTouchButton = super.createLeftOneTouchButton(); + return leftOneTouchButton; + } + + protected JButton createRightOneTouchButton() { + JButton rightOneTouchButton = super.createRightOneTouchButton(); + return rightOneTouchButton; + } + } +} diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index 3ad6d6f320f..fae7b678a09 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Byte128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3611,7 +3623,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3620,7 +3632,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3632,20 +3644,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void ANDReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3653,8 +3660,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::ANDReduce, Byte128VectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3664,7 +3694,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3678,20 +3708,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3700,7 +3725,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3709,7 +3734,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3724,17 +3749,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3742,8 +3762,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::ORReduce, Byte128VectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3753,7 +3796,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3770,17 +3813,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3789,7 +3827,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3798,7 +3836,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3813,17 +3851,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3831,8 +3864,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::XORReduce, Byte128VectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3842,7 +3898,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3859,17 +3915,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3878,7 +3929,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3887,7 +3938,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3902,17 +3953,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3920,8 +3966,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::ADDReduce, Byte128VectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3931,7 +4000,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3948,17 +4017,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3967,7 +4031,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3976,7 +4040,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3988,20 +4052,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void MULReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4009,8 +4068,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::MULReduce, Byte128VectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4020,7 +4102,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4034,20 +4116,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4056,7 +4133,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4065,7 +4142,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4077,20 +4154,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void MINReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4098,8 +4170,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::MINReduce, Byte128VectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4109,7 +4204,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4123,20 +4218,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4145,7 +4235,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4154,7 +4244,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4166,20 +4256,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void MAXReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4187,8 +4272,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::MAXReduce, Byte128VectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4198,7 +4306,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4212,20 +4320,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4234,7 +4337,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4243,7 +4346,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4255,20 +4358,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void UMINReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4276,8 +4374,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::UMINReduce, Byte128VectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4287,7 +4408,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4301,20 +4422,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4323,7 +4439,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4332,7 +4448,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4344,20 +4460,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void UMAXReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4365,8 +4476,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::UMAXReduce, Byte128VectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4376,7 +4510,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4390,20 +4524,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4412,7 +4541,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4421,7 +4550,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4433,20 +4562,15 @@ public class Byte128VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4454,8 +4578,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::FIRST_NONZEROReduce, Byte128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4465,7 +4612,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4479,20 +4626,15 @@ public class Byte128VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4549,7 +4691,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4558,7 +4700,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4573,17 +4715,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4591,8 +4728,31 @@ public class Byte128VectorTests extends AbstractVectorTest { Byte128VectorTests::SUADDReduce, Byte128VectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4602,7 +4762,7 @@ public class Byte128VectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4618,17 +4778,12 @@ public class Byte128VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index d64caa3424f..0e59db7d05d 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Byte256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3611,7 +3623,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3620,7 +3632,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3632,20 +3644,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void ANDReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3653,8 +3660,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::ANDReduce, Byte256VectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3664,7 +3694,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3678,20 +3708,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3700,7 +3725,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3709,7 +3734,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3724,17 +3749,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3742,8 +3762,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::ORReduce, Byte256VectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3753,7 +3796,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3770,17 +3813,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3789,7 +3827,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3798,7 +3836,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3813,17 +3851,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3831,8 +3864,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::XORReduce, Byte256VectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3842,7 +3898,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3859,17 +3915,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3878,7 +3929,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3887,7 +3938,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3902,17 +3953,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3920,8 +3966,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::ADDReduce, Byte256VectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3931,7 +4000,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3948,17 +4017,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3967,7 +4031,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3976,7 +4040,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3988,20 +4052,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void MULReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4009,8 +4068,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::MULReduce, Byte256VectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4020,7 +4102,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4034,20 +4116,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4056,7 +4133,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4065,7 +4142,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4077,20 +4154,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void MINReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4098,8 +4170,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::MINReduce, Byte256VectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4109,7 +4204,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4123,20 +4218,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4145,7 +4235,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4154,7 +4244,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4166,20 +4256,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void MAXReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4187,8 +4272,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::MAXReduce, Byte256VectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4198,7 +4306,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4212,20 +4320,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4234,7 +4337,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4243,7 +4346,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4255,20 +4358,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void UMINReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4276,8 +4374,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::UMINReduce, Byte256VectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4287,7 +4408,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4301,20 +4422,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4323,7 +4439,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4332,7 +4448,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4344,20 +4460,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void UMAXReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4365,8 +4476,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::UMAXReduce, Byte256VectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4376,7 +4510,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4390,20 +4524,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4412,7 +4541,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4421,7 +4550,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4433,20 +4562,15 @@ public class Byte256VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4454,8 +4578,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::FIRST_NONZEROReduce, Byte256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4465,7 +4612,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4479,20 +4626,15 @@ public class Byte256VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4549,7 +4691,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4558,7 +4700,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4573,17 +4715,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4591,8 +4728,31 @@ public class Byte256VectorTests extends AbstractVectorTest { Byte256VectorTests::SUADDReduce, Byte256VectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4602,7 +4762,7 @@ public class Byte256VectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4618,17 +4778,12 @@ public class Byte256VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index f494e3d3ae8..5ad3bbdbc05 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Byte512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3611,7 +3623,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3620,7 +3632,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3632,20 +3644,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void ANDReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3653,8 +3660,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::ANDReduce, Byte512VectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3664,7 +3694,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3678,20 +3708,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3700,7 +3725,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3709,7 +3734,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3724,17 +3749,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3742,8 +3762,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::ORReduce, Byte512VectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3753,7 +3796,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3770,17 +3813,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3789,7 +3827,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3798,7 +3836,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3813,17 +3851,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3831,8 +3864,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::XORReduce, Byte512VectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3842,7 +3898,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3859,17 +3915,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3878,7 +3929,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3887,7 +3938,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3902,17 +3953,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3920,8 +3966,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::ADDReduce, Byte512VectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3931,7 +4000,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3948,17 +4017,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3967,7 +4031,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3976,7 +4040,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3988,20 +4052,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void MULReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4009,8 +4068,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::MULReduce, Byte512VectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4020,7 +4102,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4034,20 +4116,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4056,7 +4133,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4065,7 +4142,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4077,20 +4154,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void MINReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4098,8 +4170,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::MINReduce, Byte512VectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4109,7 +4204,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4123,20 +4218,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4145,7 +4235,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4154,7 +4244,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4166,20 +4256,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void MAXReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4187,8 +4272,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::MAXReduce, Byte512VectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4198,7 +4306,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4212,20 +4320,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4234,7 +4337,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4243,7 +4346,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4255,20 +4358,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void UMINReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4276,8 +4374,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::UMINReduce, Byte512VectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4287,7 +4408,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4301,20 +4422,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4323,7 +4439,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4332,7 +4448,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4344,20 +4460,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void UMAXReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4365,8 +4476,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::UMAXReduce, Byte512VectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4376,7 +4510,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4390,20 +4524,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4412,7 +4541,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4421,7 +4550,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4433,20 +4562,15 @@ public class Byte512VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4454,8 +4578,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::FIRST_NONZEROReduce, Byte512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4465,7 +4612,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4479,20 +4626,15 @@ public class Byte512VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4549,7 +4691,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4558,7 +4700,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4573,17 +4715,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4591,8 +4728,31 @@ public class Byte512VectorTests extends AbstractVectorTest { Byte512VectorTests::SUADDReduce, Byte512VectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4602,7 +4762,7 @@ public class Byte512VectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4618,17 +4778,12 @@ public class Byte512VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index da2961cd97b..e28fb2b2001 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Byte64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3611,7 +3623,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3620,7 +3632,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3632,20 +3644,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void ANDReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3653,8 +3660,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::ANDReduce, Byte64VectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3664,7 +3694,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3678,20 +3708,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3700,7 +3725,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3709,7 +3734,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3724,17 +3749,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3742,8 +3762,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::ORReduce, Byte64VectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3753,7 +3796,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3770,17 +3813,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3789,7 +3827,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3798,7 +3836,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3813,17 +3851,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3831,8 +3864,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::XORReduce, Byte64VectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3842,7 +3898,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3859,17 +3915,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3878,7 +3929,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3887,7 +3938,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3902,17 +3953,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3920,8 +3966,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::ADDReduce, Byte64VectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3931,7 +4000,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3948,17 +4017,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3967,7 +4031,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3976,7 +4040,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3988,20 +4052,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void MULReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4009,8 +4068,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::MULReduce, Byte64VectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4020,7 +4102,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4034,20 +4116,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4056,7 +4133,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4065,7 +4142,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4077,20 +4154,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void MINReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4098,8 +4170,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::MINReduce, Byte64VectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4109,7 +4204,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4123,20 +4218,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4145,7 +4235,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4154,7 +4244,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4166,20 +4256,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void MAXReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4187,8 +4272,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::MAXReduce, Byte64VectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4198,7 +4306,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4212,20 +4320,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4234,7 +4337,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4243,7 +4346,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4255,20 +4358,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void UMINReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4276,8 +4374,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::UMINReduce, Byte64VectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4287,7 +4408,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4301,20 +4422,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4323,7 +4439,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4332,7 +4448,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4344,20 +4460,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void UMAXReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4365,8 +4476,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::UMAXReduce, Byte64VectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4376,7 +4510,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4390,20 +4524,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4412,7 +4541,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4421,7 +4550,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4433,20 +4562,15 @@ public class Byte64VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4454,8 +4578,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::FIRST_NONZEROReduce, Byte64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4465,7 +4612,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4479,20 +4626,15 @@ public class Byte64VectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4549,7 +4691,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4558,7 +4700,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4573,17 +4715,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4591,8 +4728,31 @@ public class Byte64VectorTests extends AbstractVectorTest { Byte64VectorTests::SUADDReduce, Byte64VectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4602,7 +4762,7 @@ public class Byte64VectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4618,17 +4778,12 @@ public class Byte64VectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index a5872219f10..b6932785b55 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +71,19 @@ public class ByteMaxVectorTests extends AbstractVectorTest { private static final byte CONST_SHIFT = Byte.SIZE / 2; + // Identity values for reduction operations + private static final byte ADD_IDENTITY = (byte)0; + private static final byte AND_IDENTITY = (byte)-1; + private static final byte FIRST_NONZERO_IDENTITY = (byte)0; + private static final byte MAX_IDENTITY = Byte.MIN_VALUE; + private static final byte MIN_IDENTITY = Byte.MAX_VALUE; + private static final byte MUL_IDENTITY = (byte)1; + private static final byte OR_IDENTITY = (byte)0; + private static final byte SUADD_IDENTITY = (byte)0; + private static final byte UMAX_IDENTITY = (byte)0; // Minimum unsigned value + private static final byte UMIN_IDENTITY = (byte)-1; // Maximum unsigned value + private static final byte XOR_IDENTITY = (byte)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); static void assertArraysStrictlyEquals(byte[] r, byte[] a) { @@ -3616,7 +3629,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ANDReduce(byte[] a, int idx) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3625,7 +3638,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ANDReduceAll(byte[] a) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3637,20 +3650,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void ANDReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + byte v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3658,8 +3666,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::ANDReduce, ByteMaxVectorTests::ANDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = AND_IDENTITY; + + Assert.assertEquals((byte) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id & x), x); + Assert.assertEquals((byte) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static byte ANDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3669,7 +3700,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ANDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = -1; + byte res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3683,20 +3714,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = -1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + byte v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3705,7 +3731,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ORReduce(byte[] a, int idx) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3714,7 +3740,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ORReduceAll(byte[] a) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3729,17 +3755,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + byte v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3747,8 +3768,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::ORReduce, ByteMaxVectorTests::ORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = OR_IDENTITY; + + Assert.assertEquals((byte) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id | x), x); + Assert.assertEquals((byte) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static byte ORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3758,7 +3802,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3775,17 +3819,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + byte v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3794,7 +3833,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte XORReduce(byte[] a, int idx) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3803,7 +3842,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte XORReduceAll(byte[] a) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3818,17 +3857,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + byte v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3836,8 +3870,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::XORReduce, ByteMaxVectorTests::XORReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = XOR_IDENTITY; + + Assert.assertEquals((byte) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id ^ x), x); + Assert.assertEquals((byte) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static byte XORReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3847,7 +3904,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte XORReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3864,17 +3921,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + byte v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3883,7 +3935,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3892,7 +3944,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ADDReduceAll(byte[] a) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3907,17 +3959,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + byte v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3925,8 +3972,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::ADDReduce, ByteMaxVectorTests::ADDReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = ADD_IDENTITY; + + Assert.assertEquals((byte) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id + x), x); + Assert.assertEquals((byte) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static byte ADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3936,7 +4006,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte ADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3953,17 +4023,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + byte v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3972,7 +4037,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MULReduce(byte[] a, int idx) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3981,7 +4046,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MULReduceAll(byte[] a) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3993,20 +4058,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void MULReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + byte v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4014,8 +4074,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::MULReduce, ByteMaxVectorTests::MULReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MUL_IDENTITY; + + Assert.assertEquals((byte) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) (id * x), x); + Assert.assertEquals((byte) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static byte MULReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4025,7 +4108,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MULReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 1; + byte res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4039,20 +4122,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = 1; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + byte v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4061,7 +4139,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.min(res, a[i]); } @@ -4070,7 +4148,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduce(a, i)); } @@ -4082,20 +4160,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void MINReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + byte v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4103,8 +4176,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::MINReduce, ByteMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MIN_IDENTITY; + + Assert.assertEquals((byte) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.min(id, x), x); + Assert.assertEquals((byte) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static byte MINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.min(res, a[i]); @@ -4114,7 +4210,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4128,20 +4224,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + byte v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (byte) Math.min(ra, v); } } @@ -4150,7 +4241,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) Math.max(res, a[i]); } @@ -4159,7 +4250,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduce(a, i)); } @@ -4171,20 +4262,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void MAXReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + byte v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4192,8 +4278,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::MAXReduce, ByteMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = MAX_IDENTITY; + + Assert.assertEquals((byte) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) Math.max(id, x), x); + Assert.assertEquals((byte) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static byte MAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) Math.max(res, a[i]); @@ -4203,7 +4312,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte MAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4217,20 +4326,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + byte v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (byte) Math.max(ra, v); } } @@ -4239,7 +4343,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMINReduce(byte[] a, int idx) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.minUnsigned(res, a[i]); } @@ -4248,7 +4352,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMINReduceAll(byte[] a) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4260,20 +4364,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void UMINReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + byte v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4281,8 +4380,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::UMINReduce, ByteMaxVectorTests::UMINReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMIN_IDENTITY; + + Assert.assertEquals((byte) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static byte UMINReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.minUnsigned(res, a[i]); @@ -4292,7 +4414,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMINReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MAX_VALUE; + byte res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4306,20 +4428,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MAX_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + byte v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (byte) VectorMath.minUnsigned(ra, v); } } @@ -4328,7 +4445,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMAXReduce(byte[] a, int idx) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.maxUnsigned(res, a[i]); } @@ -4337,7 +4454,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMAXReduceAll(byte[] a) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4349,20 +4466,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void UMAXReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + byte v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4370,8 +4482,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::UMAXReduce, ByteMaxVectorTests::UMAXReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = UMAX_IDENTITY; + + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static byte UMAXReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.maxUnsigned(res, a[i]); @@ -4381,7 +4516,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte UMAXReduceAllMasked(byte[] a, boolean[] mask) { - byte res = Byte.MIN_VALUE; + byte res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4395,20 +4530,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = Byte.MIN_VALUE; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Byte.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + byte v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (byte) VectorMath.maxUnsigned(ra, v); } } @@ -4417,7 +4547,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduce(byte[] a, int idx) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4426,7 +4556,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAll(byte[] a) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4438,20 +4568,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4459,8 +4584,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::FIRST_NONZEROReduce, ByteMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "byteUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static byte FIRST_NONZEROReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4470,7 +4618,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte FIRST_NONZEROReduceAllMasked(byte[] a, boolean[] mask) { - byte res = (byte) 0; + byte res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4484,20 +4632,15 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - byte ra = (byte) 0; + byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (byte) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + byte v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4554,7 +4697,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte SUADDReduce(byte[] a, int idx) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4563,7 +4706,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte SUADDReduceAll(byte[] a) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4578,17 +4721,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + byte v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4596,8 +4734,31 @@ public class ByteMaxVectorTests extends AbstractVectorTest { ByteMaxVectorTests::SUADDReduce, ByteMaxVectorTests::SUADDReduceAll); } + @Test(dataProvider = "byteSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte id = SUADD_IDENTITY; + + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + byte x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((byte) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static byte SUADDReduceMasked(byte[] a, int idx, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (byte) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4607,7 +4768,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } static byte SUADDReduceAllMasked(byte[] a, boolean[] mask) { - byte res = 0; + byte res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (byte) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4623,17 +4784,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { byte ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ByteVector av = ByteVector.fromArray(SPECIES, a, i); - ra = (byte) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + byte v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (byte) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 215edbb3a66..1d4cadd2158 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +62,12 @@ public class Double128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2384,7 +2390,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2393,7 +2399,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2408,17 +2414,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2426,8 +2427,31 @@ relativeError)); Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2437,7 +2461,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2454,17 +2478,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2473,7 +2492,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2482,7 +2501,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2494,20 +2513,15 @@ relativeError)); static void MULReduceDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2515,8 +2529,31 @@ relativeError)); Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2526,7 +2563,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2540,20 +2577,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2562,7 +2594,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2571,7 +2603,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2583,20 +2615,15 @@ relativeError)); static void MINReduceDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2604,8 +2631,31 @@ relativeError)); Double128VectorTests::MINReduce, Double128VectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2615,7 +2665,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2629,20 +2679,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2651,7 +2696,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2660,7 +2705,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2672,20 +2717,15 @@ relativeError)); static void MAXReduceDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2693,8 +2733,31 @@ relativeError)); Double128VectorTests::MAXReduce, Double128VectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2704,7 +2767,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2718,20 +2781,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2740,7 +2798,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2749,7 +2807,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2761,20 +2819,15 @@ relativeError)); static void FIRST_NONZEROReduceDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2782,8 +2835,31 @@ relativeError)); Double128VectorTests::FIRST_NONZEROReduce, Double128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2793,7 +2869,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2807,20 +2883,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index 14d52320ce8..b5acfe0ef34 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +62,12 @@ public class Double256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2384,7 +2390,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2393,7 +2399,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2408,17 +2414,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2426,8 +2427,31 @@ relativeError)); Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2437,7 +2461,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2454,17 +2478,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2473,7 +2492,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2482,7 +2501,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2494,20 +2513,15 @@ relativeError)); static void MULReduceDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2515,8 +2529,31 @@ relativeError)); Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2526,7 +2563,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2540,20 +2577,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2562,7 +2594,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2571,7 +2603,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2583,20 +2615,15 @@ relativeError)); static void MINReduceDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2604,8 +2631,31 @@ relativeError)); Double256VectorTests::MINReduce, Double256VectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2615,7 +2665,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2629,20 +2679,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2651,7 +2696,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2660,7 +2705,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2672,20 +2717,15 @@ relativeError)); static void MAXReduceDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2693,8 +2733,31 @@ relativeError)); Double256VectorTests::MAXReduce, Double256VectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2704,7 +2767,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2718,20 +2781,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2740,7 +2798,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2749,7 +2807,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2761,20 +2819,15 @@ relativeError)); static void FIRST_NONZEROReduceDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2782,8 +2835,31 @@ relativeError)); Double256VectorTests::FIRST_NONZEROReduce, Double256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2793,7 +2869,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2807,20 +2883,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 91a4669a1b1..3f85d0e52a6 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +62,12 @@ public class Double512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2384,7 +2390,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2393,7 +2399,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2408,17 +2414,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2426,8 +2427,31 @@ relativeError)); Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2437,7 +2461,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2454,17 +2478,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2473,7 +2492,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2482,7 +2501,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2494,20 +2513,15 @@ relativeError)); static void MULReduceDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2515,8 +2529,31 @@ relativeError)); Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2526,7 +2563,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2540,20 +2577,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2562,7 +2594,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2571,7 +2603,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2583,20 +2615,15 @@ relativeError)); static void MINReduceDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2604,8 +2631,31 @@ relativeError)); Double512VectorTests::MINReduce, Double512VectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2615,7 +2665,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2629,20 +2679,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2651,7 +2696,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2660,7 +2705,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2672,20 +2717,15 @@ relativeError)); static void MAXReduceDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2693,8 +2733,31 @@ relativeError)); Double512VectorTests::MAXReduce, Double512VectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2704,7 +2767,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2718,20 +2781,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2740,7 +2798,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2749,7 +2807,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2761,20 +2819,15 @@ relativeError)); static void FIRST_NONZEROReduceDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2782,8 +2835,31 @@ relativeError)); Double512VectorTests::FIRST_NONZEROReduce, Double512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2793,7 +2869,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2807,20 +2883,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 659e18cd8af..ab3586fb424 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +62,12 @@ public class Double64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2384,7 +2390,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2393,7 +2399,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2408,17 +2414,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2426,8 +2427,31 @@ relativeError)); Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2437,7 +2461,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2454,17 +2478,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2473,7 +2492,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2482,7 +2501,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2494,20 +2513,15 @@ relativeError)); static void MULReduceDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2515,8 +2529,31 @@ relativeError)); Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2526,7 +2563,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2540,20 +2577,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2562,7 +2594,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2571,7 +2603,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2583,20 +2615,15 @@ relativeError)); static void MINReduceDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2604,8 +2631,31 @@ relativeError)); Double64VectorTests::MINReduce, Double64VectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2615,7 +2665,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2629,20 +2679,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2651,7 +2696,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2660,7 +2705,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2672,20 +2717,15 @@ relativeError)); static void MAXReduceDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2693,8 +2733,31 @@ relativeError)); Double64VectorTests::MAXReduce, Double64VectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2704,7 +2767,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2718,20 +2781,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2740,7 +2798,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2749,7 +2807,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2761,20 +2819,15 @@ relativeError)); static void FIRST_NONZEROReduceDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2782,8 +2835,31 @@ relativeError)); Double64VectorTests::FIRST_NONZEROReduce, Double64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2793,7 +2869,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2807,20 +2883,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index ac85f0bd07b..8f135cd221a 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +68,13 @@ public class DoubleMaxVectorTests extends AbstractVectorTest { private static final int Max = 256; // juts so we can do N/Max + // Identity values for reduction operations + private static final double ADD_IDENTITY = (double)0; + private static final double FIRST_NONZERO_IDENTITY = (double)0; + private static final double MAX_IDENTITY = Double.NEGATIVE_INFINITY; + private static final double MIN_IDENTITY = Double.POSITIVE_INFINITY; + private static final double MUL_IDENTITY = (double)1; + // for floating point addition reduction ops that may introduce rounding errors private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; @@ -2389,7 +2396,7 @@ relativeError)); } static double ADDReduce(double[] a, int idx) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2398,7 +2405,7 @@ relativeError)); } static double ADDReduceAll(double[] a) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2413,17 +2420,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + double v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2431,8 +2433,31 @@ relativeError)); DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = ADD_IDENTITY; + + Assert.assertEquals((double) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id + x), x); + Assert.assertEquals((double) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2442,7 +2467,7 @@ relativeError)); } static double ADDReduceAllMasked(double[] a, boolean[] mask) { - double res = 0; + double res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2459,17 +2484,12 @@ relativeError)); double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + double v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2478,7 +2498,7 @@ relativeError)); } static double MULReduce(double[] a, int idx) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2487,7 +2507,7 @@ relativeError)); } static double MULReduceAll(double[] a) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2499,20 +2519,15 @@ relativeError)); static void MULReduceDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + double v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2520,8 +2535,31 @@ relativeError)); DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MUL_IDENTITY; + + Assert.assertEquals((double) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) (id * x), x); + Assert.assertEquals((double) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static double MULReduceMasked(double[] a, int idx, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2531,7 +2569,7 @@ relativeError)); } static double MULReduceAllMasked(double[] a, boolean[] mask) { - double res = 1; + double res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2545,20 +2583,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = 1; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + double v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2567,7 +2600,7 @@ relativeError)); } static double MINReduce(double[] a, int idx) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.min(res, a[i]); } @@ -2576,7 +2609,7 @@ relativeError)); } static double MINReduceAll(double[] a) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduce(a, i)); } @@ -2588,20 +2621,15 @@ relativeError)); static void MINReduceDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + double v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2609,8 +2637,31 @@ relativeError)); DoubleMaxVectorTests::MINReduce, DoubleMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MIN_IDENTITY; + + Assert.assertEquals((double) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.min(id, x), x); + Assert.assertEquals((double) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static double MINReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.min(res, a[i]); @@ -2620,7 +2671,7 @@ relativeError)); } static double MINReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.POSITIVE_INFINITY; + double res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2634,20 +2685,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.POSITIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + double v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (double) Math.min(ra, v); } } @@ -2656,7 +2702,7 @@ relativeError)); } static double MAXReduce(double[] a, int idx) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (double) Math.max(res, a[i]); } @@ -2665,7 +2711,7 @@ relativeError)); } static double MAXReduceAll(double[] a) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduce(a, i)); } @@ -2677,20 +2723,15 @@ relativeError)); static void MAXReduceDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + double v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2698,8 +2739,31 @@ relativeError)); DoubleMaxVectorTests::MAXReduce, DoubleMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = MAX_IDENTITY; + + Assert.assertEquals((double) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((double) Math.max(id, x), x); + Assert.assertEquals((double) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((double) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((double) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static double MAXReduceMasked(double[] a, int idx, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (double) Math.max(res, a[i]); @@ -2709,7 +2773,7 @@ relativeError)); } static double MAXReduceAllMasked(double[] a, boolean[] mask) { - double res = Double.NEGATIVE_INFINITY; + double res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (double) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2723,20 +2787,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = Double.NEGATIVE_INFINITY; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Double.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = (double) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + double v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (double) Math.max(ra, v); } } @@ -2745,7 +2804,7 @@ relativeError)); } static double FIRST_NONZEROReduce(double[] a, int idx) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2754,7 +2813,7 @@ relativeError)); } static double FIRST_NONZEROReduceAll(double[] a) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2766,20 +2825,15 @@ relativeError)); static void FIRST_NONZEROReduceDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2787,8 +2841,31 @@ relativeError)); DoubleMaxVectorTests::FIRST_NONZEROReduce, DoubleMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "doubleUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + double x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static double FIRST_NONZEROReduceMasked(double[] a, int idx, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2798,7 +2875,7 @@ relativeError)); } static double FIRST_NONZEROReduceAllMasked(double[] a, boolean[] mask) { - double res = (double) 0; + double res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2812,20 +2889,15 @@ relativeError)); double[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - double ra = (double) 0; + double ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (double) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + double v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 32b93293fb9..f97c5b0064c 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +62,12 @@ public class Float128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2395,7 +2401,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2404,7 +2410,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2419,17 +2425,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2437,8 +2438,31 @@ relativeError)); Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2448,7 +2472,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2465,17 +2489,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2484,7 +2503,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2493,7 +2512,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2505,20 +2524,15 @@ relativeError)); static void MULReduceFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2526,8 +2540,31 @@ relativeError)); Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2537,7 +2574,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2551,20 +2588,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2573,7 +2605,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2582,7 +2614,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2594,20 +2626,15 @@ relativeError)); static void MINReduceFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2615,8 +2642,31 @@ relativeError)); Float128VectorTests::MINReduce, Float128VectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2626,7 +2676,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2640,20 +2690,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2662,7 +2707,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2671,7 +2716,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2683,20 +2728,15 @@ relativeError)); static void MAXReduceFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2704,8 +2744,31 @@ relativeError)); Float128VectorTests::MAXReduce, Float128VectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2715,7 +2778,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2729,20 +2792,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2751,7 +2809,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2760,7 +2818,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2772,20 +2830,15 @@ relativeError)); static void FIRST_NONZEROReduceFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2793,8 +2846,31 @@ relativeError)); Float128VectorTests::FIRST_NONZEROReduce, Float128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2804,7 +2880,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2818,20 +2894,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 9847865eacb..d9746d3291c 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +62,12 @@ public class Float256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2395,7 +2401,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2404,7 +2410,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2419,17 +2425,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2437,8 +2438,31 @@ relativeError)); Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2448,7 +2472,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2465,17 +2489,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2484,7 +2503,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2493,7 +2512,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2505,20 +2524,15 @@ relativeError)); static void MULReduceFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2526,8 +2540,31 @@ relativeError)); Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2537,7 +2574,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2551,20 +2588,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2573,7 +2605,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2582,7 +2614,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2594,20 +2626,15 @@ relativeError)); static void MINReduceFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2615,8 +2642,31 @@ relativeError)); Float256VectorTests::MINReduce, Float256VectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2626,7 +2676,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2640,20 +2690,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2662,7 +2707,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2671,7 +2716,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2683,20 +2728,15 @@ relativeError)); static void MAXReduceFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2704,8 +2744,31 @@ relativeError)); Float256VectorTests::MAXReduce, Float256VectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2715,7 +2778,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2729,20 +2792,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2751,7 +2809,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2760,7 +2818,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2772,20 +2830,15 @@ relativeError)); static void FIRST_NONZEROReduceFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2793,8 +2846,31 @@ relativeError)); Float256VectorTests::FIRST_NONZEROReduce, Float256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2804,7 +2880,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2818,20 +2894,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index 0daa5310ff0..ca395221c6b 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +62,12 @@ public class Float512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2395,7 +2401,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2404,7 +2410,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2419,17 +2425,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2437,8 +2438,31 @@ relativeError)); Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2448,7 +2472,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2465,17 +2489,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2484,7 +2503,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2493,7 +2512,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2505,20 +2524,15 @@ relativeError)); static void MULReduceFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2526,8 +2540,31 @@ relativeError)); Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2537,7 +2574,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2551,20 +2588,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2573,7 +2605,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2582,7 +2614,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2594,20 +2626,15 @@ relativeError)); static void MINReduceFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2615,8 +2642,31 @@ relativeError)); Float512VectorTests::MINReduce, Float512VectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2626,7 +2676,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2640,20 +2690,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2662,7 +2707,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2671,7 +2716,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2683,20 +2728,15 @@ relativeError)); static void MAXReduceFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2704,8 +2744,31 @@ relativeError)); Float512VectorTests::MAXReduce, Float512VectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2715,7 +2778,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2729,20 +2792,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2751,7 +2809,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2760,7 +2818,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2772,20 +2830,15 @@ relativeError)); static void FIRST_NONZEROReduceFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2793,8 +2846,31 @@ relativeError)); Float512VectorTests::FIRST_NONZEROReduce, Float512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2804,7 +2880,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2818,20 +2894,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index 921264fc4e2..1b14cdb7791 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +62,12 @@ public class Float64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2395,7 +2401,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2404,7 +2410,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2419,17 +2425,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2437,8 +2438,31 @@ relativeError)); Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2448,7 +2472,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2465,17 +2489,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2484,7 +2503,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2493,7 +2512,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2505,20 +2524,15 @@ relativeError)); static void MULReduceFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2526,8 +2540,31 @@ relativeError)); Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2537,7 +2574,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2551,20 +2588,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2573,7 +2605,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2582,7 +2614,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2594,20 +2626,15 @@ relativeError)); static void MINReduceFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2615,8 +2642,31 @@ relativeError)); Float64VectorTests::MINReduce, Float64VectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2626,7 +2676,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2640,20 +2690,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2662,7 +2707,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2671,7 +2716,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2683,20 +2728,15 @@ relativeError)); static void MAXReduceFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2704,8 +2744,31 @@ relativeError)); Float64VectorTests::MAXReduce, Float64VectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2715,7 +2778,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2729,20 +2792,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2751,7 +2809,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2760,7 +2818,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2772,20 +2830,15 @@ relativeError)); static void FIRST_NONZEROReduceFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2793,8 +2846,31 @@ relativeError)); Float64VectorTests::FIRST_NONZEROReduce, Float64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2804,7 +2880,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2818,20 +2894,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 07c9b7d0ef9..53edb408035 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +68,13 @@ public class FloatMaxVectorTests extends AbstractVectorTest { private static final int Max = 256; // juts so we can do N/Max + // Identity values for reduction operations + private static final float ADD_IDENTITY = (float)0; + private static final float FIRST_NONZERO_IDENTITY = (float)0; + private static final float MAX_IDENTITY = Float.NEGATIVE_INFINITY; + private static final float MIN_IDENTITY = Float.POSITIVE_INFINITY; + private static final float MUL_IDENTITY = (float)1; + // for floating point addition reduction ops that may introduce rounding errors private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; @@ -2400,7 +2407,7 @@ relativeError)); } static float ADDReduce(float[] a, int idx) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -2409,7 +2416,7 @@ relativeError)); } static float ADDReduceAll(float[] a) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -2424,17 +2431,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + float v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -2442,8 +2444,31 @@ relativeError)); FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } + @Test(dataProvider = "floatUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = ADD_IDENTITY; + + Assert.assertEquals((float) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id + x), x); + Assert.assertEquals((float) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -2453,7 +2478,7 @@ relativeError)); } static float ADDReduceAllMasked(float[] a, boolean[] mask) { - float res = 0; + float res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -2470,17 +2495,12 @@ relativeError)); float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + float v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -2489,7 +2509,7 @@ relativeError)); } static float MULReduce(float[] a, int idx) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -2498,7 +2518,7 @@ relativeError)); } static float MULReduceAll(float[] a) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -2510,20 +2530,15 @@ relativeError)); static void MULReduceFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + float v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -2531,8 +2546,31 @@ relativeError)); FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MUL_IDENTITY; + + Assert.assertEquals((float) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) (id * x), x); + Assert.assertEquals((float) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static float MULReduceMasked(float[] a, int idx, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -2542,7 +2580,7 @@ relativeError)); } static float MULReduceAllMasked(float[] a, boolean[] mask) { - float res = 1; + float res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -2556,20 +2594,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = 1; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + float v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -2578,7 +2611,7 @@ relativeError)); } static float MINReduce(float[] a, int idx) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.min(res, a[i]); } @@ -2587,7 +2620,7 @@ relativeError)); } static float MINReduceAll(float[] a) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduce(a, i)); } @@ -2599,20 +2632,15 @@ relativeError)); static void MINReduceFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + float v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2620,8 +2648,31 @@ relativeError)); FloatMaxVectorTests::MINReduce, FloatMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MIN_IDENTITY; + + Assert.assertEquals((float) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.min(id, x), x); + Assert.assertEquals((float) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static float MINReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.min(res, a[i]); @@ -2631,7 +2682,7 @@ relativeError)); } static float MINReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.POSITIVE_INFINITY; + float res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -2645,20 +2696,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.POSITIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.POSITIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + float v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (float) Math.min(ra, v); } } @@ -2667,7 +2713,7 @@ relativeError)); } static float MAXReduce(float[] a, int idx) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (float) Math.max(res, a[i]); } @@ -2676,7 +2722,7 @@ relativeError)); } static float MAXReduceAll(float[] a) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduce(a, i)); } @@ -2688,20 +2734,15 @@ relativeError)); static void MAXReduceFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + float v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2709,8 +2750,31 @@ relativeError)); FloatMaxVectorTests::MAXReduce, FloatMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = MAX_IDENTITY; + + Assert.assertEquals((float) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((float) Math.max(id, x), x); + Assert.assertEquals((float) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((float) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((float) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static float MAXReduceMasked(float[] a, int idx, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (float) Math.max(res, a[i]); @@ -2720,7 +2784,7 @@ relativeError)); } static float MAXReduceAllMasked(float[] a, boolean[] mask) { - float res = Float.NEGATIVE_INFINITY; + float res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (float) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -2734,20 +2798,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = Float.NEGATIVE_INFINITY; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Float.NEGATIVE_INFINITY; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = (float) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + float v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (float) Math.max(ra, v); } } @@ -2756,7 +2815,7 @@ relativeError)); } static float FIRST_NONZEROReduce(float[] a, int idx) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -2765,7 +2824,7 @@ relativeError)); } static float FIRST_NONZEROReduceAll(float[] a) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -2777,20 +2836,15 @@ relativeError)); static void FIRST_NONZEROReduceFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -2798,8 +2852,31 @@ relativeError)); FloatMaxVectorTests::FIRST_NONZEROReduce, FloatMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "floatUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + float x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static float FIRST_NONZEROReduceMasked(float[] a, int idx, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -2809,7 +2886,7 @@ relativeError)); } static float FIRST_NONZEROReduceAllMasked(float[] a, boolean[] mask) { - float res = (float) 0; + float res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -2823,20 +2900,15 @@ relativeError)); float[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - float ra = (float) 0; + float ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (float) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - FloatVector av = FloatVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + float v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index 93912243ecd..69bb0c84588 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Int128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3655,7 +3667,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3664,7 +3676,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3676,20 +3688,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void ANDReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3697,8 +3704,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::ANDReduce, Int128VectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3708,7 +3738,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3722,20 +3752,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3744,7 +3769,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3753,7 +3778,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3768,17 +3793,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3786,8 +3806,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::ORReduce, Int128VectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3797,7 +3840,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3814,17 +3857,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3833,7 +3871,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3842,7 +3880,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3857,17 +3895,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3875,8 +3908,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::XORReduce, Int128VectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3886,7 +3942,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3903,17 +3959,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3922,7 +3973,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3931,7 +3982,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3946,17 +3997,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3964,8 +4010,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::ADDReduce, Int128VectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3975,7 +4044,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3992,17 +4061,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4011,7 +4075,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4020,7 +4084,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4032,20 +4096,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void MULReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4053,8 +4112,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::MULReduce, Int128VectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4064,7 +4146,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4078,20 +4160,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4100,7 +4177,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4109,7 +4186,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4121,20 +4198,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void MINReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4142,8 +4214,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::MINReduce, Int128VectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4153,7 +4248,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4167,20 +4262,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4189,7 +4279,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4198,7 +4288,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4210,20 +4300,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void MAXReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4231,8 +4316,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::MAXReduce, Int128VectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4242,7 +4350,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4256,20 +4364,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4278,7 +4381,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4287,7 +4390,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4299,20 +4402,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void UMINReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4320,8 +4418,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::UMINReduce, Int128VectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4331,7 +4452,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4345,20 +4466,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4367,7 +4483,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4376,7 +4492,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4388,20 +4504,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void UMAXReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4409,8 +4520,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::UMAXReduce, Int128VectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4420,7 +4554,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4434,20 +4568,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4456,7 +4585,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4465,7 +4594,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4477,20 +4606,15 @@ public class Int128VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4498,8 +4622,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::FIRST_NONZEROReduce, Int128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4509,7 +4656,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4523,20 +4670,15 @@ public class Int128VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4593,7 +4735,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4602,7 +4744,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4617,17 +4759,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4635,8 +4772,31 @@ public class Int128VectorTests extends AbstractVectorTest { Int128VectorTests::SUADDReduce, Int128VectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4646,7 +4806,7 @@ public class Int128VectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4662,17 +4822,12 @@ public class Int128VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index e8d6f3311ac..4e63de95b7b 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Int256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3655,7 +3667,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3664,7 +3676,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3676,20 +3688,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void ANDReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3697,8 +3704,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::ANDReduce, Int256VectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3708,7 +3738,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3722,20 +3752,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3744,7 +3769,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3753,7 +3778,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3768,17 +3793,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3786,8 +3806,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::ORReduce, Int256VectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3797,7 +3840,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3814,17 +3857,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3833,7 +3871,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3842,7 +3880,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3857,17 +3895,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3875,8 +3908,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::XORReduce, Int256VectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3886,7 +3942,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3903,17 +3959,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3922,7 +3973,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3931,7 +3982,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3946,17 +3997,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3964,8 +4010,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::ADDReduce, Int256VectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3975,7 +4044,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3992,17 +4061,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4011,7 +4075,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4020,7 +4084,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4032,20 +4096,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void MULReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4053,8 +4112,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::MULReduce, Int256VectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4064,7 +4146,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4078,20 +4160,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4100,7 +4177,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4109,7 +4186,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4121,20 +4198,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void MINReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4142,8 +4214,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::MINReduce, Int256VectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4153,7 +4248,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4167,20 +4262,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4189,7 +4279,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4198,7 +4288,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4210,20 +4300,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void MAXReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4231,8 +4316,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::MAXReduce, Int256VectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4242,7 +4350,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4256,20 +4364,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4278,7 +4381,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4287,7 +4390,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4299,20 +4402,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void UMINReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4320,8 +4418,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::UMINReduce, Int256VectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4331,7 +4452,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4345,20 +4466,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4367,7 +4483,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4376,7 +4492,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4388,20 +4504,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void UMAXReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4409,8 +4520,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::UMAXReduce, Int256VectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4420,7 +4554,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4434,20 +4568,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4456,7 +4585,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4465,7 +4594,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4477,20 +4606,15 @@ public class Int256VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4498,8 +4622,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::FIRST_NONZEROReduce, Int256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4509,7 +4656,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4523,20 +4670,15 @@ public class Int256VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4593,7 +4735,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4602,7 +4744,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4617,17 +4759,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4635,8 +4772,31 @@ public class Int256VectorTests extends AbstractVectorTest { Int256VectorTests::SUADDReduce, Int256VectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4646,7 +4806,7 @@ public class Int256VectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4662,17 +4822,12 @@ public class Int256VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index 932d9ee4487..e2de7905a83 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Int512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3655,7 +3667,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3664,7 +3676,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3676,20 +3688,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void ANDReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3697,8 +3704,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::ANDReduce, Int512VectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3708,7 +3738,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3722,20 +3752,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3744,7 +3769,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3753,7 +3778,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3768,17 +3793,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3786,8 +3806,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::ORReduce, Int512VectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3797,7 +3840,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3814,17 +3857,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3833,7 +3871,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3842,7 +3880,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3857,17 +3895,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3875,8 +3908,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::XORReduce, Int512VectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3886,7 +3942,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3903,17 +3959,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3922,7 +3973,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3931,7 +3982,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3946,17 +3997,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3964,8 +4010,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::ADDReduce, Int512VectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3975,7 +4044,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3992,17 +4061,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4011,7 +4075,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4020,7 +4084,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4032,20 +4096,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void MULReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4053,8 +4112,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::MULReduce, Int512VectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4064,7 +4146,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4078,20 +4160,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4100,7 +4177,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4109,7 +4186,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4121,20 +4198,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void MINReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4142,8 +4214,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::MINReduce, Int512VectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4153,7 +4248,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4167,20 +4262,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4189,7 +4279,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4198,7 +4288,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4210,20 +4300,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void MAXReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4231,8 +4316,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::MAXReduce, Int512VectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4242,7 +4350,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4256,20 +4364,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4278,7 +4381,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4287,7 +4390,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4299,20 +4402,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void UMINReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4320,8 +4418,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::UMINReduce, Int512VectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4331,7 +4452,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4345,20 +4466,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4367,7 +4483,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4376,7 +4492,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4388,20 +4504,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void UMAXReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4409,8 +4520,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::UMAXReduce, Int512VectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4420,7 +4554,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4434,20 +4568,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4456,7 +4585,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4465,7 +4594,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4477,20 +4606,15 @@ public class Int512VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4498,8 +4622,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::FIRST_NONZEROReduce, Int512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4509,7 +4656,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4523,20 +4670,15 @@ public class Int512VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4593,7 +4735,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4602,7 +4744,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4617,17 +4759,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4635,8 +4772,31 @@ public class Int512VectorTests extends AbstractVectorTest { Int512VectorTests::SUADDReduce, Int512VectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4646,7 +4806,7 @@ public class Int512VectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4662,17 +4822,12 @@ public class Int512VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index 3c00904a70e..d64db80b94d 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Int64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3655,7 +3667,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3664,7 +3676,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3676,20 +3688,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void ANDReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3697,8 +3704,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::ANDReduce, Int64VectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3708,7 +3738,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3722,20 +3752,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3744,7 +3769,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3753,7 +3778,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3768,17 +3793,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3786,8 +3806,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::ORReduce, Int64VectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3797,7 +3840,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3814,17 +3857,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3833,7 +3871,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3842,7 +3880,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3857,17 +3895,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3875,8 +3908,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::XORReduce, Int64VectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3886,7 +3942,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3903,17 +3959,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3922,7 +3973,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3931,7 +3982,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3946,17 +3997,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3964,8 +4010,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::ADDReduce, Int64VectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3975,7 +4044,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3992,17 +4061,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4011,7 +4075,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4020,7 +4084,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4032,20 +4096,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void MULReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4053,8 +4112,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::MULReduce, Int64VectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4064,7 +4146,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4078,20 +4160,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4100,7 +4177,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4109,7 +4186,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4121,20 +4198,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void MINReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4142,8 +4214,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::MINReduce, Int64VectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4153,7 +4248,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4167,20 +4262,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4189,7 +4279,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4198,7 +4288,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4210,20 +4300,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void MAXReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4231,8 +4316,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::MAXReduce, Int64VectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4242,7 +4350,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4256,20 +4364,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4278,7 +4381,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4287,7 +4390,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4299,20 +4402,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void UMINReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4320,8 +4418,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::UMINReduce, Int64VectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4331,7 +4452,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4345,20 +4466,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4367,7 +4483,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4376,7 +4492,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4388,20 +4504,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void UMAXReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4409,8 +4520,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::UMAXReduce, Int64VectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4420,7 +4554,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4434,20 +4568,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4456,7 +4585,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4465,7 +4594,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4477,20 +4606,15 @@ public class Int64VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4498,8 +4622,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::FIRST_NONZEROReduce, Int64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4509,7 +4656,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4523,20 +4670,15 @@ public class Int64VectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4593,7 +4735,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4602,7 +4744,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4617,17 +4759,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4635,8 +4772,31 @@ public class Int64VectorTests extends AbstractVectorTest { Int64VectorTests::SUADDReduce, Int64VectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4646,7 +4806,7 @@ public class Int64VectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4662,17 +4822,12 @@ public class Int64VectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index 42659bfe44e..7bf4dc48171 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +71,19 @@ public class IntMaxVectorTests extends AbstractVectorTest { private static final int CONST_SHIFT = Integer.SIZE / 2; + // Identity values for reduction operations + private static final int ADD_IDENTITY = (int)0; + private static final int AND_IDENTITY = (int)-1; + private static final int FIRST_NONZERO_IDENTITY = (int)0; + private static final int MAX_IDENTITY = Integer.MIN_VALUE; + private static final int MIN_IDENTITY = Integer.MAX_VALUE; + private static final int MUL_IDENTITY = (int)1; + private static final int OR_IDENTITY = (int)0; + private static final int SUADD_IDENTITY = (int)0; + private static final int UMAX_IDENTITY = (int)0; // Minimum unsigned value + private static final int UMIN_IDENTITY = (int)-1; // Maximum unsigned value + private static final int XOR_IDENTITY = (int)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); static void assertArraysStrictlyEquals(int[] r, int[] a) { @@ -3660,7 +3673,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ANDReduce(int[] a, int idx) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3669,7 +3682,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ANDReduceAll(int[] a) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3681,20 +3694,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void ANDReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + int v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3702,8 +3710,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::ANDReduce, IntMaxVectorTests::ANDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = AND_IDENTITY; + + Assert.assertEquals((int) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id & x), x); + Assert.assertEquals((int) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static int ANDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3713,7 +3744,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ANDReduceAllMasked(int[] a, boolean[] mask) { - int res = -1; + int res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3727,20 +3758,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = -1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + int v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3749,7 +3775,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ORReduce(int[] a, int idx) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3758,7 +3784,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ORReduceAll(int[] a) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3773,17 +3799,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + int v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3791,8 +3812,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::ORReduce, IntMaxVectorTests::ORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = OR_IDENTITY; + + Assert.assertEquals((int) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id | x), x); + Assert.assertEquals((int) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static int ORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3802,7 +3846,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3819,17 +3863,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + int v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3838,7 +3877,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int XORReduce(int[] a, int idx) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3847,7 +3886,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int XORReduceAll(int[] a) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3862,17 +3901,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + int v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3880,8 +3914,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::XORReduce, IntMaxVectorTests::XORReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = XOR_IDENTITY; + + Assert.assertEquals((int) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id ^ x), x); + Assert.assertEquals((int) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static int XORReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3891,7 +3948,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int XORReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3908,17 +3965,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + int v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3927,7 +3979,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ADDReduce(int[] a, int idx) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3936,7 +3988,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ADDReduceAll(int[] a) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3951,17 +4003,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + int v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3969,8 +4016,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::ADDReduce, IntMaxVectorTests::ADDReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = ADD_IDENTITY; + + Assert.assertEquals((int) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id + x), x); + Assert.assertEquals((int) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static int ADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3980,7 +4050,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int ADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3997,17 +4067,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + int v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4016,7 +4081,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MULReduce(int[] a, int idx) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4025,7 +4090,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MULReduceAll(int[] a) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4037,20 +4102,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void MULReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + int v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4058,8 +4118,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::MULReduce, IntMaxVectorTests::MULReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MUL_IDENTITY; + + Assert.assertEquals((int) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) (id * x), x); + Assert.assertEquals((int) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static int MULReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4069,7 +4152,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MULReduceAllMasked(int[] a, boolean[] mask) { - int res = 1; + int res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4083,20 +4166,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = 1; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + int v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4105,7 +4183,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.min(res, a[i]); } @@ -4114,7 +4192,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduce(a, i)); } @@ -4126,20 +4204,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void MINReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + int v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4147,8 +4220,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::MINReduce, IntMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MIN_IDENTITY; + + Assert.assertEquals((int) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.min(id, x), x); + Assert.assertEquals((int) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static int MINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.min(res, a[i]); @@ -4158,7 +4254,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4172,20 +4268,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + int v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (int) Math.min(ra, v); } } @@ -4194,7 +4285,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) Math.max(res, a[i]); } @@ -4203,7 +4294,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduce(a, i)); } @@ -4215,20 +4306,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void MAXReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + int v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4236,8 +4322,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::MAXReduce, IntMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = MAX_IDENTITY; + + Assert.assertEquals((int) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) Math.max(id, x), x); + Assert.assertEquals((int) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static int MAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) Math.max(res, a[i]); @@ -4247,7 +4356,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int MAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4261,20 +4370,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + int v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (int) Math.max(ra, v); } } @@ -4283,7 +4387,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMINReduce(int[] a, int idx) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.minUnsigned(res, a[i]); } @@ -4292,7 +4396,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMINReduceAll(int[] a) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4304,20 +4408,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void UMINReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + int v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4325,8 +4424,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::UMINReduce, IntMaxVectorTests::UMINReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMIN_IDENTITY; + + Assert.assertEquals((int) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static int UMINReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.minUnsigned(res, a[i]); @@ -4336,7 +4458,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMINReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MAX_VALUE; + int res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4350,20 +4472,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MAX_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + int v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (int) VectorMath.minUnsigned(ra, v); } } @@ -4372,7 +4489,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMAXReduce(int[] a, int idx) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.maxUnsigned(res, a[i]); } @@ -4381,7 +4498,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMAXReduceAll(int[] a) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4393,20 +4510,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void UMAXReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + int v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4414,8 +4526,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::UMAXReduce, IntMaxVectorTests::UMAXReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = UMAX_IDENTITY; + + Assert.assertEquals((int) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static int UMAXReduceMasked(int[] a, int idx, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.maxUnsigned(res, a[i]); @@ -4425,7 +4560,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int UMAXReduceAllMasked(int[] a, boolean[] mask) { - int res = Integer.MIN_VALUE; + int res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4439,20 +4574,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = Integer.MIN_VALUE; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Integer.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + int v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (int) VectorMath.maxUnsigned(ra, v); } } @@ -4461,7 +4591,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduce(int[] a, int idx) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4470,7 +4600,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAll(int[] a) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4482,20 +4612,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4503,8 +4628,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::FIRST_NONZEROReduce, IntMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "intUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static int FIRST_NONZEROReduceMasked(int[] a, int idx, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4514,7 +4662,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int FIRST_NONZEROReduceAllMasked(int[] a, boolean[] mask) { - int res = (int) 0; + int res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4528,20 +4676,15 @@ public class IntMaxVectorTests extends AbstractVectorTest { int[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - int ra = (int) 0; + int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (int) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + int v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4598,7 +4741,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int SUADDReduce(int[] a, int idx) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4607,7 +4750,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int SUADDReduceAll(int[] a) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4622,17 +4765,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + int v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4640,8 +4778,31 @@ public class IntMaxVectorTests extends AbstractVectorTest { IntMaxVectorTests::SUADDReduce, IntMaxVectorTests::SUADDReduceAll); } + @Test(dataProvider = "intSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int id = SUADD_IDENTITY; + + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + int x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((int) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static int SUADDReduceMasked(int[] a, int idx, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (int) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4651,7 +4812,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { } static int SUADDReduceAllMasked(int[] a, boolean[] mask) { - int res = 0; + int res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (int) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4667,17 +4828,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { int ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - IntVector av = IntVector.fromArray(SPECIES, a, i); - ra = (int) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + int v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (int) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index 6c305a5c2b4..227f196ffdf 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Long128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3677,7 +3689,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3686,7 +3698,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3698,20 +3710,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void ANDReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3719,8 +3726,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::ANDReduce, Long128VectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3730,7 +3760,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3744,20 +3774,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3766,7 +3791,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3775,7 +3800,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3790,17 +3815,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3808,8 +3828,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::ORReduce, Long128VectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3819,7 +3862,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3836,17 +3879,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3855,7 +3893,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3864,7 +3902,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3879,17 +3917,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3897,8 +3930,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::XORReduce, Long128VectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3908,7 +3964,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3925,17 +3981,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3944,7 +3995,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3953,7 +4004,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3968,17 +4019,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3986,8 +4032,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::ADDReduce, Long128VectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3997,7 +4066,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4014,17 +4083,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4033,7 +4097,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4042,7 +4106,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4054,20 +4118,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void MULReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4075,8 +4134,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::MULReduce, Long128VectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4086,7 +4168,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4100,20 +4182,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4122,7 +4199,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4131,7 +4208,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4143,20 +4220,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void MINReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4164,8 +4236,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::MINReduce, Long128VectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4175,7 +4270,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4189,20 +4284,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4211,7 +4301,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4220,7 +4310,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4232,20 +4322,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void MAXReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4253,8 +4338,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::MAXReduce, Long128VectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4264,7 +4372,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4278,20 +4386,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4300,7 +4403,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4309,7 +4412,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4321,20 +4424,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void UMINReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4342,8 +4440,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::UMINReduce, Long128VectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4353,7 +4474,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4367,20 +4488,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4389,7 +4505,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4398,7 +4514,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4410,20 +4526,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void UMAXReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4431,8 +4542,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::UMAXReduce, Long128VectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4442,7 +4576,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4456,20 +4590,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4478,7 +4607,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4487,7 +4616,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4499,20 +4628,15 @@ public class Long128VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4520,8 +4644,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::FIRST_NONZEROReduce, Long128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4531,7 +4678,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4545,20 +4692,15 @@ public class Long128VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4615,7 +4757,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4624,7 +4766,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4639,17 +4781,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4657,8 +4794,31 @@ public class Long128VectorTests extends AbstractVectorTest { Long128VectorTests::SUADDReduce, Long128VectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4668,7 +4828,7 @@ public class Long128VectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4684,17 +4844,12 @@ public class Long128VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index 3b276391cb7..c37e68e3728 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Long256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3677,7 +3689,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3686,7 +3698,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3698,20 +3710,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void ANDReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3719,8 +3726,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::ANDReduce, Long256VectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3730,7 +3760,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3744,20 +3774,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3766,7 +3791,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3775,7 +3800,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3790,17 +3815,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3808,8 +3828,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::ORReduce, Long256VectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3819,7 +3862,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3836,17 +3879,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3855,7 +3893,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3864,7 +3902,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3879,17 +3917,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3897,8 +3930,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::XORReduce, Long256VectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3908,7 +3964,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3925,17 +3981,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3944,7 +3995,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3953,7 +4004,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3968,17 +4019,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3986,8 +4032,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::ADDReduce, Long256VectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3997,7 +4066,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4014,17 +4083,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4033,7 +4097,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4042,7 +4106,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4054,20 +4118,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void MULReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4075,8 +4134,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::MULReduce, Long256VectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4086,7 +4168,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4100,20 +4182,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4122,7 +4199,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4131,7 +4208,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4143,20 +4220,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void MINReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4164,8 +4236,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::MINReduce, Long256VectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4175,7 +4270,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4189,20 +4284,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4211,7 +4301,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4220,7 +4310,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4232,20 +4322,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void MAXReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4253,8 +4338,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::MAXReduce, Long256VectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4264,7 +4372,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4278,20 +4386,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4300,7 +4403,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4309,7 +4412,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4321,20 +4424,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void UMINReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4342,8 +4440,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::UMINReduce, Long256VectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4353,7 +4474,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4367,20 +4488,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4389,7 +4505,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4398,7 +4514,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4410,20 +4526,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void UMAXReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4431,8 +4542,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::UMAXReduce, Long256VectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4442,7 +4576,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4456,20 +4590,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4478,7 +4607,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4487,7 +4616,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4499,20 +4628,15 @@ public class Long256VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4520,8 +4644,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::FIRST_NONZEROReduce, Long256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4531,7 +4678,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4545,20 +4692,15 @@ public class Long256VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4615,7 +4757,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4624,7 +4766,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4639,17 +4781,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4657,8 +4794,31 @@ public class Long256VectorTests extends AbstractVectorTest { Long256VectorTests::SUADDReduce, Long256VectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4668,7 +4828,7 @@ public class Long256VectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4684,17 +4844,12 @@ public class Long256VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 181116cf399..5f8abb5bdd5 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Long512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3677,7 +3689,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3686,7 +3698,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3698,20 +3710,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void ANDReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3719,8 +3726,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::ANDReduce, Long512VectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3730,7 +3760,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3744,20 +3774,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3766,7 +3791,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3775,7 +3800,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3790,17 +3815,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3808,8 +3828,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::ORReduce, Long512VectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3819,7 +3862,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3836,17 +3879,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3855,7 +3893,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3864,7 +3902,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3879,17 +3917,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3897,8 +3930,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::XORReduce, Long512VectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3908,7 +3964,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3925,17 +3981,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3944,7 +3995,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3953,7 +4004,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3968,17 +4019,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3986,8 +4032,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::ADDReduce, Long512VectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3997,7 +4066,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4014,17 +4083,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4033,7 +4097,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4042,7 +4106,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4054,20 +4118,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void MULReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4075,8 +4134,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::MULReduce, Long512VectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4086,7 +4168,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4100,20 +4182,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4122,7 +4199,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4131,7 +4208,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4143,20 +4220,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void MINReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4164,8 +4236,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::MINReduce, Long512VectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4175,7 +4270,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4189,20 +4284,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4211,7 +4301,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4220,7 +4310,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4232,20 +4322,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void MAXReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4253,8 +4338,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::MAXReduce, Long512VectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4264,7 +4372,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4278,20 +4386,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4300,7 +4403,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4309,7 +4412,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4321,20 +4424,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void UMINReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4342,8 +4440,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::UMINReduce, Long512VectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4353,7 +4474,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4367,20 +4488,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4389,7 +4505,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4398,7 +4514,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4410,20 +4526,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void UMAXReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4431,8 +4542,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::UMAXReduce, Long512VectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4442,7 +4576,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4456,20 +4590,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4478,7 +4607,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4487,7 +4616,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4499,20 +4628,15 @@ public class Long512VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4520,8 +4644,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::FIRST_NONZEROReduce, Long512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4531,7 +4678,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4545,20 +4692,15 @@ public class Long512VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4615,7 +4757,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4624,7 +4766,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4639,17 +4781,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4657,8 +4794,31 @@ public class Long512VectorTests extends AbstractVectorTest { Long512VectorTests::SUADDReduce, Long512VectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4668,7 +4828,7 @@ public class Long512VectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4684,17 +4844,12 @@ public class Long512VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index cb052925778..5f8a9018384 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Long64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3677,7 +3689,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3686,7 +3698,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3698,20 +3710,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void ANDReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3719,8 +3726,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::ANDReduce, Long64VectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3730,7 +3760,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3744,20 +3774,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3766,7 +3791,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3775,7 +3800,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3790,17 +3815,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3808,8 +3828,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::ORReduce, Long64VectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3819,7 +3862,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3836,17 +3879,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3855,7 +3893,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3864,7 +3902,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3879,17 +3917,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3897,8 +3930,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::XORReduce, Long64VectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3908,7 +3964,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3925,17 +3981,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3944,7 +3995,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3953,7 +4004,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3968,17 +4019,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3986,8 +4032,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::ADDReduce, Long64VectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3997,7 +4066,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4014,17 +4083,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4033,7 +4097,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4042,7 +4106,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4054,20 +4118,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void MULReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4075,8 +4134,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::MULReduce, Long64VectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4086,7 +4168,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4100,20 +4182,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4122,7 +4199,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4131,7 +4208,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4143,20 +4220,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void MINReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4164,8 +4236,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::MINReduce, Long64VectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4175,7 +4270,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4189,20 +4284,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4211,7 +4301,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4220,7 +4310,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4232,20 +4322,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void MAXReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4253,8 +4338,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::MAXReduce, Long64VectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4264,7 +4372,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4278,20 +4386,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4300,7 +4403,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4309,7 +4412,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4321,20 +4424,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void UMINReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4342,8 +4440,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::UMINReduce, Long64VectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4353,7 +4474,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4367,20 +4488,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4389,7 +4505,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4398,7 +4514,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4410,20 +4526,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void UMAXReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4431,8 +4542,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::UMAXReduce, Long64VectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4442,7 +4576,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4456,20 +4590,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4478,7 +4607,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4487,7 +4616,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4499,20 +4628,15 @@ public class Long64VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4520,8 +4644,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::FIRST_NONZEROReduce, Long64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4531,7 +4678,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4545,20 +4692,15 @@ public class Long64VectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4615,7 +4757,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4624,7 +4766,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4639,17 +4781,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4657,8 +4794,31 @@ public class Long64VectorTests extends AbstractVectorTest { Long64VectorTests::SUADDReduce, Long64VectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4668,7 +4828,7 @@ public class Long64VectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4684,17 +4844,12 @@ public class Long64VectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index 6fe189867c2..17fee0a7765 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +71,19 @@ public class LongMaxVectorTests extends AbstractVectorTest { private static final long CONST_SHIFT = Long.SIZE / 2; + // Identity values for reduction operations + private static final long ADD_IDENTITY = (long)0; + private static final long AND_IDENTITY = (long)-1; + private static final long FIRST_NONZERO_IDENTITY = (long)0; + private static final long MAX_IDENTITY = Long.MIN_VALUE; + private static final long MIN_IDENTITY = Long.MAX_VALUE; + private static final long MUL_IDENTITY = (long)1; + private static final long OR_IDENTITY = (long)0; + private static final long SUADD_IDENTITY = (long)0; + private static final long UMAX_IDENTITY = (long)0; // Minimum unsigned value + private static final long UMIN_IDENTITY = (long)-1; // Maximum unsigned value + private static final long XOR_IDENTITY = (long)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); static void assertArraysStrictlyEquals(long[] r, long[] a) { @@ -3682,7 +3695,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ANDReduce(long[] a, int idx) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3691,7 +3704,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ANDReduceAll(long[] a) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3703,20 +3716,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void ANDReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + long v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3724,8 +3732,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::ANDReduce, LongMaxVectorTests::ANDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = AND_IDENTITY; + + Assert.assertEquals((long) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id & x), x); + Assert.assertEquals((long) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static long ANDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3735,7 +3766,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ANDReduceAllMasked(long[] a, boolean[] mask) { - long res = -1; + long res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3749,20 +3780,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = -1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + long v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3771,7 +3797,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ORReduce(long[] a, int idx) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3780,7 +3806,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ORReduceAll(long[] a) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3795,17 +3821,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + long v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3813,8 +3834,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::ORReduce, LongMaxVectorTests::ORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = OR_IDENTITY; + + Assert.assertEquals((long) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id | x), x); + Assert.assertEquals((long) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static long ORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3824,7 +3868,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3841,17 +3885,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + long v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3860,7 +3899,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long XORReduce(long[] a, int idx) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3869,7 +3908,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long XORReduceAll(long[] a) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3884,17 +3923,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + long v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3902,8 +3936,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::XORReduce, LongMaxVectorTests::XORReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = XOR_IDENTITY; + + Assert.assertEquals((long) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id ^ x), x); + Assert.assertEquals((long) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static long XORReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3913,7 +3970,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long XORReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3930,17 +3987,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + long v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3949,7 +4001,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ADDReduce(long[] a, int idx) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3958,7 +4010,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ADDReduceAll(long[] a) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3973,17 +4025,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + long v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3991,8 +4038,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::ADDReduce, LongMaxVectorTests::ADDReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = ADD_IDENTITY; + + Assert.assertEquals((long) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id + x), x); + Assert.assertEquals((long) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static long ADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -4002,7 +4072,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long ADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -4019,17 +4089,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + long v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -4038,7 +4103,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MULReduce(long[] a, int idx) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -4047,7 +4112,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MULReduceAll(long[] a) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -4059,20 +4124,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void MULReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + long v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4080,8 +4140,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::MULReduce, LongMaxVectorTests::MULReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MUL_IDENTITY; + + Assert.assertEquals((long) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) (id * x), x); + Assert.assertEquals((long) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static long MULReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4091,7 +4174,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MULReduceAllMasked(long[] a, boolean[] mask) { - long res = 1; + long res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4105,20 +4188,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = 1; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + long v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4127,7 +4205,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.min(res, a[i]); } @@ -4136,7 +4214,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduce(a, i)); } @@ -4148,20 +4226,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void MINReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + long v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4169,8 +4242,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::MINReduce, LongMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MIN_IDENTITY; + + Assert.assertEquals((long) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.min(id, x), x); + Assert.assertEquals((long) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static long MINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.min(res, a[i]); @@ -4180,7 +4276,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4194,20 +4290,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + long v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (long) Math.min(ra, v); } } @@ -4216,7 +4307,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) Math.max(res, a[i]); } @@ -4225,7 +4316,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduce(a, i)); } @@ -4237,20 +4328,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void MAXReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + long v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4258,8 +4344,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::MAXReduce, LongMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = MAX_IDENTITY; + + Assert.assertEquals((long) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) Math.max(id, x), x); + Assert.assertEquals((long) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static long MAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) Math.max(res, a[i]); @@ -4269,7 +4378,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long MAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4283,20 +4392,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + long v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (long) Math.max(ra, v); } } @@ -4305,7 +4409,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMINReduce(long[] a, int idx) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.minUnsigned(res, a[i]); } @@ -4314,7 +4418,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMINReduceAll(long[] a) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4326,20 +4430,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void UMINReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + long v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4347,8 +4446,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::UMINReduce, LongMaxVectorTests::UMINReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMIN_IDENTITY; + + Assert.assertEquals((long) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static long UMINReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.minUnsigned(res, a[i]); @@ -4358,7 +4480,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMINReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MAX_VALUE; + long res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4372,20 +4494,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MAX_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + long v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (long) VectorMath.minUnsigned(ra, v); } } @@ -4394,7 +4511,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMAXReduce(long[] a, int idx) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.maxUnsigned(res, a[i]); } @@ -4403,7 +4520,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMAXReduceAll(long[] a) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4415,20 +4532,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void UMAXReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + long v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4436,8 +4548,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::UMAXReduce, LongMaxVectorTests::UMAXReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = UMAX_IDENTITY; + + Assert.assertEquals((long) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static long UMAXReduceMasked(long[] a, int idx, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.maxUnsigned(res, a[i]); @@ -4447,7 +4582,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long UMAXReduceAllMasked(long[] a, boolean[] mask) { - long res = Long.MIN_VALUE; + long res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4461,20 +4596,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = Long.MIN_VALUE; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Long.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + long v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (long) VectorMath.maxUnsigned(ra, v); } } @@ -4483,7 +4613,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduce(long[] a, int idx) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4492,7 +4622,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAll(long[] a) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4504,20 +4634,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4525,8 +4650,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::FIRST_NONZEROReduce, LongMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "longUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static long FIRST_NONZEROReduceMasked(long[] a, int idx, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4536,7 +4684,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long FIRST_NONZEROReduceAllMasked(long[] a, boolean[] mask) { - long res = (long) 0; + long res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4550,20 +4698,15 @@ public class LongMaxVectorTests extends AbstractVectorTest { long[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - long ra = (long) 0; + long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (long) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + long v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4620,7 +4763,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long SUADDReduce(long[] a, int idx) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4629,7 +4772,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long SUADDReduceAll(long[] a) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4644,17 +4787,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + long v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4662,8 +4800,31 @@ public class LongMaxVectorTests extends AbstractVectorTest { LongMaxVectorTests::SUADDReduce, LongMaxVectorTests::SUADDReduceAll); } + @Test(dataProvider = "longSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long id = SUADD_IDENTITY; + + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + long x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((long) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static long SUADDReduceMasked(long[] a, int idx, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (long) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4673,7 +4834,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { } static long SUADDReduceAllMasked(long[] a, boolean[] mask) { - long res = 0; + long res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (long) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4689,17 +4850,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { long ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - LongVector av = LongVector.fromArray(SPECIES, a, i); - ra = (long) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + long v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (long) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index be39a01a4e7..fb740fedfd4 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Short128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3602,7 +3614,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3611,7 +3623,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3623,20 +3635,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void ANDReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3644,8 +3651,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::ANDReduce, Short128VectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3655,7 +3685,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3669,20 +3699,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3691,7 +3716,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3700,7 +3725,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3715,17 +3740,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3733,8 +3753,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::ORReduce, Short128VectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3744,7 +3787,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3761,17 +3804,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3780,7 +3818,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3789,7 +3827,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3804,17 +3842,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3822,8 +3855,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::XORReduce, Short128VectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3833,7 +3889,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3850,17 +3906,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3869,7 +3920,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3878,7 +3929,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3893,17 +3944,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3911,8 +3957,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::ADDReduce, Short128VectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3922,7 +3991,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3939,17 +4008,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3958,7 +4022,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3967,7 +4031,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3979,20 +4043,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void MULReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4000,8 +4059,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::MULReduce, Short128VectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4011,7 +4093,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4025,20 +4107,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4047,7 +4124,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4056,7 +4133,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4068,20 +4145,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void MINReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4089,8 +4161,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::MINReduce, Short128VectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4100,7 +4195,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4114,20 +4209,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4136,7 +4226,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4145,7 +4235,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4157,20 +4247,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void MAXReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4178,8 +4263,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::MAXReduce, Short128VectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4189,7 +4297,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4203,20 +4311,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4225,7 +4328,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4234,7 +4337,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4246,20 +4349,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void UMINReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4267,8 +4365,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::UMINReduce, Short128VectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4278,7 +4399,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4292,20 +4413,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4314,7 +4430,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4323,7 +4439,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4335,20 +4451,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void UMAXReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4356,8 +4467,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::UMAXReduce, Short128VectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4367,7 +4501,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4381,20 +4515,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4403,7 +4532,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4412,7 +4541,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4424,20 +4553,15 @@ public class Short128VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4445,8 +4569,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::FIRST_NONZEROReduce, Short128VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4456,7 +4603,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4470,20 +4617,15 @@ public class Short128VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4540,7 +4682,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4549,7 +4691,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4564,17 +4706,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4582,8 +4719,31 @@ public class Short128VectorTests extends AbstractVectorTest { Short128VectorTests::SUADDReduce, Short128VectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4593,7 +4753,7 @@ public class Short128VectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4609,17 +4769,12 @@ public class Short128VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 0b6ae53710e..cd6aa113b84 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Short256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3602,7 +3614,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3611,7 +3623,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3623,20 +3635,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void ANDReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3644,8 +3651,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::ANDReduce, Short256VectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3655,7 +3685,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3669,20 +3699,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3691,7 +3716,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3700,7 +3725,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3715,17 +3740,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3733,8 +3753,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::ORReduce, Short256VectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3744,7 +3787,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3761,17 +3804,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3780,7 +3818,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3789,7 +3827,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3804,17 +3842,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3822,8 +3855,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::XORReduce, Short256VectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3833,7 +3889,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3850,17 +3906,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3869,7 +3920,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3878,7 +3929,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3893,17 +3944,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3911,8 +3957,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::ADDReduce, Short256VectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3922,7 +3991,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3939,17 +4008,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3958,7 +4022,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3967,7 +4031,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3979,20 +4043,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void MULReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4000,8 +4059,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::MULReduce, Short256VectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4011,7 +4093,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4025,20 +4107,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4047,7 +4124,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4056,7 +4133,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4068,20 +4145,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void MINReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4089,8 +4161,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::MINReduce, Short256VectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4100,7 +4195,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4114,20 +4209,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4136,7 +4226,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4145,7 +4235,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4157,20 +4247,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void MAXReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4178,8 +4263,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::MAXReduce, Short256VectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4189,7 +4297,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4203,20 +4311,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4225,7 +4328,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4234,7 +4337,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4246,20 +4349,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void UMINReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4267,8 +4365,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::UMINReduce, Short256VectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4278,7 +4399,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4292,20 +4413,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4314,7 +4430,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4323,7 +4439,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4335,20 +4451,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void UMAXReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4356,8 +4467,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::UMAXReduce, Short256VectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4367,7 +4501,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4381,20 +4515,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4403,7 +4532,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4412,7 +4541,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4424,20 +4553,15 @@ public class Short256VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4445,8 +4569,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::FIRST_NONZEROReduce, Short256VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4456,7 +4603,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4470,20 +4617,15 @@ public class Short256VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4540,7 +4682,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4549,7 +4691,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4564,17 +4706,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4582,8 +4719,31 @@ public class Short256VectorTests extends AbstractVectorTest { Short256VectorTests::SUADDReduce, Short256VectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4593,7 +4753,7 @@ public class Short256VectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4609,17 +4769,12 @@ public class Short256VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index d4568068b6a..722f826f3e9 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Short512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3602,7 +3614,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3611,7 +3623,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3623,20 +3635,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void ANDReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3644,8 +3651,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::ANDReduce, Short512VectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3655,7 +3685,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3669,20 +3699,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3691,7 +3716,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3700,7 +3725,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3715,17 +3740,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3733,8 +3753,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::ORReduce, Short512VectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3744,7 +3787,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3761,17 +3804,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3780,7 +3818,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3789,7 +3827,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3804,17 +3842,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3822,8 +3855,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::XORReduce, Short512VectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3833,7 +3889,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3850,17 +3906,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3869,7 +3920,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3878,7 +3929,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3893,17 +3944,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3911,8 +3957,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::ADDReduce, Short512VectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3922,7 +3991,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3939,17 +4008,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3958,7 +4022,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3967,7 +4031,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3979,20 +4043,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void MULReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4000,8 +4059,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::MULReduce, Short512VectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4011,7 +4093,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4025,20 +4107,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4047,7 +4124,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4056,7 +4133,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4068,20 +4145,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void MINReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4089,8 +4161,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::MINReduce, Short512VectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4100,7 +4195,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4114,20 +4209,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4136,7 +4226,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4145,7 +4235,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4157,20 +4247,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void MAXReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4178,8 +4263,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::MAXReduce, Short512VectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4189,7 +4297,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4203,20 +4311,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4225,7 +4328,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4234,7 +4337,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4246,20 +4349,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void UMINReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4267,8 +4365,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::UMINReduce, Short512VectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4278,7 +4399,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4292,20 +4413,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4314,7 +4430,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4323,7 +4439,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4335,20 +4451,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void UMAXReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4356,8 +4467,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::UMAXReduce, Short512VectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4367,7 +4501,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4381,20 +4515,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4403,7 +4532,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4412,7 +4541,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4424,20 +4553,15 @@ public class Short512VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4445,8 +4569,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::FIRST_NONZEROReduce, Short512VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4456,7 +4603,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4470,20 +4617,15 @@ public class Short512VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4540,7 +4682,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4549,7 +4691,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4564,17 +4706,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4582,8 +4719,31 @@ public class Short512VectorTests extends AbstractVectorTest { Short512VectorTests::SUADDReduce, Short512VectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4593,7 +4753,7 @@ public class Short512VectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4609,17 +4769,12 @@ public class Short512VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 83d5cfd18e8..9ec8ac08789 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +63,21 @@ public class Short64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3602,7 +3614,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3611,7 +3623,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3623,20 +3635,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void ANDReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3644,8 +3651,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::ANDReduce, Short64VectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3655,7 +3685,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3669,20 +3699,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3691,7 +3716,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3700,7 +3725,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3715,17 +3740,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3733,8 +3753,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::ORReduce, Short64VectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3744,7 +3787,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3761,17 +3804,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3780,7 +3818,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3789,7 +3827,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3804,17 +3842,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3822,8 +3855,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::XORReduce, Short64VectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3833,7 +3889,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3850,17 +3906,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3869,7 +3920,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3878,7 +3929,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3893,17 +3944,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3911,8 +3957,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::ADDReduce, Short64VectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3922,7 +3991,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3939,17 +4008,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3958,7 +4022,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3967,7 +4031,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3979,20 +4043,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void MULReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4000,8 +4059,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::MULReduce, Short64VectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4011,7 +4093,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4025,20 +4107,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4047,7 +4124,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4056,7 +4133,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4068,20 +4145,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void MINReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4089,8 +4161,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::MINReduce, Short64VectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4100,7 +4195,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4114,20 +4209,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4136,7 +4226,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4145,7 +4235,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4157,20 +4247,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void MAXReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4178,8 +4263,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::MAXReduce, Short64VectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4189,7 +4297,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4203,20 +4311,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4225,7 +4328,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4234,7 +4337,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4246,20 +4349,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void UMINReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4267,8 +4365,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::UMINReduce, Short64VectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4278,7 +4399,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4292,20 +4413,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4314,7 +4430,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4323,7 +4439,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4335,20 +4451,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void UMAXReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4356,8 +4467,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::UMAXReduce, Short64VectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4367,7 +4501,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4381,20 +4515,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4403,7 +4532,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4412,7 +4541,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4424,20 +4553,15 @@ public class Short64VectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4445,8 +4569,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::FIRST_NONZEROReduce, Short64VectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4456,7 +4603,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4470,20 +4617,15 @@ public class Short64VectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4540,7 +4682,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4549,7 +4691,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4564,17 +4706,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4582,8 +4719,31 @@ public class Short64VectorTests extends AbstractVectorTest { Short64VectorTests::SUADDReduce, Short64VectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4593,7 +4753,7 @@ public class Short64VectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4609,17 +4769,12 @@ public class Short64VectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 45ba8db51c1..ad2efd3575d 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +71,19 @@ public class ShortMaxVectorTests extends AbstractVectorTest { private static final short CONST_SHIFT = Short.SIZE / 2; + // Identity values for reduction operations + private static final short ADD_IDENTITY = (short)0; + private static final short AND_IDENTITY = (short)-1; + private static final short FIRST_NONZERO_IDENTITY = (short)0; + private static final short MAX_IDENTITY = Short.MIN_VALUE; + private static final short MIN_IDENTITY = Short.MAX_VALUE; + private static final short MUL_IDENTITY = (short)1; + private static final short OR_IDENTITY = (short)0; + private static final short SUADD_IDENTITY = (short)0; + private static final short UMAX_IDENTITY = (short)0; // Minimum unsigned value + private static final short UMIN_IDENTITY = (short)-1; // Maximum unsigned value + private static final short XOR_IDENTITY = (short)0; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); static void assertArraysStrictlyEquals(short[] r, short[] a) { @@ -3607,7 +3620,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ANDReduce(short[] a, int idx) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res &= a[i]; } @@ -3616,7 +3629,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ANDReduceAll(short[] a) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduce(a, i); } @@ -3628,20 +3641,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void ANDReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND); + short v = av.reduceLanes(VectorOperators.AND); + r[i] = v; + ra &= v; } } @@ -3649,8 +3657,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::ANDReduce, ShortMaxVectorTests::ANDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ANDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = AND_IDENTITY; + + Assert.assertEquals((short) (id & id), id, + "AND(AND_IDENTITY, AND_IDENTITY) != AND_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id & x), x); + Assert.assertEquals((short) (x & id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id & x), x, + "AND(AND_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x & id), x, + "AND(" + x + ", AND_IDENTITY) != " + x); + } + } + static short ANDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res &= a[i]; @@ -3660,7 +3691,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ANDReduceAllMasked(short[] a, boolean[] mask) { - short res = -1; + short res = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res &= ANDReduceMasked(a, i, mask); } @@ -3674,20 +3705,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = -1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = AND_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.AND, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = -1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra &= av.reduceLanes(VectorOperators.AND, vmask); + short v = av.reduceLanes(VectorOperators.AND, vmask); + r[i] = v; + ra &= v; } } @@ -3696,7 +3722,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ORReduce(short[] a, int idx) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res |= a[i]; } @@ -3705,7 +3731,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ORReduceAll(short[] a) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduce(a, i); } @@ -3720,17 +3746,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR); + short v = av.reduceLanes(VectorOperators.OR); + r[i] = v; + ra |= v; } } @@ -3738,8 +3759,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::ORReduce, ShortMaxVectorTests::ORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = OR_IDENTITY; + + Assert.assertEquals((short) (id | id), id, + "OR(OR_IDENTITY, OR_IDENTITY) != OR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id | x), x); + Assert.assertEquals((short) (x | id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id | x), x, + "OR(OR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x | id), x, + "OR(" + x + ", OR_IDENTITY) != " + x); + } + } + static short ORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res |= a[i]; @@ -3749,7 +3793,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res |= ORReduceMasked(a, i, mask); } @@ -3766,17 +3810,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = OR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.OR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra |= av.reduceLanes(VectorOperators.OR, vmask); + short v = av.reduceLanes(VectorOperators.OR, vmask); + r[i] = v; + ra |= v; } } @@ -3785,7 +3824,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short XORReduce(short[] a, int idx) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res ^= a[i]; } @@ -3794,7 +3833,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short XORReduceAll(short[] a) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduce(a, i); } @@ -3809,17 +3848,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR); + short v = av.reduceLanes(VectorOperators.XOR); + r[i] = v; + ra ^= v; } } @@ -3827,8 +3861,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::XORReduce, ShortMaxVectorTests::XORReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void XORReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = XOR_IDENTITY; + + Assert.assertEquals((short) (id ^ id), id, + "XOR(XOR_IDENTITY, XOR_IDENTITY) != XOR_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id ^ x), x); + Assert.assertEquals((short) (x ^ id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id ^ x), x, + "XOR(XOR_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x ^ id), x, + "XOR(" + x + ", XOR_IDENTITY) != " + x); + } + } + static short XORReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res ^= a[i]; @@ -3838,7 +3895,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short XORReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res ^= XORReduceMasked(a, i, mask); } @@ -3855,17 +3912,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = XOR_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.XOR, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra ^= av.reduceLanes(VectorOperators.XOR, vmask); + short v = av.reduceLanes(VectorOperators.XOR, vmask); + r[i] = v; + ra ^= v; } } @@ -3874,7 +3926,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ADDReduce(short[] a, int idx) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res += a[i]; } @@ -3883,7 +3935,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ADDReduceAll(short[] a) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduce(a, i); } @@ -3898,17 +3950,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD); + short v = av.reduceLanes(VectorOperators.ADD); + r[i] = v; + ra += v; } } @@ -3916,8 +3963,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::ADDReduce, ShortMaxVectorTests::ADDReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void ADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = ADD_IDENTITY; + + Assert.assertEquals((short) (id + id), id, + "ADD(ADD_IDENTITY, ADD_IDENTITY) != ADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id + x), x); + Assert.assertEquals((short) (x + id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id + x), x, + "ADD(ADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x + id), x, + "ADD(" + x + ", ADD_IDENTITY) != " + x); + } + } + static short ADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res += a[i]; @@ -3927,7 +3997,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short ADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res += ADDReduceMasked(a, i, mask); } @@ -3944,17 +4014,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = ADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.ADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra += av.reduceLanes(VectorOperators.ADD, vmask); + short v = av.reduceLanes(VectorOperators.ADD, vmask); + r[i] = v; + ra += v; } } @@ -3963,7 +4028,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MULReduce(short[] a, int idx) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res *= a[i]; } @@ -3972,7 +4037,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MULReduceAll(short[] a) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduce(a, i); } @@ -3984,20 +4049,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void MULReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL); + short v = av.reduceLanes(VectorOperators.MUL); + r[i] = v; + ra *= v; } } @@ -4005,8 +4065,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::MULReduce, ShortMaxVectorTests::MULReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MULReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MUL_IDENTITY; + + Assert.assertEquals((short) (id * id), id, + "MUL(MUL_IDENTITY, MUL_IDENTITY) != MUL_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) (id * x), x); + Assert.assertEquals((short) (x * id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) (id * x), x, + "MUL(MUL_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) (x * id), x, + "MUL(" + x + ", MUL_IDENTITY) != " + x); + } + } + static short MULReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res *= a[i]; @@ -4016,7 +4099,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MULReduceAllMasked(short[] a, boolean[] mask) { - short res = 1; + short res = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res *= MULReduceMasked(a, i, mask); } @@ -4030,20 +4113,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = 1; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MUL_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MUL, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 1; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra *= av.reduceLanes(VectorOperators.MUL, vmask); + short v = av.reduceLanes(VectorOperators.MUL, vmask); + r[i] = v; + ra *= v; } } @@ -4052,7 +4130,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.min(res, a[i]); } @@ -4061,7 +4139,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduce(a, i)); } @@ -4073,20 +4151,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void MINReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN)); + short v = av.reduceLanes(VectorOperators.MIN); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4094,8 +4167,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::MINReduce, ShortMaxVectorTests::MINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MIN_IDENTITY; + + Assert.assertEquals((short) Math.min(id, id), id, + "MIN(MIN_IDENTITY, MIN_IDENTITY) != MIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.min(id, x), x); + Assert.assertEquals((short) Math.min(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.min(id, x), x, + "MIN(MIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.min(x, id), x, + "MIN(" + x + ", MIN_IDENTITY) != " + x); + } + } + static short MINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.min(res, a[i]); @@ -4105,7 +4201,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.min(res, MINReduceMasked(a, i, mask)); } @@ -4119,20 +4215,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.min(ra, av.reduceLanes(VectorOperators.MIN, vmask)); + short v = av.reduceLanes(VectorOperators.MIN, vmask); + r[i] = v; + ra = (short) Math.min(ra, v); } } @@ -4141,7 +4232,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) Math.max(res, a[i]); } @@ -4150,7 +4241,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduce(a, i)); } @@ -4162,20 +4253,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void MAXReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX)); + short v = av.reduceLanes(VectorOperators.MAX); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4183,8 +4269,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::MAXReduce, ShortMaxVectorTests::MAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = MAX_IDENTITY; + + Assert.assertEquals((short) Math.max(id, id), id, + "MAX(MAX_IDENTITY, MAX_IDENTITY) != MAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) Math.max(id, x), x); + Assert.assertEquals((short) Math.max(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) Math.max(id, x), x, + "MAX(MAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) Math.max(x, id), x, + "MAX(" + x + ", MAX_IDENTITY) != " + x); + } + } + static short MAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) Math.max(res, a[i]); @@ -4194,7 +4303,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short MAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) Math.max(res, MAXReduceMasked(a, i, mask)); } @@ -4208,20 +4317,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = MAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.MAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) Math.max(ra, av.reduceLanes(VectorOperators.MAX, vmask)); + short v = av.reduceLanes(VectorOperators.MAX, vmask); + r[i] = v; + ra = (short) Math.max(ra, v); } } @@ -4230,7 +4334,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMINReduce(short[] a, int idx) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.minUnsigned(res, a[i]); } @@ -4239,7 +4343,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMINReduceAll(short[] a) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduce(a, i)); } @@ -4251,20 +4355,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void UMINReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN)); + short v = av.reduceLanes(VectorOperators.UMIN); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4272,8 +4371,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::UMINReduce, ShortMaxVectorTests::UMINReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMINReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMIN_IDENTITY; + + Assert.assertEquals((short) VectorMath.minUnsigned(id, id), id, + "UMIN(UMIN_IDENTITY, UMIN_IDENTITY) != UMIN_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.minUnsigned(id, x), x, + "UMIN(UMIN_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.minUnsigned(x, id), x, + "UMIN(" + x + ", UMIN_IDENTITY) != " + x); + } + } + static short UMINReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.minUnsigned(res, a[i]); @@ -4283,7 +4405,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMINReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MAX_VALUE; + short res = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.minUnsigned(res, UMINReduceMasked(a, i, mask)); } @@ -4297,20 +4419,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MAX_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMIN_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMIN, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MAX_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.minUnsigned(ra, av.reduceLanes(VectorOperators.UMIN, vmask)); + short v = av.reduceLanes(VectorOperators.UMIN, vmask); + r[i] = v; + ra = (short) VectorMath.minUnsigned(ra, v); } } @@ -4319,7 +4436,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMAXReduce(short[] a, int idx) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.maxUnsigned(res, a[i]); } @@ -4328,7 +4445,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMAXReduceAll(short[] a) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduce(a, i)); } @@ -4340,20 +4457,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void UMAXReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX)); + short v = av.reduceLanes(VectorOperators.UMAX); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4361,8 +4473,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::UMAXReduce, ShortMaxVectorTests::UMAXReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void UMAXReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = UMAX_IDENTITY; + + Assert.assertEquals((short) VectorMath.maxUnsigned(id, id), id, + "UMAX(UMAX_IDENTITY, UMAX_IDENTITY) != UMAX_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.maxUnsigned(id, x), x, + "UMAX(UMAX_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.maxUnsigned(x, id), x, + "UMAX(" + x + ", UMAX_IDENTITY) != " + x); + } + } + static short UMAXReduceMasked(short[] a, int idx, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.maxUnsigned(res, a[i]); @@ -4372,7 +4507,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short UMAXReduceAllMasked(short[] a, boolean[] mask) { - short res = Short.MIN_VALUE; + short res = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.maxUnsigned(res, UMAXReduceMasked(a, i, mask)); } @@ -4386,20 +4521,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = Short.MIN_VALUE; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = UMAX_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.UMAX, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = Short.MIN_VALUE; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.maxUnsigned(ra, av.reduceLanes(VectorOperators.UMAX, vmask)); + short v = av.reduceLanes(VectorOperators.UMAX, vmask); + r[i] = v; + ra = (short) VectorMath.maxUnsigned(ra, v); } } @@ -4408,7 +4538,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduce(short[] a, int idx) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = firstNonZero(res, a[i]); } @@ -4417,7 +4547,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAll(short[] a) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduce(a, i)); } @@ -4429,20 +4559,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { static void FIRST_NONZEROReduceShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4450,8 +4575,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::FIRST_NONZEROReduce, ShortMaxVectorTests::FIRST_NONZEROReduceAll); } + @Test(dataProvider = "shortUnaryOpProvider") + static void FIRST_NONZEROReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = FIRST_NONZERO_IDENTITY; + + Assert.assertEquals(firstNonZero(id, id), id, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, FIRST_NONZERO_IDENTITY) != FIRST_NONZERO_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(firstNonZero(id, x), x); + Assert.assertEquals(firstNonZero(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(firstNonZero(id, x), x, + "FIRST_NONZERO(FIRST_NONZERO_IDENTITY, " + x + ") != " + x); + Assert.assertEquals(firstNonZero(x, id), x, + "FIRST_NONZERO(" + x + ", FIRST_NONZERO_IDENTITY) != " + x); + } + } + static short FIRST_NONZEROReduceMasked(short[] a, int idx, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = firstNonZero(res, a[i]); @@ -4461,7 +4609,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short FIRST_NONZEROReduceAllMasked(short[] a, boolean[] mask) { - short res = (short) 0; + short res = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = firstNonZero(res, FIRST_NONZEROReduceMasked(a, i, mask)); } @@ -4475,20 +4623,15 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); - short ra = (short) 0; + short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = FIRST_NONZERO_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = (short) 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = firstNonZero(ra, av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask)); + short v = av.reduceLanes(VectorOperators.FIRST_NONZERO, vmask); + r[i] = v; + ra = firstNonZero(ra, v); } } @@ -4545,7 +4688,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short SUADDReduce(short[] a, int idx) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); } @@ -4554,7 +4697,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short SUADDReduceAll(short[] a) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduce(a, i)); } @@ -4569,17 +4712,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD)); + short v = av.reduceLanes(VectorOperators.SUADD); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } @@ -4587,8 +4725,31 @@ public class ShortMaxVectorTests extends AbstractVectorTest { ShortMaxVectorTests::SUADDReduce, ShortMaxVectorTests::SUADDReduceAll); } + @Test(dataProvider = "shortSaturatingUnaryOpProvider") + static void SUADDReduceIdentityValueTests(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short id = SUADD_IDENTITY; + + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, id), id, + "SUADD(SUADD_IDENTITY, SUADD_IDENTITY) != SUADD_IDENTITY"); + + short x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(id, x), x, + "SUADD(SUADD_IDENTITY, " + x + ") != " + x); + Assert.assertEquals((short) VectorMath.addSaturatingUnsigned(x, id), x, + "SUADD(" + x + ", SUADD_IDENTITY) != " + x); + } + } + static short SUADDReduceMasked(short[] a, int idx, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = idx; i < (idx + SPECIES.length()); i++) { if (mask[i % SPECIES.length()]) res = (short) VectorMath.addSaturatingUnsigned(res, a[i]); @@ -4598,7 +4759,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } static short SUADDReduceAllMasked(short[] a, boolean[] mask) { - short res = 0; + short res = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { res = (short) VectorMath.addSaturatingUnsigned(res, SUADDReduceMasked(a, i, mask)); } @@ -4614,17 +4775,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { short ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { + ra = SUADD_IDENTITY; for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.SUADD, vmask); - } - } - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - ra = 0; - for (int i = 0; i < a.length; i += SPECIES.length()) { - ShortVector av = ShortVector.fromArray(SPECIES, a, i); - ra = (short) VectorMath.addSaturatingUnsigned(ra, av.reduceLanes(VectorOperators.SUADD, vmask)); + short v = av.reduceLanes(VectorOperators.SUADD, vmask); + r[i] = v; + ra = (short) VectorMath.addSaturatingUnsigned(ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/gen-template.sh b/test/jdk/jdk/incubator/vector/gen-template.sh index d9bae116da2..d2528b13b78 100644 --- a/test/jdk/jdk/incubator/vector/gen-template.sh +++ b/test/jdk/jdk/incubator/vector/gen-template.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -511,23 +511,23 @@ gen_binary_bcst_op_no_masked "MAX+max" "Math.max(a, b)" gen_saturating_binary_op_associative "SUADD" "VectorMath.addSaturatingUnsigned(a, b)" "BITWISE" # Reductions. -gen_reduction_op "AND" "\&" "BITWISE" "-1" -gen_reduction_op "OR" "|" "BITWISE" "0" -gen_reduction_op "XOR" "^" "BITWISE" "0" -gen_reduction_op "ADD" "+" "" "0" -gen_reduction_op "MUL" "*" "" "1" -gen_reduction_op_func "MIN" "(\$type\$) Math.min" "" "\$Wideboxtype\$.\$MaxValue\$" -gen_reduction_op_func "MAX" "(\$type\$) Math.max" "" "\$Wideboxtype\$.\$MinValue\$" -gen_reduction_op_func "UMIN" "(\$type\$) VectorMath.minUnsigned" "BITWISE" "\$Wideboxtype\$.\$MaxValue\$" -gen_reduction_op_func "UMAX" "(\$type\$) VectorMath.maxUnsigned" "BITWISE" "\$Wideboxtype\$.\$MinValue\$" -gen_reduction_op_func "FIRST_NONZERO" "firstNonZero" "" "(\$type\$) 0" +gen_reduction_op "AND" "\&" "BITWISE" "AND_IDENTITY" +gen_reduction_op "OR" "|" "BITWISE" "OR_IDENTITY" +gen_reduction_op "XOR" "^" "BITWISE" "XOR_IDENTITY" +gen_reduction_op "ADD" "+" "" "ADD_IDENTITY" +gen_reduction_op "MUL" "*" "" "MUL_IDENTITY" +gen_reduction_op_func "MIN" "(\$type\$) Math.min" "" "MIN_IDENTITY" +gen_reduction_op_func "MAX" "(\$type\$) Math.max" "" "MAX_IDENTITY" +gen_reduction_op_func "UMIN" "(\$type\$) VectorMath.minUnsigned" "BITWISE" "UMIN_IDENTITY" +gen_reduction_op_func "UMAX" "(\$type\$) VectorMath.maxUnsigned" "BITWISE" "UMAX_IDENTITY" +gen_reduction_op_func "FIRST_NONZERO" "firstNonZero" "" "FIRST_NONZERO_IDENTITY" # Boolean reductions. gen_bool_reduction_op "anyTrue" "|" "BITWISE" "false" gen_bool_reduction_op "allTrue" "\&" "BITWISE" "true" # Saturating reductions. -gen_saturating_reduction_op "SUADD" "(\$type\$) VectorMath.addSaturatingUnsigned" "BITWISE" "0" +gen_saturating_reduction_op "SUADD" "(\$type\$) VectorMath.addSaturatingUnsigned" "BITWISE" "SUADD_IDENTITY" #Insert gen_with_op "withLane" "" "" "" diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template index bf03a4d0430..73e02bf68dd 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op-func.template @@ -2,20 +2,15 @@ $type$[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]], vmask); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]], vmask); + r[i] = v; + ra = [[TEST_OP]](ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op.template index f108491523e..82e20d594b6 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-Masked-op.template @@ -2,20 +2,15 @@ $type$[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]], vmask); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra [[TEST_OP]]= av.reduceLanes(VectorOperators.[[TEST]], vmask); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]], vmask); + r[i] = v; + ra [[TEST_OP]]= v; } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template index 7082ff0795e..94fae420cdd 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op-func.template @@ -1,19 +1,14 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] r = fr.apply(SPECIES.length()); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]]); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]])); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]]); + r[i] = v; + ra = [[TEST_OP]](ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op.template index 66250c09213..3edc2b27e3e 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Reduction-op.template @@ -1,19 +1,14 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] r = fr.apply(SPECIES.length()); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]]); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra [[TEST_OP]]= av.reduceLanes(VectorOperators.[[TEST]]); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]]); + r[i] = v; + ra [[TEST_OP]]= v; } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-Masked-op.template index bf03a4d0430..73e02bf68dd 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-Masked-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-Masked-op.template @@ -2,20 +2,15 @@ $type$[] r = fr.apply(SPECIES.length()); boolean[] mask = fm.apply(SPECIES.length()); VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]], vmask); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]], vmask)); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]], vmask); + r[i] = v; + ra = [[TEST_OP]](ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-op.template index 7082ff0795e..94fae420cdd 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-SaturatingReduction-op.template @@ -1,19 +1,14 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] r = fr.apply(SPECIES.length()); - $type$ ra = [[TEST_INIT]]; - - for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { - $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - r[i] = av.reduceLanes(VectorOperators.[[TEST]]); - } - } + $type$ ra = 0; for (int ic = 0; ic < INVOC_COUNT; ic++) { ra = [[TEST_INIT]]; for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - ra = [[TEST_OP]](ra, av.reduceLanes(VectorOperators.[[TEST]])); + $type$ v = av.reduceLanes(VectorOperators.[[TEST]]); + r[i] = v; + ra = [[TEST_OP]](ra, v); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template index e6bcdb83c2e..c797ad907fb 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op-func.template @@ -5,3 +5,26 @@ assertReductionArraysEquals(r, ra, a, $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); } + + @Test(dataProvider = "$type$UnaryOpProvider") + static void [[TEST]]ReduceIdentityValueTests(IntFunction<$type$[]> fa) { + $type$[] a = fa.apply(SPECIES.length()); + $type$ id = [[TEST_INIT]]; + + Assert.assertEquals([[TEST_OP]](id, id), id, + "[[TEST]]([[TEST_INIT]], [[TEST_INIT]]) != [[TEST_INIT]]"); + + $type$ x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals([[TEST_OP]](id, x), x); + Assert.assertEquals([[TEST_OP]](x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals([[TEST_OP]](id, x), x, + "[[TEST]]([[TEST_INIT]], " + x + ") != " + x); + Assert.assertEquals([[TEST_OP]](x, id), x, + "[[TEST]](" + x + ", [[TEST_INIT]]) != " + x); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template index 5638940045d..f8438fa58c8 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template @@ -9,3 +9,26 @@ $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); #end[FP] } + + @Test(dataProvider = "$type$UnaryOpProvider") + static void [[TEST]]ReduceIdentityValueTests(IntFunction<$type$[]> fa) { + $type$[] a = fa.apply(SPECIES.length()); + $type$ id = [[TEST_INIT]]; + + Assert.assertEquals(($type$) (id [[TEST_OP]] id), id, + "[[TEST]]([[TEST_INIT]], [[TEST_INIT]]) != [[TEST_INIT]]"); + + $type$ x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals(($type$) (id [[TEST_OP]] x), x); + Assert.assertEquals(($type$) (x [[TEST_OP]] id), x); + } + } catch (AssertionError e) { + Assert.assertEquals(($type$) (id [[TEST_OP]] x), x, + "[[TEST]]([[TEST_INIT]], " + x + ") != " + x); + Assert.assertEquals(($type$) (x [[TEST_OP]] id), x, + "[[TEST]](" + x + ", [[TEST_INIT]]) != " + x); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingReduction-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingReduction-op.template index fdd9e47167e..d961a29e5c8 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingReduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-SaturatingReduction-op.template @@ -5,3 +5,26 @@ assertReductionArraysEquals(r, ra, a, $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); } + + @Test(dataProvider = "$type$SaturatingUnaryOpProvider") + static void [[TEST]]ReduceIdentityValueTests(IntFunction<$type$[]> fa) { + $type$[] a = fa.apply(SPECIES.length()); + $type$ id = [[TEST_INIT]]; + + Assert.assertEquals([[TEST_OP]](id, id), id, + "[[TEST]]([[TEST_INIT]], [[TEST_INIT]]) != [[TEST_INIT]]"); + + $type$ x = 0; + try { + for (int i = 0; i < a.length; i++) { + x = a[i]; + Assert.assertEquals([[TEST_OP]](id, x), x); + Assert.assertEquals([[TEST_OP]](x, id), x); + } + } catch (AssertionError e) { + Assert.assertEquals([[TEST_OP]](id, x), x, + "[[TEST]]([[TEST_INIT]], " + x + ") != " + x); + Assert.assertEquals([[TEST_OP]](x, id), x, + "[[TEST]](" + x + ", [[TEST_INIT]]) != " + x); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 7e00cb1678c..e1ec6624022 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,19 +86,37 @@ public class $vectorteststype$ extends AbstractVectorTest { #end[MaxBit] static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - #if[MaxBit] + static VectorShape getMaxBit() { return VectorShape.S_Max_BIT; } private static final int Max = 256; // juts so we can do N/$bits$ #end[MaxBit] - #if[BITWISE] + private static final $type$ CONST_SHIFT = $Boxtype$.SIZE / 2; #end[BITWISE] + + // Identity values for reduction operations + private static final $type$ ADD_IDENTITY = ($type$)0; +#if[BITWISE] + private static final $type$ AND_IDENTITY = ($type$)-1; +#end[BITWISE] + private static final $type$ FIRST_NONZERO_IDENTITY = ($type$)0; + private static final $type$ MAX_IDENTITY = $Wideboxtype$.$MinValue$; + private static final $type$ MIN_IDENTITY = $Wideboxtype$.$MaxValue$; + private static final $type$ MUL_IDENTITY = ($type$)1; +#if[BITWISE] + private static final $type$ OR_IDENTITY = ($type$)0; + private static final $type$ SUADD_IDENTITY = ($type$)0; + private static final $type$ UMAX_IDENTITY = ($type$)0; // Minimum unsigned value + private static final $type$ UMIN_IDENTITY = ($type$)-1; // Maximum unsigned value + private static final $type$ XOR_IDENTITY = ($type$)0; +#end[BITWISE] #if[FP] + // for floating point addition reduction ops that may introduce rounding errors private static final $type$ RELATIVE_ROUNDING_ERROR_FACTOR_ADD = ($type$)10.0; diff --git a/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java b/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java index dbcb30255a8..b86593d84ba 100644 --- a/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java +++ b/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java @@ -24,6 +24,7 @@ /** * @test * @requires vm.flagless + * @requires test.thread.factory == null * @library /test/lib * @modules java.base/jdk.internal.misc * jdk.zipfs diff --git a/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java b/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java index d540acd853b..b3630fa7f77 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2025, NTT DATA. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -98,8 +98,8 @@ public class TestEmergencyDumpAtOOM { // Check OldObjectSample events if (oldObjects.get() > 0L) { if (shouldCrash) { - Asserts.assertEquals("VM Error", shutdownReason.get()); - Asserts.assertEquals("Out of Memory", dumpReason.get()); + Asserts.assertEquals("CrashOnOutOfMemoryError", shutdownReason.get()); + Asserts.assertEquals("CrashOnOutOfMemoryError", dumpReason.get()); } else { Asserts.assertEquals("No remaining non-daemon Java threads", shutdownReason.get()); } diff --git a/test/jdk/sun/security/tools/keytool/ListAlias.java b/test/jdk/sun/security/tools/keytool/ListAlias.java new file mode 100644 index 00000000000..91994c04a9c --- /dev/null +++ b/test/jdk/sun/security/tools/keytool/ListAlias.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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 8286032 + * @summary Validate the warnings of the keytool -list -alias command + * @library /test/lib + */ + +import jdk.test.lib.SecurityTools; + +public class ListAlias { + + public static void main(String[] args) throws Exception { + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-genseckey -keyalg DES -alias deskey") + .shouldContain("Warning") + .shouldMatch("The generated secret key uses the DES algorithm.*considered a security risk") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-list -alias deskey -v") + .shouldContain("Warning") + .shouldMatch(" uses the DES algorithm.*considered a security risk") + .shouldNotContain("The certificate") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-genkeypair -keyalg RSA -alias ca -dname CN=CA -ext bc:c " + + "-sigalg SHA1withRSA") + .shouldContain("Warning") + .shouldMatch("The generated certificate uses the SHA1withRSA.*considered a security risk") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-list -alias ca -v") + .shouldContain("Warning") + .shouldMatch(" uses the SHA1withRSA.*considered a security risk") + .shouldNotContain("The certificate") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-list -v") + .shouldContain("Warning") + .shouldMatch(" uses the DES algorithm.*considered a security risk") + .shouldMatch(" uses the SHA1withRSA.*considered a security risk") + .shouldNotContain("The certificate") + .shouldHaveExitValue(0); + } +} \ No newline at end of file diff --git a/test/jdk/sun/security/tools/keytool/WeakAlg.java b/test/jdk/sun/security/tools/keytool/WeakAlg.java index de2435a4f4b..546a4182e97 100644 --- a/test/jdk/sun/security/tools/keytool/WeakAlg.java +++ b/test/jdk/sun/security/tools/keytool/WeakAlg.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -750,7 +750,7 @@ public class WeakAlg { oa.shouldNotContain("Warning"); } else { oa.shouldContain("Warning") - .shouldMatch("The certificate.*" + bad + ".*is disabled"); + .shouldMatch("uses.*" + bad + ".*is disabled"); } // With cert content @@ -770,7 +770,7 @@ public class WeakAlg { } else { oa.shouldContain("Warning") .shouldContain(bad + " (disabled)") - .shouldMatch("The certificate.*" + bad + ".*is disabled"); + .shouldMatch("uses.*" + bad + ".*is disabled"); } } @@ -844,11 +844,11 @@ public class WeakAlg { break; case "SHA1withRSA": oa.shouldContain("Warning") - .shouldMatch("The certificate.*" + bad + ".*considered a security risk"); + .shouldMatch("uses.*" + bad + ".*considered a security risk"); break; case "1024-bit RSA key": oa.shouldContain("Warning") - .shouldMatch("The certificate.*" + bad + ".*will be disabled"); + .shouldMatch("uses.*" + bad + ".*will be disabled"); break; } @@ -879,12 +879,12 @@ public class WeakAlg { case "SHA1withRSA": oa.shouldContain("Warning") .shouldContain(bad + " (weak)") - .shouldMatch("The certificate.*" + bad + ".*considered a security risk"); + .shouldMatch("uses.*" + bad + ".*considered a security risk"); break; case "1024-bit RSA key": oa.shouldContain("Warning") .shouldContain(bad + " (weak)") - .shouldMatch("The certificate.*" + bad + ".*will be disabled"); + .shouldMatch("uses.*" + bad + ".*will be disabled"); break; } } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java new file mode 100644 index 00000000000..b0d44702d47 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.spi.ToolProvider; +import jdk.jpackage.internal.util.function.ExceptionBox; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class JPackageCommandTest extends JUnitAdapter.TestSrcInitializer { + + @ParameterizedTest + @MethodSource + void testUseToolProvider(UseToolProviderTestSpec spec) { + // Run the test with the new state to avoid UnsupportedOperationException + // that will be thrown if it attempts to alter global variables in the default R/O state. + TKit.withNewState(spec::test); + } + + private static List testUseToolProvider() { + + var testCases = new ArrayList(); + + for (var globalToolProvider : ExecutableSetterType.values()) { + for (var instanceToolProvider : ExecutableSetterType.values()) { + testCases.add(new UseToolProviderTestSpec(globalToolProvider, instanceToolProvider)); + } + } + + return testCases; + } + + record UseToolProviderTestSpec(ExecutableSetterType globalType, ExecutableSetterType instanceType) { + + UseToolProviderTestSpec { + Objects.requireNonNull(globalType); + Objects.requireNonNull(instanceType); + } + + @Override + public String toString() { + return String.format("%s, global=%s", instanceType, globalType); + } + + void test() { + + final Optional global; + switch (globalType) { + case SET_CUSTOM_TOOL_PROVIDER -> { + global = Optional.of(createNewToolProvider("jpackage-mock-global")); + JPackageCommand.useToolProviderByDefault(global.get()); + } + case SET_DEFAULT_TOOL_PROVIDER -> { + global = Optional.of(JavaTool.JPACKAGE.asToolProvider()); + JPackageCommand.useToolProviderByDefault(); + } + case SET_PROCESS -> { + global = Optional.empty(); + JPackageCommand.useExecutableByDefault(); + } + case SET_NONE -> { + global = Optional.empty(); + } + default -> { + throw ExceptionBox.reachedUnreachable(); + } + } + + var cmd = new JPackageCommand(); + + final Optional instance; + switch (instanceType) { + case SET_CUSTOM_TOOL_PROVIDER -> { + instance = Optional.of(createNewToolProvider("jpackage-mock")); + cmd.useToolProvider(instance.get()); + } + case SET_DEFAULT_TOOL_PROVIDER -> { + instance = Optional.of(JavaTool.JPACKAGE.asToolProvider()); + cmd.useToolProvider(true); + } + case SET_PROCESS -> { + instance = Optional.empty(); + cmd.useToolProvider(false); + } + case SET_NONE -> { + instance = Optional.empty(); + } + default -> { + throw ExceptionBox.reachedUnreachable(); + } + } + + var actual = cmd.createExecutor().getToolProvider(); + + switch (instanceType) { + case SET_CUSTOM_TOOL_PROVIDER -> { + assertSame(actual.get(), instance.get()); + assertTrue(cmd.isWithToolProvider()); + } + case SET_DEFAULT_TOOL_PROVIDER -> { + global.ifPresentOrElse(expected -> { + assertEquals(expected.name(), actual.orElseThrow().name()); + }, () -> { + assertEquals(instance.get().name(), actual.get().name()); + }); + assertTrue(cmd.isWithToolProvider()); + } + case SET_PROCESS -> { + assertFalse(actual.isPresent()); + assertFalse(cmd.isWithToolProvider()); + } + case SET_NONE -> { + switch (globalType) { + case SET_CUSTOM_TOOL_PROVIDER -> { + assertSame(global.get(), actual.get()); + assertTrue(cmd.isWithToolProvider()); + } + case SET_DEFAULT_TOOL_PROVIDER -> { + assertEquals(global.get().name(), actual.orElseThrow().name()); + assertTrue(cmd.isWithToolProvider()); + } + case SET_PROCESS, SET_NONE -> { + assertFalse(actual.isPresent()); + assertFalse(cmd.isWithToolProvider()); + } + } + } + } + } + + private static ToolProvider createNewToolProvider(String name) { + return new ToolProvider() { + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + throw new UnsupportedOperationException(); + } + + @Override + public String name() { + return name; + } + }; + } + } + + enum ExecutableSetterType { + SET_DEFAULT_TOOL_PROVIDER, + SET_CUSTOM_TOOL_PROVIDER, + SET_PROCESS, + SET_NONE, + ; + } +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java index 1c6c0ce4447..55b13a06620 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java @@ -47,7 +47,7 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; public record AppImageFile(String mainLauncherName, Optional mainLauncherClassName, - String version, boolean macSigned, boolean macAppStore, Map> launchers) { + String version, boolean macAppStore, Map> launchers) { public static Path getPathInAppImage(Path appImageDir) { return ApplicationLayout.platformAppImage() @@ -66,7 +66,7 @@ public record AppImageFile(String mainLauncherName, Optional mainLaunche } public AppImageFile(String mainLauncherName, Optional mainLauncherClassName) { - this(mainLauncherName, mainLauncherClassName, "1.0", false, false, Map.of(mainLauncherName, Map.of())); + this(mainLauncherName, mainLauncherClassName, "1.0", false, Map.of(mainLauncherName, Map.of())); } public AppImageFile(String mainLauncherName, String mainLauncherClassName) { @@ -103,10 +103,6 @@ public record AppImageFile(String mainLauncherName, Optional mainLaunche xml.writeEndElement(); })); - xml.writeStartElement("signed"); - xml.writeCharacters(Boolean.toString(macSigned)); - xml.writeEndElement(); - xml.writeStartElement("app-store"); xml.writeCharacters(Boolean.toString(macAppStore)); xml.writeEndElement(); @@ -140,10 +136,6 @@ public record AppImageFile(String mainLauncherName, Optional mainLaunche var mainLauncherClassName = Optional.ofNullable(xPath.evaluate( "/jpackage-state/main-class/text()", doc)); - var macSigned = Optional.ofNullable(xPath.evaluate( - "/jpackage-state/signed/text()", doc)).map( - Boolean::parseBoolean).orElse(false); - var macAppStore = Optional.ofNullable(xPath.evaluate( "/jpackage-state/app-store/text()", doc)).map( Boolean::parseBoolean).orElse(false); @@ -171,7 +163,6 @@ public record AppImageFile(String mainLauncherName, Optional mainLaunche mainLauncherName, mainLauncherClassName, version, - macSigned, macAppStore, Collections.unmodifiableMap(launchers)); 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 5d3033e2e8c..1ae678cd944 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -35,6 +35,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.function.Supplier; import java.util.spi.ToolProvider; import java.util.stream.IntStream; @@ -62,6 +63,7 @@ public final class Executor extends CommandArguments { } public Executor() { + commandOutputControl.dumpStdout(TKit.state().out()).dumpStderr(TKit.state().err()); } public Executor setExecutable(String v) { @@ -84,6 +86,10 @@ public final class Executor extends CommandArguments { return setToolProvider(v.asToolProvider()); } + public Optional getToolProvider() { + return Optional.ofNullable(toolProvider); + } + public Optional getExecutable() { return Optional.ofNullable(executable); } @@ -109,15 +115,6 @@ public final class Executor extends CommandArguments { return this; } - public Executor setWinRunWithEnglishOutput(boolean value) { - if (!TKit.isWindows()) { - throw new UnsupportedOperationException( - "setWinRunWithEnglishOutput is only valid on Windows platform"); - } - winEnglishOutput = value; - return this; - } - public Executor setWindowsTmpDir(String tmp) { if (!TKit.isWindows()) { throw new UnsupportedOperationException( @@ -186,15 +183,20 @@ public final class Executor extends CommandArguments { return commandOutputControl.charset(); } - Executor storeOutputInFiles(boolean v) { + public Executor storeOutputInFiles(boolean v) { commandOutputControl.storeOutputInFiles(v); return this; } - Executor storeOutputInFiles() { + public Executor storeOutputInFiles() { return storeOutputInFiles(true); } + public Executor processListener(Consumer v) { + commandOutputControl.processListener(v); + return this; + } + public record Result(CommandOutputControl.Result base) { public Result { Objects.requireNonNull(base); @@ -281,11 +283,11 @@ public final class Executor extends CommandArguments { long expectedExitCode = expectedExitCodes.getFirst(); TKit.assertEquals(expectedExitCode, getExitCode(), String.format( "Check command %s exited with %d code", - base.execAttrs(), expectedExitCode)); + base.execAttrs().printableCommandLine(), expectedExitCode)); } default -> { TKit.assertTrue(expectedExitCodes.contains(getExitCode()), String.format( "Check command %s exited with one of %s codes", - base.execAttrs(), expectedExitCodes.stream().sorted().toList())); + base.execAttrs().printableCommandLine(), expectedExitCodes.stream().sorted().toList())); } } return this; @@ -300,7 +302,7 @@ public final class Executor extends CommandArguments { } public String getPrintableCommandLine() { - return base.execAttrs().toString(); + return base.execAttrs().printableCommandLine(); } } @@ -310,11 +312,6 @@ public final class Executor extends CommandArguments { "Can't change directory when using tool provider"); } - if (toolProvider != null && winEnglishOutput) { - throw new IllegalArgumentException( - "Can't change locale when using tool provider"); - } - return ThrowingSupplier.toSupplier(() -> { if (toolProvider != null) { return runToolProvider(); @@ -434,17 +431,8 @@ public final class Executor extends CommandArguments { return executable.toAbsolutePath(); } - private List prefixCommandLineArgs() { - if (winEnglishOutput) { - return List.of("cmd.exe", "/c", "chcp", "437", ">nul", "2>&1", "&&"); - } else { - return List.of(); - } - } - private Result runExecutable() throws IOException, InterruptedException { List command = new ArrayList<>(); - command.addAll(prefixCommandLineArgs()); command.add(executablePath().toString()); command.addAll(args); ProcessBuilder builder = new ProcessBuilder(command); @@ -522,27 +510,21 @@ public final class Executor extends CommandArguments { exec = executablePath().toString(); } - var cmdline = Stream.of(prefixCommandLineArgs(), List.of(exec), args).flatMap( - List::stream).toList(); + var cmdline = Stream.of(List.of(exec), args).flatMap(List::stream).toList(); return String.format(format, CommandLineFormat.DEFAULT.apply(cmdline), cmdline.size()); } - private record ExecutableAttributes(CommandOutputControl.ExecutableAttributes base, String toStringValue) + private record ExecutableAttributes(CommandOutputControl.ExecutableAttributes base, String printableCommandLine) implements CommandOutputControl.ExecutableAttributes { ExecutableAttributes { Objects.requireNonNull(base); - if (toStringValue.isBlank()) { + if (printableCommandLine.isBlank()) { throw new IllegalArgumentException(); } } - @Override - public String toString() { - return toStringValue; - } - @Override public List commandLine() { return base.commandLine(); @@ -559,6 +541,5 @@ public final class Executor extends CommandArguments { private Path directory; private Set removeEnvVars = new HashSet<>(); private Map setEnvVars = new HashMap<>(); - private boolean winEnglishOutput; private String winTmpDir = null; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 6c7b6a25255..bc731e18136 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.regex.Matcher; @@ -315,37 +316,33 @@ public final class HelloApp { public static void executeLauncherAndVerifyOutput(JPackageCommand cmd, String... args) { - AppOutputVerifier av = assertMainLauncher(cmd, args); - if (av != null) { + assertMainLauncher(cmd, args).ifPresent(av -> { av.executeAndVerifyOutput(args); - } + }); } public static Executor.Result executeLauncher(JPackageCommand cmd, String... args) { - AppOutputVerifier av = assertMainLauncher(cmd, args); - if (av != null) { + return assertMainLauncher(cmd, args).map(av -> { return av.saveOutput(true).execute(args); - } else { - return null; - } + }).orElseThrow(); } - public static AppOutputVerifier assertMainLauncher(JPackageCommand cmd, + public static Optional assertMainLauncher(JPackageCommand cmd, String... args) { final Path launcherPath = cmd.appLauncherPath(); if (!cmd.canRunLauncher(String.format("Not running [%s] launcher", launcherPath))) { - return null; + return Optional.empty(); } - return assertApp(launcherPath) + return Optional.of(assertApp(launcherPath) .addDefaultArguments(Optional .ofNullable(cmd.getAllArgumentValues("--arguments")) .orElseGet(() -> new String[0])) .addJavaOptions(Optional .ofNullable(cmd.getAllArgumentValues("--java-options")) - .orElseGet(() -> new String[0])); + .orElseGet(() -> new String[0]))); } @@ -426,6 +423,11 @@ public final class HelloApp { .collect(Collectors.toList())); } + public AppOutputVerifier processListener(Consumer v) { + processListener = v; + return this; + } + public void verifyOutput(String... args) { final List launcherArgs = List.of(args); final List appArgs; @@ -479,6 +481,7 @@ public final class HelloApp { .saveOutput(saveOutput) .dumpOutput() .setExecutable(executablePath) + .processListener(processListener) .addArguments(List.of(args)); env.forEach((envVarName, envVarValue) -> { @@ -493,6 +496,7 @@ public final class HelloApp { private final Path launcherPath; private Path outputFilePath; private int expectedExitCode; + private Consumer processListener; private final List defaultLauncherArgs; private final Map params; private final Map env; 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 c5c4f87b097..f81c35cea0b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -52,8 +52,6 @@ import java.util.Optional; import java.util.OptionalInt; import java.util.Set; import java.util.TreeSet; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -63,6 +61,7 @@ import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.jpackage.internal.util.function.ExceptionBox; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.util.function.ThrowingRunnable; @@ -77,20 +76,23 @@ public class JPackageCommand extends CommandArguments { @SuppressWarnings("this-escape") public JPackageCommand() { + toolProviderSource = new ToolProviderSource(); prerequisiteActions = new Actions(); verifyActions = new Actions(); excludeStandardAsserts(StandardAssert.MAIN_LAUNCHER_DESCRIPTION); + removeOldOutputBundle = true; } private JPackageCommand(JPackageCommand cmd, boolean immutable) { args.addAll(cmd.args); - withToolProvider = cmd.withToolProvider; + toolProviderSource = cmd.toolProviderSource.copy(); saveConsoleOutput = cmd.saveConsoleOutput; discardStdout = cmd.discardStdout; discardStderr = cmd.discardStderr; suppressOutput = cmd.suppressOutput; ignoreDefaultRuntime = cmd.ignoreDefaultRuntime; ignoreDefaultVerbose = cmd.ignoreDefaultVerbose; + removeOldOutputBundle = cmd.removeOldOutputBundle; this.immutable = immutable; prerequisiteActions = new Actions(cmd.prerequisiteActions); verifyActions = new Actions(cmd.verifyActions); @@ -292,34 +294,8 @@ public class JPackageCommand extends CommandArguments { public JPackageCommand setFakeRuntime() { verifyMutable(); - - ThrowingConsumer createBulkFile = path -> { - Files.createDirectories(path.getParent()); - try (FileOutputStream out = new FileOutputStream(path.toFile())) { - byte[] bytes = new byte[4 * 1024]; - new SecureRandom().nextBytes(bytes); - out.write(bytes); - } - }; - addPrerequisiteAction(cmd -> { - Path fakeRuntimeDir = TKit.createTempDirectory("fake_runtime"); - - TKit.trace(String.format("Init fake runtime in [%s] directory", - fakeRuntimeDir)); - - if (TKit.isOSX()) { - // Make MacAppImageBuilder happy - createBulkFile.accept(fakeRuntimeDir.resolve(Path.of( - "lib/jli/libjli.dylib"))); - } - - // Make sure fake runtime takes some disk space. - // Package bundles with 0KB size are unexpected and considered - // an error by PackageTest. - createBulkFile.accept(fakeRuntimeDir.resolve(Path.of("lib", "bulk"))); - - cmd.setArgumentValue("--runtime-image", fakeRuntimeDir); + cmd.setArgumentValue("--runtime-image", createInputRuntimeImage(RuntimeImageType.RUNTIME_TYPE_FAKE)); }); return this; @@ -388,24 +364,77 @@ public class JPackageCommand extends CommandArguments { return cmd; } + public enum RuntimeImageType { + + /** + * Runtime suitable for running the default "Hello" test app. + */ + RUNTIME_TYPE_HELLO_APP, + + /** + * Fake runtime. + */ + RUNTIME_TYPE_FAKE, + + ; + } + public static Path createInputRuntimeImage() { + return createInputRuntimeImage(RuntimeImageType.RUNTIME_TYPE_HELLO_APP); + } + + public static Path createInputRuntimeImage(RuntimeImageType role) { + Objects.requireNonNull(role); final Path runtimeImageDir; + switch (role) { - if (JPackageCommand.DEFAULT_RUNTIME_IMAGE != null) { - runtimeImageDir = JPackageCommand.DEFAULT_RUNTIME_IMAGE; - } else { - runtimeImageDir = TKit.createTempDirectory("runtime-image").resolve("data"); + case RUNTIME_TYPE_FAKE -> { + Consumer createBulkFile = ThrowingConsumer.toConsumer(path -> { + Files.createDirectories(path.getParent()); + try (FileOutputStream out = new FileOutputStream(path.toFile())) { + byte[] bytes = new byte[4 * 1024]; + new SecureRandom().nextBytes(bytes); + out.write(bytes); + } + }); - new Executor().setToolProvider(JavaTool.JLINK) - .dumpOutput() - .addArguments( - "--output", runtimeImageDir.toString(), - "--add-modules", "java.desktop", - "--strip-debug", - "--no-header-files", - "--no-man-pages") - .execute(); + runtimeImageDir = TKit.createTempDirectory("fake_runtime"); + + TKit.trace(String.format("Init fake runtime in [%s] directory", runtimeImageDir)); + + if (TKit.isOSX()) { + // Make MacAppImageBuilder happy + createBulkFile.accept(runtimeImageDir.resolve(Path.of("lib/jli/libjli.dylib"))); + } + + // Make sure fake runtime takes some disk space. + // Package bundles with 0KB size are unexpected and considered + // an error by PackageTest. + createBulkFile.accept(runtimeImageDir.resolve(Path.of("lib", "bulk"))); + } + + case RUNTIME_TYPE_HELLO_APP -> { + if (JPackageCommand.DEFAULT_RUNTIME_IMAGE != null && !isFakeRuntime(DEFAULT_RUNTIME_IMAGE)) { + runtimeImageDir = JPackageCommand.DEFAULT_RUNTIME_IMAGE; + } else { + runtimeImageDir = TKit.createTempDirectory("runtime-image").resolve("data"); + + new Executor().setToolProvider(JavaTool.JLINK) + .dumpOutput() + .addArguments( + "--output", runtimeImageDir.toString(), + "--add-modules", "java.desktop", + "--strip-debug", + "--no-header-files", + "--no-man-pages") + .execute(); + } + } + + default -> { + throw ExceptionBox.reachedUnreachable(); + } } return runtimeImageDir; @@ -770,7 +799,7 @@ public class JPackageCommand extends CommandArguments { } public static void useToolProviderByDefault(ToolProvider jpackageToolProvider) { - defaultToolProvider.set(Optional.of(jpackageToolProvider)); + TKit.state().setProperty(DefaultToolProviderKey.VALUE, Objects.requireNonNull(jpackageToolProvider)); } public static void useToolProviderByDefault() { @@ -778,45 +807,22 @@ public class JPackageCommand extends CommandArguments { } public static void useExecutableByDefault() { - defaultToolProvider.set(Optional.empty()); - } - - /** - * In a separate thread calls {@link #useToolProviderByDefault(ToolProvider)} - * with the specified {@code jpackageToolProvider} and then calls - * {@code workload.run()}. Joins the thread. - *

- * The idea is to run the {@code workload} in the context of the specified - * jpackage {@code ToolProvider} without altering the global variable holding - * the default jpackage {@code ToolProvider}. The global variable is - * thread-local; setting its value in a new thread doesn't alter its copy in the - * calling thread. - * - * @param jpackageToolProvider jpackage {@code ToolProvider} - * @param workload the workload to run - */ - public static void withToolProvider(Runnable workload, ToolProvider jpackageToolProvider) { - Objects.requireNonNull(workload); - Objects.requireNonNull(jpackageToolProvider); - - CompletableFuture.runAsync(() -> { - var oldValue = defaultToolProvider.get(); - useToolProviderByDefault(jpackageToolProvider); - try { - workload.run(); - } finally { - defaultToolProvider.set(oldValue); - } - // Run the future in a new native thread. Don't run it in a virtual/pooled thread. - // Pooled and/or virtual threads are problematic when used with inheritable thread-local variables. - // TKit class depends on such a variable, which results in intermittent test failures - // if the default executor runs this future. - }, Executors.newThreadPerTaskExecutor(Thread.ofPlatform().factory())).join(); + TKit.state().setProperty(DefaultToolProviderKey.VALUE, null); } public JPackageCommand useToolProvider(boolean v) { verifyMutable(); - withToolProvider = v; + if (v) { + toolProviderSource.useDefaultToolProvider(); + } else { + toolProviderSource.useProcess(); + } + return this; + } + + public JPackageCommand useToolProvider(ToolProvider v) { + verifyMutable(); + toolProviderSource.useToolProvider(v); return this; } @@ -867,6 +873,28 @@ public class JPackageCommand extends CommandArguments { return this; } + /** + * Configures this instance to optionally remove the existing output bundle + * before running the jpackage command. + * + * @param v {@code true} to remove existing output bundle before running the + * jpackage command, and {@code false} otherwise + * @return this + */ + public JPackageCommand removeOldOutputBundle(boolean v) { + verifyMutable(); + removeOldOutputBundle = v; + return this; + } + + /** + * Returns {@code true} if this instance will remove existing output bundle + * before running the jpackage command, and {@code false} otherwise. + */ + public boolean isRemoveOldOutputBundle() { + return removeOldOutputBundle; + } + public JPackageCommand validateOutput(TKit.TextStreamVerifier validator) { return validateOutput(validator::apply); } @@ -928,9 +956,7 @@ public class JPackageCommand extends CommandArguments { } public boolean isWithToolProvider() { - return Optional.ofNullable(withToolProvider).orElseGet(() -> { - return defaultToolProvider.get().isPresent(); - }); + return toolProviderSource.toolProvider().isPresent(); } public JPackageCommand executePrerequisiteActions() { @@ -938,21 +964,19 @@ public class JPackageCommand extends CommandArguments { return this; } - private Executor createExecutor() { + Executor createExecutor() { Executor exec = new Executor() .saveOutput(saveConsoleOutput).dumpOutput(!suppressOutput) .discardStdout(discardStdout).discardStderr(discardStderr) .setDirectory(executeInDirectory) .addArguments(args); - if (isWithToolProvider()) { - exec.setToolProvider(defaultToolProvider.get().orElseGet(JavaTool.JPACKAGE::asToolProvider)); - } else { - exec.setExecutable(JavaTool.JPACKAGE); - if (TKit.isWindows()) { - exec.setWindowsTmpDir(System.getProperty("java.io.tmpdir")); - } - } + toolProviderSource.toolProvider().ifPresentOrElse(exec::setToolProvider, () -> { + exec.setExecutable(JavaTool.JPACKAGE); + if (TKit.isWindows()) { + exec.setWindowsTmpDir(System.getProperty("java.io.tmpdir")); + } + }); return exec; } @@ -973,21 +997,18 @@ public class JPackageCommand extends CommandArguments { verifyMutable(); executePrerequisiteActions(); - if (hasArgument("--dest")) { - nullableOutputBundle().ifPresent(path -> { - ThrowingRunnable.toRunnable(() -> { - if (Files.isDirectory(path)) { - TKit.deleteDirectoryRecursive(path, String.format( - "Delete [%s] folder before running jpackage", - path)); - } else if (TKit.deleteIfExists(path)) { - TKit.trace(String.format( - "Deleted [%s] file before running jpackage", - path)); - } - }).run(); - }); - } + nullableOutputBundle().filter(_ -> { + return !(TKit.isOSX() && MacHelper.signPredefinedAppImage(this)) && removeOldOutputBundle; + }).ifPresent(path -> { + ThrowingRunnable.toRunnable(() -> { + if (Files.isDirectory(path)) { + TKit.deleteDirectoryRecursive(path, + String.format("Delete [%s] folder before running jpackage", path)); + } else if (TKit.deleteIfExists(path)) { + TKit.trace(String.format("Deleted [%s] file before running jpackage", path)); + } + }).run(); + }); Path resourceDir = getArgumentValue("--resource-dir", () -> null, Path::of); if (resourceDir != null && Files.isDirectory(resourceDir)) { @@ -1117,7 +1138,7 @@ public class JPackageCommand extends CommandArguments { private final Map> snapshots; } - public static enum ReadOnlyPathAssert{ + public static enum ReadOnlyPathAssert { APP_IMAGE(new Builder("--app-image").enable(cmd -> { // External app image should be R/O unless it is an app image signing on macOS. return !(TKit.isOSX() && MacHelper.signPredefinedAppImage(cmd)); @@ -1385,7 +1406,7 @@ public class JPackageCommand extends CommandArguments { if (!isImagePackageType() && hasArgument("--app-image")) { // Build native macOS package from an external app image. // If the external app image is signed, ".jpackage.xml" file should be kept, otherwise removed. - return AppImageFile.load(Path.of(getArgumentValue("--app-image"))).macSigned(); + return MacHelper.isBundleSigned(Path.of(getArgumentValue("--app-image"))); } } @@ -1406,13 +1427,8 @@ public class JPackageCommand extends CommandArguments { final AppImageFile aif = AppImageFile.load(rootDir); if (TKit.isOSX()) { - boolean expectedValue = MacHelper.appImageSigned(this); - boolean actualValue = aif.macSigned(); - TKit.assertEquals(expectedValue, actualValue, - "Check for unexpected value of property in app image file"); - - expectedValue = hasArgument("--mac-app-store"); - actualValue = aif.macAppStore(); + var expectedValue = hasArgument("--mac-app-store"); + var actualValue = aif.macAppStore(); TKit.assertEquals(expectedValue, actualValue, "Check for unexpected value of property in app image file"); } @@ -1437,7 +1453,7 @@ public class JPackageCommand extends CommandArguments { } else { if (TKit.isOSX() && hasArgument("--app-image")) { String appImage = getArgumentValue("--app-image"); - if (AppImageFile.load(Path.of(appImage)).macSigned()) { + if (MacHelper.isBundleSigned(Path.of(appImage))) { assertFileNotInAppImage(lookupPath); } else { assertFileInAppImage(lookupPath); @@ -1736,13 +1752,77 @@ public class JPackageCommand extends CommandArguments { private final List actions; } - private Boolean withToolProvider; + private static final class ToolProviderSource { + + ToolProviderSource copy() { + return new ToolProviderSource(this); + } + + void useDefaultToolProvider() { + customToolProvider = null; + mode = Mode.USE_TOOL_PROVIDER; + } + + void useToolProvider(ToolProvider tp) { + customToolProvider = Objects.requireNonNull(tp); + mode = Mode.USE_TOOL_PROVIDER; + } + + void useProcess() { + customToolProvider = null; + mode = Mode.USE_PROCESS; + } + + Optional toolProvider() { + switch (mode) { + case USE_PROCESS -> { + return Optional.empty(); + } + case USE_TOOL_PROVIDER -> { + if (customToolProvider != null) { + return Optional.of(customToolProvider); + } else { + return TKit.state().findProperty(DefaultToolProviderKey.VALUE).map(ToolProvider.class::cast).or(() -> { + return Optional.of(JavaTool.JPACKAGE.asToolProvider()); + }); + } + } + case INHERIT_DEFAULTS -> { + return TKit.state().findProperty(DefaultToolProviderKey.VALUE).map(ToolProvider.class::cast); + } + default -> { + throw ExceptionBox.reachedUnreachable(); + } + } + } + + ToolProviderSource() { + mode = Mode.INHERIT_DEFAULTS; + } + + private ToolProviderSource(ToolProviderSource other) { + this.customToolProvider = other.customToolProvider; + this.mode = other.mode; + } + + private enum Mode { + INHERIT_DEFAULTS, + USE_PROCESS, + USE_TOOL_PROVIDER + } + + private ToolProvider customToolProvider; + private Mode mode; + } + + private final ToolProviderSource toolProviderSource; private boolean saveConsoleOutput; private boolean discardStdout; private boolean discardStderr; private boolean suppressOutput; private boolean ignoreDefaultRuntime; private boolean ignoreDefaultVerbose; + private boolean removeOldOutputBundle; private boolean immutable; private final Actions prerequisiteActions; private final Actions verifyActions; @@ -1752,12 +1832,10 @@ public class JPackageCommand extends CommandArguments { private Set readOnlyPathAsserts = Set.of(ReadOnlyPathAssert.values()); private Set standardAsserts = Set.of(StandardAssert.values()); private List>> outputValidators = new ArrayList<>(); - private static InheritableThreadLocal> defaultToolProvider = new InheritableThreadLocal<>() { - @Override - protected Optional initialValue() { - return Optional.empty(); - } - }; + + private enum DefaultToolProviderKey { + VALUE + } private static final Map PACKAGE_TYPES = Stream.of(PackageType.values()).collect(toMap(PackageType::getType, x -> x)); 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 6a5be77457a..dc1a7b3512b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -33,6 +33,7 @@ import static jdk.jpackage.internal.util.PListWriter.writeStringArray; import static jdk.jpackage.internal.util.PListWriter.writeStringOptional; import static jdk.jpackage.internal.util.XmlUtils.initDocumentBuilder; import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; import java.io.ByteArrayInputStream; @@ -45,6 +46,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; +import java.security.cert.X509Certificate; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -59,14 +62,14 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; -import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.util.Enquoter; import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.RetryExecutor; @@ -74,6 +77,8 @@ import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingSupplier; import jdk.jpackage.test.MacSign.CertificateRequest; +import jdk.jpackage.test.MacSign.CertificateType; +import jdk.jpackage.test.MacSign.ResolvedKeychain; import jdk.jpackage.test.PackageTest.PackageHandlers; import jdk.jpackage.test.RunnablePackageTest.Action; import org.xml.sax.SAXException; @@ -89,8 +94,8 @@ public final class MacHelper { // See JDK-8373105. "hdiutil" does not handle such cases very good. final var mountRoot = TKit.createTempDirectory("mountRoot"); - // Explode DMG assuming this can require interaction, thus use `yes`. - final var attachStdout = Executor.of("sh", "-c", String.join(" ", + // Explode the DMG assuming this can require interaction if the DMG has a license, thus use `yes`. + final var attachExec = Executor.of("sh", "-c", String.join(" ", "yes", "|", "/usr/bin/hdiutil", @@ -99,14 +104,34 @@ public final class MacHelper { "-mountroot", PathUtils.normalizedAbsolutePathString(mountRoot), "-nobrowse", "-plist" - )).saveOutput().storeOutputInFiles().executeAndRepeatUntilExitCode(0, 10, 6).stdout(); + )).saveOutput().storeOutputInFiles().binaryOutput(); + + final var attachResult = attachExec.executeAndRepeatUntilExitCode(0, 10, 6); final Path mountPoint; boolean mountPointInitialized = false; try { + byte[] stdout = attachResult.byteStdout(); + + // If the DMG has a license, it will be printed to the stdout before the plist content. + // All bytes before the XML declaration of the plist must be skipped. + // We need to find the location of the {'<', '?', 'x', 'm', 'l'} byte array + // (the XML declaration) in the captured binary stdout. + // Instead of crafting an ad-hoc function that operates on byte arrays, + // we will convert the byte array into a String instance using + // an 8-bit character set (ISO-8859-1) and use the standard String#indexOf(). + var startPlistIndex = new String(stdout, StandardCharsets.ISO_8859_1).indexOf(" 0) { + plistXml = Arrays.copyOfRange(stdout, startPlistIndex, stdout.length); + } else { + plistXml = stdout; + } + // One of "dict" items of "system-entities" array property should contain "mount-point" string property. - mountPoint = readPList(attachStdout).queryArrayValue("system-entities", false) + mountPoint = readPList(plistXml).queryArrayValue("system-entities", false) .map(PListReader.class::cast) .map(dict -> { return dict.findValue("mount-point"); @@ -117,7 +142,7 @@ public final class MacHelper { } finally { if (!mountPointInitialized) { TKit.trace("Unexpected plist file missing `system-entities` array:"); - attachStdout.forEach(TKit::trace); + attachResult.toCharacterResult(attachExec.charset(), false).stdout().forEach(TKit::trace); TKit.trace("Done"); } } @@ -168,19 +193,13 @@ public final class MacHelper { public static PListReader readPList(Path path) { TKit.assertReadableFileExists(path); - return ThrowingSupplier.toSupplier(() -> readPList(Files.readAllLines( - path))).get(); + return readPList(toFunction(Files::readAllBytes).apply(path)); } - public static PListReader readPList(List lines) { - return readPList(lines.stream()); - } - - public static PListReader readPList(Stream lines) { - return ThrowingSupplier.toSupplier(() -> new PListReader(lines - // Skip leading lines before xml declaration - .dropWhile(Pattern.compile("\\s?<\\?xml\\b.+\\?>").asPredicate().negate()) - .collect(Collectors.joining()).getBytes(StandardCharsets.UTF_8))).get(); + public static PListReader readPList(byte[] xml) { + return ThrowingSupplier.toSupplier(() -> { + return new PListReader(xml); + }).get(); } public static Map flatMapPList(PListReader plistReader) { @@ -265,13 +284,13 @@ public final class MacHelper { throw new UnsupportedOperationException(); } - var runtimeImage = Optional.ofNullable(cmd.getArgumentValue("--runtime-image")).map(Path::of); + var runtimeImageBundle = Optional.ofNullable(cmd.getArgumentValue("--runtime-image")).map(Path::of).flatMap(MacBundle::fromPath); var appImage = Optional.ofNullable(cmd.getArgumentValue("--app-image")).map(Path::of); - if (cmd.isRuntime() && Files.isDirectory(runtimeImage.orElseThrow().resolve("Contents/_CodeSignature"))) { + if (cmd.isRuntime() && runtimeImageBundle.map(MacHelper::isBundleSigned).orElse(false)) { // If the predefined runtime is a signed bundle, bundled image should be signed too. return true; - } else if (appImage.map(AppImageFile::load).map(AppImageFile::macSigned).orElse(false)) { + } else if (appImage.map(MacHelper::isBundleSigned).orElse(false)) { // The external app image is signed, so the app image is signed too. return true; } @@ -301,6 +320,14 @@ public final class MacHelper { }).run(); } + static boolean isBundleSigned(Path bundleRoot) { + return isBundleSigned(MacBundle.fromPath(bundleRoot).orElseThrow(IllegalArgumentException::new)); + } + + static boolean isBundleSigned(MacBundle bundle) { + return MacSignVerify.findSpctlSignOrigin(MacSignVerify.SpctlType.EXEC, bundle.root(), true).isPresent(); + } + private static void createFaPListFragmentFromFaProperties(JPackageCommand cmd, XMLStreamWriter xml) throws XMLStreamException, IOException { @@ -383,7 +410,7 @@ public final class MacHelper { var predefinedAppImage = Path.of(Optional.ofNullable(cmd.getArgumentValue("--app-image")).orElseThrow(IllegalArgumentException::new)); - var plistPath = ApplicationLayout.macAppImage().resolveAt(predefinedAppImage).contentDirectory().resolve("Info.plist"); + var plistPath = MacBundle.fromPath(predefinedAppImage).orElseThrow().infoPlistFile(); try (var plistStream = Files.newInputStream(plistPath)) { var plist = new PListReader(initDocumentBuilder().parse(plistStream)); @@ -407,18 +434,50 @@ public final class MacHelper { } } + public static final class RuntimeBundleBuilder { + + public Path create() { + return createRuntimeBundle(type, Optional.ofNullable(mutator)); + } + + public RuntimeBundleBuilder type(JPackageCommand.RuntimeImageType v) { + type = Objects.requireNonNull(v); + return this; + } + + public RuntimeBundleBuilder mutator(Consumer v) { + mutator = v; + return this; + } + + public RuntimeBundleBuilder mutate(Consumer mutator) { + mutator.accept(this); + return this; + } + + private RuntimeBundleBuilder() { + } + + private JPackageCommand.RuntimeImageType type = JPackageCommand.RuntimeImageType.RUNTIME_TYPE_HELLO_APP; + private Consumer mutator; + }; + + public static RuntimeBundleBuilder buildRuntimeBundle() { + return new RuntimeBundleBuilder(); + } + public static Path createRuntimeBundle(Consumer mutator) { - return createRuntimeBundle(Optional.of(mutator)); + return buildRuntimeBundle().mutator(Objects.requireNonNull(mutator)).create(); } public static Path createRuntimeBundle() { - return createRuntimeBundle(Optional.empty()); + return buildRuntimeBundle().create(); } - public static Path createRuntimeBundle(Optional> mutator) { + private static Path createRuntimeBundle(JPackageCommand.RuntimeImageType type, Optional> mutator) { Objects.requireNonNull(mutator); - final var runtimeImage = JPackageCommand.createInputRuntimeImage(); + final var runtimeImage = JPackageCommand.createInputRuntimeImage(type); final var runtimeBundleWorkDir = TKit.createTempDirectory("runtime-bundle"); @@ -472,25 +531,244 @@ public final class MacHelper { return cmd; } - public record SignKeyOption(Type type, CertificateRequest certRequest) { + public static final class ResolvableCertificateRequest { + + public ResolvableCertificateRequest( + CertificateRequest certRequest, + Function certResolver, + String label) { + + Objects.requireNonNull(certRequest); + Objects.requireNonNull(certResolver); + Objects.requireNonNull(label); + if (label.isBlank()) { + throw new IllegalArgumentException(); + } + + this.certRequest = certRequest; + this.certResolver = certResolver; + this.label = label; + } + + public ResolvableCertificateRequest( + CertificateRequest certRequest, + ResolvedKeychain keychain, + String label) { + this(certRequest, keychain.asCertificateResolver(), label); + } + + @Override + public String toString() { + return label; + } + + public CertificateRequest certRequest() { + return certRequest; + } + + public X509Certificate cert() { + return certResolver.apply(certRequest); + } + + public CertificateType type() { + return certRequest.type(); + } + + public String name() { + return certRequest.name(); + } + + public String shortName() { + return certRequest.shortName(); + } + + public int days() { + return certRequest.days(); + } + + public boolean expired() { + return certRequest.expired(); + } + + public boolean trusted() { + return certRequest.trusted(); + } + + private final CertificateRequest certRequest; + private final Function certResolver; + private final String label; + } + + public interface NamedCertificateRequestSupplier { + + String name(); + + CertificateRequest certRequest(); + + default ResolvableCertificateRequest certRequest(ResolvedKeychain keychain) { + Objects.requireNonNull(keychain); + var certRequest = Objects.requireNonNull(certRequest()); + if (keychain.spec().certificateRequests().contains(certRequest)) { + return new ResolvableCertificateRequest(certRequest, keychain.asCertificateResolver(), name()); + } else { + throw new IllegalArgumentException(String.format( + "Certificate request %s not found in [%s] keychain", + name(), keychain.spec().keychain().name())); + } + } + } + + public record SignKeyOption(Type type, ResolvableCertificateRequest certRequest, Optional customOptionValue) { public SignKeyOption { Objects.requireNonNull(type); Objects.requireNonNull(certRequest); + Objects.requireNonNull(customOptionValue); + if (customOptionValue.isEmpty() == (type == Type.SIGN_KEY_USER_NAME)) { + throw new IllegalArgumentException(); + } + } + + public SignKeyOption(Type type, ResolvableCertificateRequest certRequest) { + this(type, certRequest, Optional.empty()); + } + + public SignKeyOption( + Type type, + NamedCertificateRequestSupplier certRequestSupplier, + ResolvedKeychain keychain) { + + this(type, certRequestSupplier.certRequest(keychain)); + } + + public SignKeyOption(String optionValue, ResolvableCertificateRequest certRequest) { + this(Type.SIGN_KEY_USER_NAME, certRequest, Optional.of(optionValue)); + } + + public SignKeyOption( + String optionValue, + NamedCertificateRequestSupplier certRequestSupplier, + ResolvedKeychain keychain) { + + this(optionValue, certRequestSupplier.certRequest(keychain)); + } + + public enum Name { + KEY_USER_NAME("--mac-signing-key-user-name"), + KEY_IDENTITY_APP_IMAGE("--mac-app-image-sign-identity"), + KEY_IDENTITY_INSTALLER("--mac-installer-sign-identity"), + ; + + Name(String optionName) { + this.optionName = Objects.requireNonNull(optionName); + } + + public String optionName() { + return optionName; + } + + public boolean passThrough() { + return this != KEY_USER_NAME; + } + + private final String optionName; } public enum Type { - SIGN_KEY_USER_NAME, - SIGN_KEY_IDENTITY, + /** + * "--mac-signing-key-user-name" option with custom value + */ + SIGN_KEY_USER_NAME(Name.KEY_USER_NAME), + + /** + * "--mac-signing-key-user-name" option with the short user name, e.g.: + * {@code --mac-signing-key-user-name foo} + */ + SIGN_KEY_USER_SHORT_NAME(Name.KEY_USER_NAME), + + /** + * "--mac-signing-key-user-name" option with the full user name (aka signing + * identity name), e.g.: + * {@code --mac-signing-key-user-name 'Developer ID Application: foo'} + */ + SIGN_KEY_USER_FULL_NAME(Name.KEY_USER_NAME), + + /** + * "--mac-installer-sign-identity" or "--mac-app-image-sign-identity" option + * with the signing identity name, e.g.: + * {@code --mac-app-image-sign-identity 'Developer ID Application: foo'} + */ + SIGN_KEY_IDENTITY(Map.of( + MacSign.CertificateType.CODE_SIGN, Name.KEY_IDENTITY_APP_IMAGE, + MacSign.CertificateType.INSTALLER, Name.KEY_IDENTITY_INSTALLER)), + + /** + * "--mac-app-image-sign-identity" regardless of the type of signing identity + * (for signing app image or .pkg installer). + */ + SIGN_KEY_IDENTITY_APP_IMAGE(Name.KEY_IDENTITY_APP_IMAGE), + + /** + * "--mac-installer-sign-identity" regardless of the type of signing identity + * (for signing app image or .pkg installer). + */ + SIGN_KEY_IDENTITY_INSTALLER(Name.KEY_IDENTITY_INSTALLER), + ; + + Type(Map optionNameMap) { + Objects.requireNonNull(optionNameMap); + this.optionNameMapper = certType -> { + return Optional.of(optionNameMap.get(certType)); + }; + } + + Type(Name optionName) { + Objects.requireNonNull(optionName); + this.optionNameMapper = _ -> Optional.of(optionName); + } + + Type() { + this.optionNameMapper = _ -> Optional.empty(); + } + + public Optional mapOptionName(MacSign.CertificateType certType) { + return optionNameMapper.apply(Objects.requireNonNull(certType)); + } + + public static Type[] defaultValues() { + return new Type[] { + SIGN_KEY_USER_SHORT_NAME, + SIGN_KEY_USER_FULL_NAME, + SIGN_KEY_IDENTITY + }; + } + + private final Function> optionNameMapper; } @Override public String toString() { var sb = new StringBuilder(); + sb.append('{'); applyTo((optionName, _) -> { - sb.append(String.format("{%s: %s}", optionName, certRequest)); + sb.append(optionName); + switch (type) { + case SIGN_KEY_USER_FULL_NAME -> { + sb.append("/full"); + } + case SIGN_KEY_USER_NAME -> { + customOptionValue.ifPresent(optionValue -> { + sb.append("=").append(ENQUOTER.applyTo(optionValue)); + }); + } + default -> { + // NOP + } + } + sb.append(": "); }); + sb.append(certRequest).append('}'); return sb.toString(); } @@ -504,35 +782,127 @@ public final class MacHelper { return sign(cmd); } - private void applyTo(BiConsumer sink) { - switch (certRequest.type()) { - case INSTALLER -> { - switch (type) { - case SIGN_KEY_IDENTITY -> { - sink.accept("--mac-installer-sign-identity", certRequest.name()); - return; - } - case SIGN_KEY_USER_NAME -> { - sink.accept("--mac-signing-key-user-name", certRequest.shortName()); - return; - } - } - } - case CODE_SIGN -> { - switch (type) { - case SIGN_KEY_IDENTITY -> { - sink.accept("--mac-app-image-sign-identity", certRequest.name()); - return; - } - case SIGN_KEY_USER_NAME -> { - sink.accept("--mac-signing-key-user-name", certRequest.shortName()); - return; - } - } - } - } + public List asCmdlineArgs() { + String[] args = new String[2]; + applyTo((optionName, optionValue) -> { + args[0] = optionName; + args[1] = optionValue; + }); + return List.of(args); + } - throw new AssertionError(); + private void applyTo(BiConsumer sink) { + type.mapOptionName(certRequest.type()).ifPresent(optionName -> { + sink.accept(optionName.optionName(), optionValue()); + }); + } + + private String optionValue() { + return customOptionValue.orElseGet(() -> { + switch (type) { + case SIGN_KEY_IDENTITY, + SIGN_KEY_USER_FULL_NAME, + SIGN_KEY_IDENTITY_APP_IMAGE, + SIGN_KEY_IDENTITY_INSTALLER -> { + return certRequest.name(); + } + case SIGN_KEY_USER_SHORT_NAME -> { + return certRequest.shortName(); + } + default -> { + throw new IllegalStateException(); + } + } + }); + } + + private static final Enquoter ENQUOTER = Enquoter.identity() + .setEnquotePredicate(Enquoter.QUOTE_IF_WHITESPACES).setQuoteChar('\''); + } + + public record SignKeyOptionWithKeychain(SignKeyOption signKeyOption, ResolvedKeychain keychain) { + + public SignKeyOptionWithKeychain { + Objects.requireNonNull(signKeyOption); + Objects.requireNonNull(keychain); + } + + public SignKeyOptionWithKeychain( + SignKeyOption.Type type, + ResolvableCertificateRequest certRequest, + ResolvedKeychain keychain) { + + this(new SignKeyOption(type, certRequest), keychain); + } + + public SignKeyOptionWithKeychain( + SignKeyOption.Type type, + NamedCertificateRequestSupplier certRequestSupplier, + ResolvedKeychain keychain) { + + this(type, certRequestSupplier.certRequest(keychain), keychain); + } + + public SignKeyOptionWithKeychain( + String optionValue, + ResolvableCertificateRequest certRequest, + ResolvedKeychain keychain) { + + this(new SignKeyOption(optionValue, certRequest), keychain); + } + + public SignKeyOptionWithKeychain( + String optionValue, + NamedCertificateRequestSupplier certRequestSupplier, + ResolvedKeychain keychain) { + + this(optionValue, certRequestSupplier.certRequest(keychain), keychain); + } + + public SignKeyOptionWithKeychain( + SignKeyOption.Type type, + CertificateRequest certRequest, + ResolvedKeychain keychain) { + + this(new SignKeyOption( + type, + new ResolvableCertificateRequest( + certRequest, + keychain.asCertificateResolver(), + certRequest.toString())), + keychain); + } + + @Override + public String toString() { + return String.format("%s@%s", signKeyOption, keychain.name()); + } + + public SignKeyOption.Type type() { + return signKeyOption.type(); + } + + public ResolvableCertificateRequest certRequest() { + return signKeyOption.certRequest(); + } + + public JPackageCommand addTo(JPackageCommand cmd) { + Optional.ofNullable(cmd.getArgumentValue("--mac-signing-keychain")).ifPresentOrElse(configuredKeychain -> { + if (!configuredKeychain.equals(keychain.name())) { + throw new IllegalStateException(String.format( + "Command line [%s] already has the '--mac-signing-keychain' option, not adding another one with [%s] value", + cmd, keychain.name())); + } + }, () -> { + useKeychain(cmd, keychain); + }); + return signKeyOption.addTo(cmd); + } + + public JPackageCommand setTo(JPackageCommand cmd) { + cmd.removeArgumentWithValue("--mac-signing-keychain"); + useKeychain(cmd, keychain); + return signKeyOption.setTo(cmd); } } 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 70de6ba92af..3bbbf436300 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java @@ -61,6 +61,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; import javax.naming.ldap.LdapName; @@ -1132,6 +1133,18 @@ public final class MacSign { return certMap; } + public Function asCertificateResolver() { + return certRequest -> { + if (!spec.certificateRequests().contains(certRequest)) { + throw new IllegalArgumentException(String.format( + "Certificate request %s not found in [%s] keychain", + certRequest, name())); + } else { + return Objects.requireNonNull(mapCertificateRequests().get(certRequest)); + } + }; + } + private final KeychainWithCertsSpec spec; private volatile Map certMap; } 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 0ecfd4c3432..ddf899d603c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java @@ -22,7 +22,6 @@ */ package jdk.jpackage.test; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import static jdk.jpackage.test.MacSign.DigestAlgorithm.SHA256; import java.nio.file.Path; @@ -30,12 +29,11 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HexFormat; import java.util.List; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.regex.Pattern; import jdk.jpackage.internal.util.PListReader; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; import jdk.jpackage.test.MacSign.CertificateHash; import jdk.jpackage.test.MacSign.CertificateRequest; @@ -44,12 +42,10 @@ import jdk.jpackage.test.MacSign.CertificateRequest; */ public final class MacSignVerify { - public static void verifyAppImageSigned( - JPackageCommand cmd, CertificateRequest certRequest, MacSign.ResolvedKeychain keychain) { + public static void verifyAppImageSigned(JPackageCommand cmd, ResolvableCertificateRequest certRequest) { - cmd.verifyIsOfType(PackageType.MAC); + cmd.verifyIsOfType(PackageType.MAC_DMG, PackageType.MAC_PKG, PackageType.IMAGE); Objects.requireNonNull(certRequest); - Objects.requireNonNull(keychain); final Path bundleRoot; if (cmd.isImagePackageType()) { @@ -66,20 +62,19 @@ public final class MacSignVerify { }); // Set to "null" if the sign origin is not found, instead of bailing out with an exception. - // Let is fail in the following TKit.assertEquals() call with a proper log message. + // Let it fail in the following TKit.assertEquals() call with a proper log message. var signOrigin = findSpctlSignOrigin(SpctlType.EXEC, bundleRoot).orElse(null); TKit.assertEquals(certRequest.name(), signOrigin, String.format("Check [%s] has sign origin as expected", bundleRoot)); } - public static void verifyPkgSigned(JPackageCommand cmd, CertificateRequest certRequest, MacSign.ResolvedKeychain keychain) { + public static void verifyPkgSigned(JPackageCommand cmd, ResolvableCertificateRequest certRequest) { cmd.verifyIsOfType(PackageType.MAC_PKG); - assertPkgSigned(cmd.outputBundle(), certRequest, - Objects.requireNonNull(keychain.mapCertificateRequests().get(certRequest))); + assertPkgSigned(cmd.outputBundle(), certRequest); } - public static void assertSigned(Path path, CertificateRequest certRequest) { + public static void assertSigned(Path path, ResolvableCertificateRequest certRequest) { assertSigned(path); TKit.assertEquals(certRequest.name(), findCodesignSignOrigin(path).orElse(null), String.format("Check [%s] signed with certificate", path)); @@ -92,10 +87,14 @@ public final class MacSignVerify { } public static Optional findEntitlements(Path path) { - final var exec = Executor.of("/usr/bin/codesign", "-d", "--entitlements", "-", "--xml", path.toString()).saveOutput().dumpOutput(); + final var exec = Executor.of( + "/usr/bin/codesign", + "-d", + "--entitlements", "-", + "--xml", path.toString()).saveOutput().dumpOutput().binaryOutput(); final var result = exec.execute(); - var xml = result.stdout(); - if (xml.isEmpty()) { + var xml = result.byteStdout(); + if (xml.length == 0) { return Optional.empty(); } else { return Optional.of(MacHelper.readPList(xml)); @@ -107,6 +106,10 @@ public final class MacSignVerify { String.format("Check [%s] unsigned", path)); } + public static void assertPkgSigned(Path path, ResolvableCertificateRequest certRequest) { + assertPkgSigned(path, certRequest.certRequest(), certRequest.cert()); + } + public static void assertPkgSigned(Path path, CertificateRequest certRequest, X509Certificate cert) { final var expectedCertChain = List.of(new SignIdentity(certRequest.name(), CertificateHash.of(cert, SHA256))); final var actualCertChain = getPkgCertificateChain(path); @@ -135,17 +138,33 @@ public final class MacSignVerify { public static final String ADHOC_SIGN_ORIGIN = "-"; public static Optional findSpctlSignOrigin(SpctlType type, Path path) { - final var exec = Executor.of("/usr/sbin/spctl", "-vv", "--raw", "--assess", "--type", type.value(), path.toString()).saveOutput().discardStderr(); - final var result = exec.executeWithoutExitCodeCheck(); - TKit.assertTrue(Set.of(0, 3).contains(result.getExitCode()), - String.format("Check exit code of command %s is either 0 or 3", exec.getPrintableCommandLine())); - return toSupplier(() -> { - try { - return Optional.of(new PListReader(String.join("", result.getOutput()).getBytes()).queryValue("assessment:originator")); - } catch (NoSuchElementException ex) { - return Optional.empty(); + return findSpctlSignOrigin(type, path, false); + } + + public static Optional findSpctlSignOrigin(SpctlType type, Path path, boolean acceptBrokenSignature) { + final var exec = Executor.of( + "/usr/sbin/spctl", + "-vv", + "--raw", + "--assess", + "--type", type.value(), + path.toString()).saveOutput().discardStderr().binaryOutput(); + Executor.Result result; + if (acceptBrokenSignature) { + result = exec.executeWithoutExitCodeCheck(); + switch (result.getExitCode()) { + case 0, 3 -> { + // NOP + } + default -> { + // No plist XML to process. + return Optional.empty(); + } } - }).get(); + } else { + result = exec.execute(0, 3); + } + return MacHelper.readPList(result.byteStdout()).findValue("assessment:originator"); } public static Optional findCodesignSignOrigin(Path path) { 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 fee5b65c897..c0bc858eb1e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,24 @@ import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.toMap; import static jdk.jpackage.test.TestBuilder.CMDLINE_ARG_PREFIX; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Comparator; import java.util.Deque; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.internal.util.function.ThrowingRunnable; public final class Main { @@ -47,10 +54,52 @@ public final class Main { } public static void main(TestBuilder.Builder builder, String... args) throws Exception { + Objects.requireNonNull(builder); + + var argList = List.of(args); + + var ignoreLogfile = argList.contains(CMDLINE_ARG_PREFIX + "ignore-logfile"); + + List filteredArgs; + if (ignoreLogfile) { + filteredArgs = argList.stream().filter(Predicate.isEqual(CMDLINE_ARG_PREFIX + "ignore-logfile").negate()).toList(); + } else { + filteredArgs = argList; + } + + ThrowingRunnable workload = () -> { + run(builder, filteredArgs); + }; + + try { + Optional.ofNullable(TKit.getConfigProperty("logfile")).filter(_ -> { + return !ignoreLogfile; + }).map(Path::of).ifPresentOrElse(logfile -> { + + try (var out = new PrintStream( + Files.newOutputStream(logfile, StandardOpenOption.CREATE, StandardOpenOption.APPEND), + true, + System.out.charset())) { + + TKit.withOutput(workload, out, out); + + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + + }, () -> { + ThrowingRunnable.toRunnable(workload).run(); + }); + } catch (Exception ex) { + throw ExceptionBox.unbox(ex); + } + } + + private static void run(TestBuilder.Builder builder, List args) throws Exception { boolean listTests = false; List tests = new ArrayList<>(); try (TestBuilder testBuilder = builder.testConsumer(tests::add).create()) { - Deque argsAsList = new ArrayDeque<>(List.of(args)); + Deque argsAsList = new ArrayDeque<>(args); while (!argsAsList.isEmpty()) { var arg = argsAsList.pop(); TestBuilder.trace(String.format("Parsing [%s]...", arg)); @@ -115,7 +164,7 @@ public final class Main { return; } - TKit.withExtraLogStream(() -> runTests(orderedTests)); + runTests(orderedTests); } private static void runTests(List tests) { 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 2e4f11d056f..2baf6683fdf 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -726,12 +726,30 @@ public final class PackageTest extends RunnablePackageTest { } case CREATE -> { - Executor.Result result = cmd.execute(expectedJPackageExitCode); + var nullableOutputBundle = cmd.nullableOutputBundle(); + + var oldOutputBundleSnapshot = nullableOutputBundle + .filter(Files::exists) + .filter(_ -> { + return !cmd.isRemoveOldOutputBundle(); + }) + .map(TKit.PathSnapshot::new); + + var result = cmd.execute(expectedJPackageExitCode); + if (expectedJPackageExitCode == 0) { TKit.assertFileExists(cmd.outputBundle()); } else { - cmd.nullableOutputBundle().ifPresent(outputBundle -> { - TKit.assertPathExists(outputBundle, false); + nullableOutputBundle.ifPresent(outputBundle -> { + oldOutputBundleSnapshot.ifPresentOrElse(snapshot -> { + // jpackage failed, but the output bundle exists. + // This output bundle existed before the jpackage was invoked. + // Verify jpackage didn't modify it. + new TKit.PathSnapshot(outputBundle).assertEquals(snapshot, String.format( + "Check jpackage didn't modify the old output bundle [%s]", outputBundle)); + }, () -> { + TKit.assertPathExists(outputBundle, false); + }); }); } verifyPackageBundle(cmd, result, expectedJPackageExitCode); 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 47ab838f8d6..1639beadb28 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.nio.file.StandardOpenOption; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; @@ -52,6 +51,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -109,56 +109,45 @@ public final class TKit { throw throwUnknownPlatformError(); }).get(); - static void withExtraLogStream(ThrowingRunnable action) { - if (state().extraLogStream != null) { - ThrowingRunnable.toRunnable(action).run(); - } else { - try (PrintStream logStream = openLogStream()) { - withExtraLogStream(action, logStream); + public static void withOutput(ThrowingRunnable action, PrintStream out, PrintStream err) { + Objects.requireNonNull(action); + Objects.requireNonNull(out); + Objects.requireNonNull(err); + + try { + withState(action, stateBuilder -> { + stateBuilder.out(out).err(err); + }); + } finally { + try { + out.flush(); + } finally { + err.flush(); } } } - static void withExtraLogStream(ThrowingRunnable action, PrintStream logStream) { - withNewState(action, stateBuilder -> { - stateBuilder.extraLogStream(logStream); - }); - } - - public static void withMainLogStream(ThrowingRunnable action, PrintStream logStream) { - withNewState(action, stateBuilder -> { - stateBuilder.mainLogStream(logStream); - }); - } - - public static void withStackTraceStream(ThrowingRunnable action, PrintStream logStream) { - withNewState(action, stateBuilder -> { - stateBuilder.stackTraceStream(logStream); - }); - } - - public static State state() { - return STATE.get(); - } - - public static void state(State v) { - STATE.set(Objects.requireNonNull(v)); - } - - private static void withNewState(ThrowingRunnable action, Consumer stateBuilderMutator) { + public static void withState(ThrowingRunnable action, Consumer stateBuilderMutator) { Objects.requireNonNull(action); Objects.requireNonNull(stateBuilderMutator); - var oldState = state(); - var builder = oldState.buildCopy(); - stateBuilderMutator.accept(builder); - var newState = builder.create(); - try { - state(newState); - ThrowingRunnable.toRunnable(action).run(); - } finally { - state(oldState); - } + var stateBuilder = state().buildCopy(); + stateBuilderMutator.accept(stateBuilder); + withState(action, stateBuilder.create()); + } + + public static void withNewState(ThrowingRunnable action) { + withState(action, _ -> {}); + } + + public static void withState(ThrowingRunnable action, State state) { + Objects.requireNonNull(action); + Objects.requireNonNull(state); + ScopedValue.where(STATE, state).run(ThrowingRunnable.toRunnable(action)); + } + + public static State state() { + return STATE.orElse(DEFAULT_STATE); } enum RunTestMode { @@ -178,33 +167,19 @@ public final class TKit { throw new IllegalStateException("Unexpected nested Test.run() call"); } - withExtraLogStream(() -> { - tests.stream().forEach(test -> { - withNewState(() -> { - try { - if (modes.contains(RunTestMode.FAIL_FAST)) { - test.run(); - } else { - ignoreExceptions(test).run(); - } - } finally { - Optional.ofNullable(state().extraLogStream).ifPresent(PrintStream::flush); - } - }, stateBuilder -> { - stateBuilder.currentTest(test); - }); + tests.stream().forEach(test -> { + withState(() -> { + if (modes.contains(RunTestMode.FAIL_FAST)) { + test.run(); + } else { + ignoreExceptions(test).run(); + } + }, stateBuilder -> { + stateBuilder.currentTest(test); }); }); } - static T runAdhocTest(ThrowingSupplier action) { - final List box = new ArrayList<>(); - runAdhocTest(() -> { - box.add(action.get()); - }); - return box.getFirst(); - } - static void runAdhocTest(ThrowingRunnable action) { Objects.requireNonNull(action); @@ -281,10 +256,7 @@ public final class TKit { static void log(String v) { v = addTimestamp(v); var state = state(); - state.mainLogStream.println(v); - if (state.extraLogStream != null) { - state.extraLogStream.println(v); - } + state.out.println(v); } static Path removeRootFromAbsolutePath(Path v) { @@ -692,8 +664,7 @@ public final class TKit { static void printStackTrace(Throwable throwable) { var state = state(); - Optional.ofNullable(state.extraLogStream).ifPresent(throwable::printStackTrace); - throwable.printStackTrace(state.stackTraceStream); + throwable.printStackTrace(state.err); } private static String concatMessages(String msg, String msg2) { @@ -1255,16 +1226,6 @@ public final class TKit { return new TextStreamVerifier(what); } - private static PrintStream openLogStream() { - return state().logFile.map(logfile -> { - try { - return Files.newOutputStream(logfile, StandardOpenOption.CREATE, StandardOpenOption.APPEND); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - }).map(PrintStream::new).orElse(null); - } - public record PathSnapshot(List contentHashes) { public PathSnapshot { contentHashes.forEach(Objects::requireNonNull); @@ -1376,25 +1337,23 @@ public final class TKit { public static final class State { private State( - Optional logFile, TestInstance currentTest, - PrintStream mainLogStream, - PrintStream stackTraceStream, - PrintStream extraLogStream, + PrintStream out, + PrintStream err, + Map properties, boolean trace, boolean traceAsserts, boolean verboseJPackage, boolean verboseTestSetup) { - Objects.requireNonNull(logFile); - Objects.requireNonNull(mainLogStream); - Objects.requireNonNull(stackTraceStream); + Objects.requireNonNull(out); + Objects.requireNonNull(err); + Objects.requireNonNull(properties); - this.logFile = logFile; this.currentTest = currentTest; - this.mainLogStream = mainLogStream; - this.stackTraceStream = stackTraceStream; - this.extraLogStream = extraLogStream; + this.out = out; + this.err = err; + this.properties = Collections.synchronizedMap(properties); this.trace = trace; this.traceAsserts = traceAsserts; @@ -1403,11 +1362,30 @@ public final class TKit { this.verboseTestSetup = verboseTestSetup; } - Builder buildCopy() { return build().initFrom(this); } + PrintStream out() { + return out; + } + + PrintStream err() { + return err; + } + + Optional findProperty(Object key) { + return Optional.ofNullable(properties.get(Objects.requireNonNull(key))); + } + + void setProperty(Object key, Object value) { + if (value == null) { + properties.remove(Objects.requireNonNull(key)); + } else { + properties.put(Objects.requireNonNull(key), value); + } + } + static Builder build() { return new Builder(); } @@ -1416,11 +1394,9 @@ public final class TKit { static final class Builder { Builder initDefaults() { - logFile = Optional.ofNullable(getConfigProperty("logfile")).map(Path::of); currentTest = null; - mainLogStream = System.out; - stackTraceStream = System.err; - extraLogStream = null; + out = System.out; + err = System.err; var logOptions = tokenizeConfigProperty("suppress-logging"); if (logOptions == null) { @@ -1444,15 +1420,17 @@ public final class TKit { verboseTestSetup = isNonOf.test(Set.of("init", "i")); } + mutable = true; + return this; } Builder initFrom(State state) { - logFile = state.logFile; currentTest = state.currentTest; - mainLogStream = state.mainLogStream; - stackTraceStream = state.stackTraceStream; - extraLogStream = state.extraLogStream; + out = state.out; + err = state.err; + properties.clear(); + properties.putAll(state.properties); trace = state.trace; traceAsserts = state.traceAsserts; @@ -1463,54 +1441,67 @@ public final class TKit { return this; } - Builder logFile(Optional v) { - logFile = v; - return this; - } - Builder currentTest(TestInstance v) { currentTest = v; return this; } - Builder mainLogStream(PrintStream v) { - mainLogStream = v; + Builder out(PrintStream v) { + out = v; return this; } - Builder stackTraceStream(PrintStream v) { - stackTraceStream = v; + Builder err(PrintStream v) { + err = v; return this; } - Builder extraLogStream(PrintStream v) { - extraLogStream = v; + Builder property(Object key, Object value) { + if (value == null) { + properties.remove(Objects.requireNonNull(key)); + } else { + properties.put(Objects.requireNonNull(key), value); + } + return this; + } + + Builder mutable(boolean v) { + mutable = v; return this; } State create() { - return new State(logFile, currentTest, mainLogStream, stackTraceStream, extraLogStream, trace, traceAsserts, verboseJPackage, verboseTestSetup); + return new State( + currentTest, + out, + err, + mutable ? new HashMap<>(properties) : Map.copyOf(properties), + trace, + traceAsserts, + verboseJPackage, + verboseTestSetup); } - private Optional logFile; private TestInstance currentTest; - private PrintStream mainLogStream; - private PrintStream stackTraceStream; - private PrintStream extraLogStream; + private PrintStream out; + private PrintStream err; + private Map properties = new HashMap<>(); private boolean trace; private boolean traceAsserts; private boolean verboseJPackage; private boolean verboseTestSetup; + + private boolean mutable = true; } - private final Optional logFile; private final TestInstance currentTest; - private final PrintStream mainLogStream; - private final PrintStream stackTraceStream; - private final PrintStream extraLogStream; + private final PrintStream out; + private final PrintStream err; + + private final Map properties; private final boolean trace; private final boolean traceAsserts; @@ -1520,10 +1511,6 @@ public final class TKit { } - private static final InheritableThreadLocal STATE = new InheritableThreadLocal<>() { - @Override - protected State initialValue() { - return State.build().initDefaults().create(); - } - }; + private static final ScopedValue STATE = ScopedValue.newInstance(); + private static final State DEFAULT_STATE = State.build().initDefaults().mutable(false).create(); } 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 f9fbf285b49..c7b55ed1de7 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -42,8 +42,6 @@ import java.util.Optional; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Stream; import jdk.jpackage.internal.util.function.ThrowingRunnable; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -306,91 +304,6 @@ public class WindowsHelper { "Failed to get file description of [%s]", pathToExeFile)); } - public static void killProcess(long pid) { - Executor.of("taskkill", "/F", "/PID", Long.toString(pid)).dumpOutput(true).execute(); - } - - public static void killAppLauncherProcess(JPackageCommand cmd, - String launcherName, int expectedCount) { - var pids = findAppLauncherPIDs(cmd, launcherName); - try { - TKit.assertEquals(expectedCount, pids.length, String.format( - "Check [%d] %s app launcher processes found running", - expectedCount, Optional.ofNullable(launcherName).map( - str -> "[" + str + "]").orElse("
"))); - } finally { - if (pids.length != 0) { - killProcess(pids[0]); - } - } - } - - private static long[] findAppLauncherPIDs(JPackageCommand cmd, String launcherName) { - // Get the list of PIDs and PPIDs of app launcher processes. Run setWinRunWithEnglishOutput(true) for JDK-8344275. - // powershell -NoLogo -NoProfile -NonInteractive -Command - // "Get-CimInstance Win32_Process -Filter \"Name = 'foo.exe'\" | select ProcessID,ParentProcessID" - String command = "Get-CimInstance Win32_Process -Filter \\\"Name = '" - + cmd.appLauncherPath(launcherName).getFileName().toString() - + "'\\\" | select ProcessID,ParentProcessID"; - List output = Executor.of("powershell", "-NoLogo", "-NoProfile", "-NonInteractive", "-Command", command) - .dumpOutput(true).saveOutput().setWinRunWithEnglishOutput(true).executeAndGetOutput(); - - if (output.size() < 1) { - return new long[0]; - } - - String[] headers = Stream.of(output.get(1).split("\\s+", 2)).map( - String::trim).map(String::toLowerCase).toArray(String[]::new); - Pattern pattern; - if (headers[0].equals("parentprocessid") && headers[1].equals( - "processid")) { - pattern = Pattern.compile("^\\s+(?\\d+)\\s+(?\\d+)$"); - } else if (headers[1].equals("parentprocessid") && headers[0].equals( - "processid")) { - pattern = Pattern.compile("^\\s+(?\\d+)\\s+(?\\d+)$"); - } else { - throw new RuntimeException( - "Unrecognizable output of \'Get-CimInstance Win32_Process\' command"); - } - - List processes = output.stream().skip(3).map(line -> { - Matcher m = pattern.matcher(line); - long[] pids = null; - if (m.matches()) { - pids = new long[]{Long.parseLong(m.group("pid")), Long. - parseLong(m.group("ppid"))}; - } - return pids; - }).filter(Objects::nonNull).toList(); - - switch (processes.size()) { - case 2 -> { - final long parentPID; - final long childPID; - if (processes.get(0)[0] == processes.get(1)[1]) { - parentPID = processes.get(0)[0]; - childPID = processes.get(1)[0]; - } else if (processes.get(1)[0] == processes.get(0)[1]) { - parentPID = processes.get(1)[0]; - childPID = processes.get(0)[0]; - } else { - TKit.assertUnexpected("App launcher processes unrelated"); - return null; // Unreachable - } - return new long[]{parentPID, childPID}; - } - case 1 -> { - return new long[]{processes.get(0)[0]}; - } - default -> { - TKit.assertUnexpected(String.format( - "Unexpected number of running processes [%d]", - processes.size())); - return null; // Unreachable - } - } - } - static boolean isUserLocalInstall(JPackageCommand cmd) { return cmd.hasArgument("--win-per-user-install"); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java index e89e458c02d..ce3aa6f80e1 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java @@ -115,6 +115,13 @@ public record CommandActionSpecs(List specs) { return printToStderr(List.of(str)); } + public Builder argsListener(Consumer> listener) { + Objects.requireNonNull(listener); + return action(CommandActionSpec.create("args-listener", context -> { + listener.accept(context.args()); + })); + } + public Builder exit(int exitCode) { return action(CommandActionSpec.create(String.format("exit(%d)", exitCode), () -> { return exitCode; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 375c6aa637a..8fdcc96acff 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import static jdk.jpackage.internal.cli.StandardAppImageFileOption.LAUNCHER_AS_S import static jdk.jpackage.internal.cli.StandardAppImageFileOption.LAUNCHER_NAME; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.LINUX_LAUNCHER_SHORTCUT; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_APP_STORE; -import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_SIGNED; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.WIN_LAUNCHER_DESKTOP_SHORTCUT; import static jdk.jpackage.internal.cli.StandardAppImageFileOption.WIN_LAUNCHER_MENU_SHORTCUT; import static jdk.jpackage.internal.cli.StandardOption.APPCLASS; @@ -223,7 +222,7 @@ public class AppImageFileTest { version, null, null, - Optional.empty(), + List.of(), List.of(), null, Optional.empty(), @@ -514,7 +513,6 @@ public class AppImageFileTest { "Foo", "", "property-x", - "true", "False", "", " Quick brown fox", @@ -546,8 +544,7 @@ public class AppImageFileTest { .addExtra(WIN_LAUNCHER_MENU_SHORTCUT, new LauncherShortcut(LauncherShortcutStartupDirectory.APP_DIR)).commit()).create()); testCases.add(builder.os(OperatingSystem.MACOS).expect(appBuilder.get().commit() - .addExtra(MAC_APP_STORE, false) - .addExtra(MAC_SIGNED, true)).create()); + .addExtra(MAC_APP_STORE, false)).create()); return testCases; } @@ -580,7 +577,6 @@ public class AppImageFileTest { "OverwrittenMain", "Main", "property-x", - "true", "", " foo", " service-launcher description", diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DefaultBundlingEnvironmentTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DefaultBundlingEnvironmentTest.java index 1a14330fe6e..709f0f8413b 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DefaultBundlingEnvironmentTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DefaultBundlingEnvironmentTest.java @@ -41,7 +41,7 @@ import java.util.spi.ToolProvider; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.cli.StandardBundlingOperation; -import jdk.jpackage.internal.model.AppImagePackageType; +import jdk.jpackage.internal.model.AppImageBundleType; import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.StandardPackageType; @@ -119,9 +119,9 @@ public class DefaultBundlingEnvironmentTest extends JUnitAdapter { // #2 - jpackage should bail out earlier). // - final var type = op.packageTypeValue(); + final var type = op.bundleTypeValue(); final int iterationCount; - if (op.packageType() instanceof AppImagePackageType) { + if (op.bundleType() instanceof AppImageBundleType) { iterationCount = 1; } else { iterationCount = 2; @@ -165,7 +165,7 @@ public class DefaultBundlingEnvironmentTest extends JUnitAdapter { private static Script createMockScript(StandardBundlingOperation op) { - if (op.packageType() instanceof AppImagePackageType) { + if (op.bundleType() instanceof AppImageBundleType) { return Script.build().createSequence(); } 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 721e0802d16..de0ba67fece 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -616,7 +616,7 @@ public class PackagingPipelineTest { "1.0", "Acme", "copyright", - Optional.empty(), + List.of(), List.of(), appImageLayout, runtimeBuilder, @@ -633,7 +633,12 @@ public class PackagingPipelineTest { Package create() { return new Package.Stub( app, - new PackageType() {}, + new PackageType() { + @Override + public String label() { + throw new UnsupportedOperationException(); + } + }, "the-package", "My package", "1.0", 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 365a8a50b33..79648260274 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +22,7 @@ */ package jdk.jpackage.internal.cli; +import static jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput.augmentResultWithOutput; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -43,19 +44,31 @@ import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.UnaryOperator; +import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.Globals; +import jdk.jpackage.internal.MockUtils; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput; import jdk.jpackage.internal.model.JPackageException; +import jdk.jpackage.internal.util.CommandOutputControl; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedExitCodeException; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedResultException; import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.test.Annotations; +import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JUnitAdapter; import jdk.jpackage.test.TKit; +import jdk.jpackage.test.mock.CommandActionSpecs; +import jdk.jpackage.test.mock.Script; +import jdk.jpackage.test.mock.VerbatimCommandMock; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; -public class MainTest extends JUnitAdapter.TestSrcInitializer { +public class MainTest extends JUnitAdapter { @ParameterizedTest @MethodSource @@ -78,6 +91,71 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { assertNotEquals(str, msg); } + /** + * Run app image packaging and simulate jlink failure. + *

+ * The test verifies that jpackage prints an error message with jlink exit code, + * command line, and output. + */ + @Annotations.Test + public void testFailedCommandOutput() { + + var jlinkMockExitCode = 17; + + var jlinkArgs = new ArrayList(); + + var jlinkMock = CommandActionSpecs.build() + .stdout("It").stderr("fell").stdout("apart") + .argsListener(jlinkArgs::addAll) + .exit(jlinkMockExitCode).create().toCommandMockBuilder().name("jlink-mock").create(); + + var script = Script.build() + // Replace jlink with the mock. + .map(Script.cmdlineStartsWith("jlink"), jlinkMock) + // Don't mock other external commands. + .map(_ -> true, VerbatimCommandMock.INSTANCE) + .createLoop(); + + var jpackageExitCode = 1; + + var jpackageToolProviderMock = new ToolProvider() { + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + var globalsMutator = MockUtils.buildJPackage().script(script).createGlobalsMutator(); + return Globals.main(() -> { + globalsMutator.accept(Globals.instance()); + + var result = ExecutionResult.create(args); + + var jlinkMockAttrs = new CommandOutputControl.ToolProviderAttributes(jlinkMock.name(), jlinkArgs); + + result.stdout().forEach(out::println); + result.stderr().forEach(err::println); + + assertEquals(jpackageExitCode, result.exitCode()); + assertEquals(List.of(), result.stdout()); + assertEquals(List.of( + I18N.format("message.error-header", I18N.format("error.command-failed-unexpected-exit-code", + jlinkMockExitCode, jlinkMockAttrs.printableCommandLine())), + I18N.format("message.failed-command-output-header"), + "It", "fell", "apart"), result.stderr()); + + return jpackageExitCode; + }); + } + + @Override + public String name() { + return "jpackage-mock"; + } + }; + + JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .useToolProvider(jpackageToolProviderMock) + .execute(jpackageExitCode); + } + private static Collection testOutput() { return Stream.of( // Print the tool version @@ -165,6 +243,49 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { data.add(new ErrorReporterTestSpec(cause, expect.getKey(), verbose, expectedOutput)); } } + + var execAttrs = new CommandOutputControl.ProcessAttributes(Optional.of(12345L), List.of("foo", "--bar")); + for (var makeCause : List.>of( + ex -> ex, + ExceptionBox::toUnchecked + )) { + + for (var expect : List.of( + Map.entry( + augmentResultWithOutput( + CommandOutputControl.Result.build().exitCode(135).execAttrs(execAttrs).create(), + "The quick brown fox\njumps over the lazy dog" + ).unexpected("Kaput!"), + ExceptionFormatter.FAILED_COMMAND_UNEXPECTED_OUTPUT_MESSAGE + ), + Map.entry( + new UnexpectedExitCodeException(augmentResultWithOutput( + CommandOutputControl.Result.build().exitCode(135).create(), + "The quick brown fox\njumps" + )), + ExceptionFormatter.FAILED_COMMAND_UNEXPECTED_EXIT_CODE_MESSAGE + ), + Map.entry( + augmentResultWithOutput( + CommandOutputControl.Result.build().create(), + "The quick brown fox\njumps" + ).unexpected("Timed out!"), + ExceptionFormatter.FAILED_COMMAND_TIMEDOUT_MESSAGE + ) + )) { + var cause = makeCause.apply(expect.getKey()); + var expectedOutput = new ArrayList(); + if (verbose) { + expectedOutput.add(ExceptionFormatter.STACK_TRACE); + } + expectedOutput.add(expect.getValue()); + if (!verbose) { + expectedOutput.add(ExceptionFormatter.FAILED_COMMAND_OUTPUT); + } + data.add(new ErrorReporterTestSpec(cause, expect.getKey(), verbose, expectedOutput)); + } + } + } return data; @@ -350,7 +471,24 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { ex.printStackTrace(pw); } return sink.toString(); - }) + }), + FAILED_COMMAND_OUTPUT(ex -> { + var result = failedCommandResult(ex); + var commandOutput = ((ExecutableAttributesWithCapturedOutput)result.execAttrs()).printableOutput(); + + var sink = new StringWriter(); + var pw = new PrintWriter(sink); + + pw.println(I18N.format("message.failed-command-output-header")); + try (var lines = new BufferedReader(new StringReader(commandOutput)).lines()) { + lines.forEach(pw::println); + } + + return sink.toString(); + }), + FAILED_COMMAND_UNEXPECTED_OUTPUT_MESSAGE(errorMessage(CommandFailureType.UNEXPECTED_OUTPUT::getMessage)), + FAILED_COMMAND_UNEXPECTED_EXIT_CODE_MESSAGE(errorMessage(CommandFailureType.UNEXPECTED_EXIT_CODE::getMessage)), + FAILED_COMMAND_TIMEDOUT_MESSAGE(errorMessage(CommandFailureType.TIMEDOUT::getMessage)), ; ExceptionFormatter(Function formatter) { @@ -369,6 +507,42 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { }; } + private static CommandOutputControl.Result failedCommandResult(Exception ex) { + Objects.requireNonNull(ex); + if (ex instanceof UnexpectedResultException urex) { + return urex.getResult(); + } else { + throw new IllegalArgumentException(); + } + } + + private enum CommandFailureType { + UNEXPECTED_OUTPUT, + UNEXPECTED_EXIT_CODE, + TIMEDOUT, + ; + + String getMessage(Exception ex) { + var result = failedCommandResult(ex); + var printableCommandLine = result.execAttrs().printableCommandLine(); + switch (this) { + case TIMEDOUT -> { + return I18N.format("error.command-failed-timed-out", printableCommandLine); + } + case UNEXPECTED_EXIT_CODE -> { + return I18N.format("error.command-failed-unexpected-exit-code", result.getExitCode(), printableCommandLine); + } + case UNEXPECTED_OUTPUT -> { + return I18N.format("error.command-failed-unexpected-output", printableCommandLine); + } + default -> { + // Unreachable + throw ExceptionBox.reachedUnreachable(); + } + } + } + } + private final Function formatter; } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecMutatorOptionScopeTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecMutatorOptionScopeTest.java index 1849a3b5333..59c7c85ce85 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecMutatorOptionScopeTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecMutatorOptionScopeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +75,11 @@ public class OptionSpecMutatorOptionScopeTest { assertEquals(OptionName.of("foo"), mappedSpec.name()); } - assertEquals("731", mappedSpec.converter().orElseThrow().convert(spec.name(), StringToken.of("str")).orElseThrow()); + assertEquals("731", mappedSpec.convert(spec.name(), StringToken.of("str")).orElseThrow()); assertEquals(OptionName.of("foo"), spec.name()); - assertEquals("123", spec.converter().orElseThrow().convert(spec.name(), StringToken.of("str")).orElseThrow()); + assertEquals("123", spec.convert(spec.name(), StringToken.of("str")).orElseThrow()); } @Test @@ -99,11 +99,11 @@ public class OptionSpecMutatorOptionScopeTest { var mappedSpec = new DummyContext(731).mapOptionSpec(spec); - assertArrayEquals(new String[] {"731"}, mappedSpec.converter().orElseThrow().convert(spec.name(), StringToken.of("str")).orElseThrow()); + assertArrayEquals(new String[] {"731"}, mappedSpec.convert(spec.name(), StringToken.of("str")).orElseThrow()); assertEquals(OptionName.of("foo"), spec.name()); - assertArrayEquals(new String[] {"123"}, spec.converter().orElseThrow().convert(spec.name(), StringToken.of("str")).orElseThrow()); + assertArrayEquals(new String[] {"123"}, spec.convert(spec.name(), StringToken.of("str")).orElseThrow()); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecTest.java index a92c677d9cf..66bd44a2402 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionSpecTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -293,11 +293,11 @@ public class OptionSpecTest { return toOptionNames(List.of(names)); } - private static OptionValueConverter converter(ValueConverter conv) { + private static OptionValueConverter converter(ValueConverter conv) { return buildConverter(conv).create(); } - private static OptionValueConverter.Builder buildConverter(ValueConverter conv) { + private static OptionValueConverter.Builder buildConverter(ValueConverter conv) { return OptionValueConverter.build().converter(conv); } @@ -329,7 +329,7 @@ public class OptionSpecTest { return this; } - OptionSpecBuilder converter(OptionValueConverter v) { + OptionSpecBuilder converter(OptionValueConverter v) { converter = v; return this; } @@ -355,7 +355,7 @@ public class OptionSpecTest { } private List names; - private OptionValueConverter converter; + private OptionValueConverter converter; private T defaultOptionalValue; private Set scope = Set.of(new OptionScope() {}); private MergePolicy mergePolicy = MergePolicy.USE_LAST; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionValueConverterTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionValueConverterTest.java index c026ee0639f..3d8f26523a0 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionValueConverterTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionValueConverterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 @@ */ package jdk.jpackage.internal.cli; +import static jdk.jpackage.internal.cli.OptionValueConverter.convertString; import static jdk.jpackage.internal.cli.TestUtils.assertExceptionListEquals; import static jdk.jpackage.internal.cli.TestUtils.configureConverter; import static jdk.jpackage.internal.cli.TestUtils.configureValidator; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; @@ -33,6 +35,7 @@ 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.nio.file.Path; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; @@ -55,10 +58,10 @@ public class OptionValueConverterTest { if (positive) { final var token = StringToken.of("758"); - assertEquals(758, converter.convert(OptionName.of("number"), token).orElseThrow()); + assertEquals(758, convertString(converter, OptionName.of("number"), token).orElseThrow()); } else { final var token = StringToken.of("foo"); - final var result = converter.convert(OptionName.of("number"), token); + final var result = convertString(converter, OptionName.of("number"), token); assertEquals(1, result.errors().size()); @@ -77,7 +80,7 @@ public class OptionValueConverterTest { .converter(ValueConverter.create(Integer::valueOf, Integer.class)).create(); Function> convertString = (v) -> { - return converter.convert(OptionName.of("foo"), StringToken.of(v)); + return convertString(converter, OptionName.of("foo"), StringToken.of(v)); }; assertEquals(10, convertString.apply("10").orElseThrow()); @@ -89,24 +92,32 @@ public class OptionValueConverterTest { public void test_Builder_invalid() { assertThrowsExactly(NullPointerException.class, OptionValueConverter.build() - .converter(ValueConverter.create(Integer::valueOf, Integer.class)) + .converter(phonyConverter(Integer.class)) .mutate(configureConverter()) .formatString(null)::create); assertThrowsExactly(NullPointerException.class, OptionValueConverter.build() - .converter(ValueConverter.create(Integer::valueOf, Integer.class)) + .converter(phonyConverter(Integer.class)) .mutate(configureConverter()) .exceptionFactory(null)::create); } - @Test - public void test_Builder_copy() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_Builder_copy(boolean twoStep) { Function tokenizer = _ -> { throw new UnsupportedOperationException(); }; - var builder = OptionValueConverter.build() - .converter(ValueConverter.create(Integer::valueOf, Integer.class)) - .validator(Validator.build().predicate(_ -> true).create()) + final OptionValueConverter.Builder builder; + if (twoStep) { + builder = OptionValueConverter.build() + .converter(phonyConverter(Path.class)) + .map(phonyConverter(Integer.class)); + } else { + builder = OptionValueConverter.build().converter(phonyConverter(Integer.class)); + } + + builder.validator(Validator.build().predicate(_ -> true).create()) .mutate(configureConverter()) .tokenizer(tokenizer); @@ -114,7 +125,10 @@ public class OptionValueConverterTest { assertNotSame(copy, builder); - assertSame(builder.converter().orElse(null), copy.converter().orElse(null)); + if (!twoStep) { + assertSame(builder.converter().orElse(null), copy.converter().orElse(null)); + } + assertSame(builder.formatString().orElse(null), copy.formatString().orElse(null)); assertSame(builder.exceptionFactory().orElse(null), copy.exceptionFactory().orElse(null)); assertSame(builder.tokenizer().orElse(null), copy.tokenizer().orElse(null)); @@ -125,6 +139,23 @@ public class OptionValueConverterTest { assertNotEquals(builder.formatString().orElse(null), copy.formatString().orElse(null)); } + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_Builder_hasConverter(boolean twoStep) { + + if (twoStep) { + final var builder = OptionValueConverter.build() + .converter(phonyConverter(Path.class)) + .map(phonyConverter(String.class)); + assertTrue(builder.hasConverter()); + } else { + final var builder = OptionValueConverter.build(); + assertFalse(builder.hasConverter()); + builder.converter(phonyConverter(String.class)); + assertTrue(builder.hasConverter()); + } + } + @Test public void test_Builder_createArray() { @@ -134,7 +165,7 @@ public class OptionValueConverterTest { .tokenizer(str -> str.split(":")) .createArray(); - assertNotEquals(List.of(100, 67, 145), List.of(converter.convert(OptionName.of("foo"), StringToken.of("110:67:145")).orElseThrow())); + assertNotEquals(List.of(100, 67, 145), List.of(convertString(converter, OptionName.of("foo"), StringToken.of("110:67:145")).orElseThrow())); assertEquals(Integer[].class, converter.valueType()); } @@ -170,7 +201,7 @@ public class OptionValueConverterTest { var converter = builder.createArray(); - var result = converter.convert(OptionName.of("foo"), StringToken.of("100:-10:-10:67:str:145:-7")); + var result = convertString(converter, OptionName.of("foo"), StringToken.of("100:-10:-10:67:str:145:-7")); assertExceptionListEquals(Stream.of( new IllegalArgumentException("-10"), @@ -192,7 +223,7 @@ public class OptionValueConverterTest { }, Integer.class)).mutate(configureConverter()).create(); final var token = StringToken.of("foo"); - final var ex = assertThrowsExactly(ConverterException.class, () -> converter.convert(OptionName.of("number"), token)); + final var ex = assertThrowsExactly(ConverterException.class, () -> convertString(converter, OptionName.of("number"), token)); assertSame(exception, ex.getCause()); } @@ -209,8 +240,133 @@ public class OptionValueConverterTest { }).mutate(configureValidator()).create()).create(); final var token = StringToken.of("100"); - final var ex = assertThrowsExactly(ConverterException.class, () -> converter.convert(OptionName.of("number"), token)); + final var ex = assertThrowsExactly(ConverterException.class, () -> convertString(converter, OptionName.of("number"), token)); assertSame(exception, ex.getCause()); } + + @Test + public void testTwoStep() { + + final var multiplyConverter = ValueConverter.create(v -> { + return (long)(v * -1); + }, Long.class); + + final var converter = OptionValueConverter.build() + .converter(ValueConverter.create(Integer::parseInt, Integer.class)) + .map(multiplyConverter) + .create(); + + assertEquals(Long.class, converter.valueType()); + + var result = convertString(converter, OptionName.of("foo"), StringToken.of("123")).orElseThrow(); + assertEquals(-123, result); + } + + @Test + public void testMultiStep() { + + final var converter = OptionValueConverter.build() + .converter(ValueConverter.create(Path::of, Path.class)) + .map(ValueConverter.create(v -> { + return v.normalize().toString(); + }, String.class)) + .map(ValueConverter.create(Integer::valueOf, Integer.class)) + .create(); + + assertEquals(Integer.class, converter.valueType()); + + var result = convertString(converter, OptionName.of("foo"), StringToken.of("./123")).orElseThrow(); + assertEquals(123, result); + } + + @ParameterizedTest + @ValueSource(ints = {0, 1, 2}) + public void testTwoStep_map(int type) { + + var tolower = ValueConverter.create(String::toLowerCase, String.class); + var toupper = ValueConverter.create(String::toUpperCase, String.class); + var reverse = ValueConverter.create(str -> { + return new StringBuilder(str).reverse().toString(); + }, String.class); + + final var baseBuilder = OptionValueConverter.build().converter(toupper); + + switch (type) { + case 0 -> { + assertThrowsExactly(UnsupportedOperationException.class, () -> { + baseBuilder.map(OptionValueConverter.build()); + }); + } + case 1 -> { + var builder = baseBuilder.map(reverse); + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + builder.map(OptionValueConverter.build().converter(phonyConverter(Object.class))); + }); + assertEquals(String.format("Expected (%s); actual (%s)", String.class, Object.class), ex.getMessage()); + + assertEquals("CBA", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + var copy = builder.map(baseBuilder); + assertNotSame(copy, builder); + assertEquals("CBA", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("CBA", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + copy = builder.map(baseBuilder.copy().converter(tolower)); + assertNotSame(copy, builder); + assertEquals("cba", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("CBA", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + } + case 2 -> { + var builder = baseBuilder.map(reverse).map(reverse); + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + builder.map(OptionValueConverter.build().converter(phonyConverter(Object.class))); + }); + assertEquals(String.format("Expected (%s); actual (%s)", String.class, Object.class), ex.getMessage()); + + assertEquals("ABC", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + var copy = builder.map(baseBuilder.map(reverse)); + assertNotSame(copy, builder); + assertEquals("ABC", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("ABC", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + copy = builder.map(baseBuilder.copy().converter(tolower).map(reverse)); + assertNotSame(copy, builder); + assertEquals("abc", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("ABC", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + + copy = builder.map(baseBuilder.copy().converter(tolower)); + assertNotSame(copy, builder); + assertEquals("cba", convertString(copy.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + assertEquals("ABC", convertString(builder.create(), OptionName.of("foo"), StringToken.of("aBc")).orElseThrow()); + } + } + } + + @Test + public void testTwoStep_converter() { + + final var builder = OptionValueConverter.build() + // Create the "String -> Path" converter + .converter(ValueConverter.create(Path::of, Path.class)) + // Map the "String -> Path" converter into the "Path -> String" converter + .map(phonyConverter(String.class)) + // Map the "Path -> String" converter into the "String -> String" converter + .map(phonyConverter(String.class)); + + assertThrowsExactly(UnsupportedOperationException.class, () -> { + builder.converter(phonyConverter(String.class)); + }); + + assertThrowsExactly(UnsupportedOperationException.class, () -> { + builder.converter(); + }); + } + + private static ValueConverter phonyConverter(Class valueType) { + return ValueConverter.create(v -> { + throw new AssertionError(); + }, valueType); + } } 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 e15d5130d43..9826f0e9069 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +200,14 @@ public class OptionsValidationFailTest { Stream.of("--jpt-run=ErrorTest") ).flatMap(x -> x).toArray(String[]::new)).map(dynamicTest -> { return DynamicTest.dynamicTest(dynamicTest.getDisplayName(), () -> { - JPackageCommand.withToolProvider(() -> { + TKit.withNewState(() -> { + JPackageCommand.useToolProviderByDefault(jpackageToolProviderMock); try { dynamicTest.getExecutable().execute(); } catch (Throwable t) { throw ExceptionBox.toUnchecked(ExceptionBox.unbox(t)); } - }, jpackageToolProviderMock); + }); }); }); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java index 4aa3d5f72c1..58a78edb627 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java @@ -24,6 +24,8 @@ package jdk.jpackage.internal.cli; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.cli.TestUtils.assertExceptionListEquals; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertSame; @@ -53,12 +55,16 @@ import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.cli.JOptSimpleOptionsBuilder.ConvertedOptionsBuilder; import jdk.jpackage.internal.cli.JOptSimpleOptionsBuilder.OptionsBuilder; import jdk.jpackage.internal.cli.StandardOption.LauncherProperty; +import jdk.jpackage.internal.model.AppImageBundleType; +import jdk.jpackage.internal.model.BundleType; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; +import jdk.jpackage.internal.util.RootedPath; import jdk.jpackage.internal.util.StringBundle; import jdk.jpackage.test.Comm; import jdk.jpackage.test.JUnitAdapter; +import jdk.jpackage.test.JUnitUtils; import jdk.jpackage.test.TKit; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -109,7 +115,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = StandardOption.ICON.getSpec(); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(name)); + var result = spec.convert(spec.name(), StringToken.of(name)); assertEquals(Path.of(name), result.orElseThrow()); } @@ -119,7 +125,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = StandardOption.ICON.getSpec(); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(workDir.toString())); + var result = spec.convert(spec.name(), StringToken.of(workDir.toString())); var ex = assertThrows(JPackageException.class, result::orElseThrow); @@ -133,7 +139,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = new StandardOptionContext().forFile(propertyFile).mapOptionSpec(StandardOption.ICON.getSpec()); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(workDir.toString())); + var result = spec.convert(spec.name(), StringToken.of(workDir.toString())); var ex = assertThrows(JPackageException.class, result::orElseThrow); @@ -148,7 +154,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var tempRoot = workDir.resolve(dir); - var value = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(tempRoot.toString())).orElseThrow(); + var value = spec.convert(spec.name(), StringToken.of(tempRoot.toString())).orElseThrow(); assertEquals(tempRoot, value); } @@ -163,28 +169,33 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { Files.writeString(tempRoot, "foo"); var ex = assertThrowsExactly(JPackageException.class, - spec.converter().orElseThrow().convert(spec.name(), StringToken.of(tempRoot.toString()))::orElseThrow); + spec.convert(spec.name(), StringToken.of(tempRoot.toString()))::orElseThrow); assertEquals(I18N.format("error.parameter-not-empty-directory", tempRoot, "--temp"), ex.getMessage()); assertEquals(NotDirectoryException.class, ex.getCause().getClass()); tempRoot = workDir; ex = assertThrowsExactly(JPackageException.class, - spec.converter().orElseThrow().convert(spec.name(), StringToken.of(tempRoot.toString()))::orElseThrow); + spec.convert(spec.name(), StringToken.of(tempRoot.toString()))::orElseThrow); assertEquals(I18N.format("error.parameter-not-empty-directory", tempRoot, "--temp"), ex.getMessage()); assertEquals(DirectoryNotEmptyException.class, ex.getCause().getClass()); } + @ParameterizedTest + @EnumSource(names = {"WINDOWS", "LINUX", "MACOS"}) + public void test_TYPE_valid(OperatingSystem appImageOS) { + + var spec = new StandardOptionContext(appImageOS).mapOptionSpec(StandardOption.TYPE.getSpec()); + + test_TYPE_valid(spec, appImageOS); + } + @Test public void test_TYPE_valid() { var spec = StandardOption.TYPE.getSpec(); - Stream.of(StandardBundlingOperation.values()).forEach(bundlingOperation -> { - var pkgTypeStr = bundlingOperation.packageTypeValue(); - var pkgType = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(pkgTypeStr)).orElseThrow(); - assertSame(bundlingOperation.packageType(), pkgType); - }); + test_TYPE_valid(spec, OperatingSystem.current()); } @ParameterizedTest @@ -193,13 +204,146 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = StandardOption.TYPE.getSpec(); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(name)); + var result = spec.convert(spec.name(), StringToken.of(name)); var ex = assertThrows(JPackageException.class, result::orElseThrow); assertEquals(I18N.format("ERR_InvalidInstallerType", name), ex.getMessage()); } + @Test + public void test_APP_CONTENT_valid(@TempDir Path workDir) throws IOException { + + var spec = StandardOption.APP_CONTENT.getSpec(); + + var contentDir = workDir.resolve("a"); + var emptyDir = contentDir.resolve("b/empty-dir"); + var file = contentDir.resolve("file.txt"); + + Files.createDirectories(emptyDir); + Files.createDirectories(file.getParent()); + Files.createFile(file); + + Object convertedValue = spec.convert( + spec.name(), + StringToken.of(Stream.of(contentDir, file).map(Path::toString).collect(joining(","))) + ).orElseThrow(); + + var paths = StandardOption.APP_CONTENT.getFrom(Options.of(Map.of(StandardOption.APP_CONTENT, convertedValue))); + var sortedPathList = paths.stream().flatMap(Collection::stream).map(RootedPath::branch).sorted().toList(); + + var expectedPathList = Stream.of( + "a", + "a/b", + "a/b/empty-dir", + "a/file.txt", + "file.txt" + ).map(Path::of).sorted().toList(); + + assertEquals(expectedPathList, sortedPathList); + } + + @Test + public void test_APP_CONTENT_invalid(@TempDir Path workDir) throws IOException { + var spec = StandardOption.APP_CONTENT.getSpec(); + + var token = StringToken.of(workDir.resolve("nonexistent").toString()); + var result = spec.convert(spec.name(), token); + + assertExceptionListEquals(Stream.of( + "error.parameter-not-directory", + "error.parameter-not-file" + ).map(key -> { + return new JPackageException(I18N.format(key, token.value(), spec.name().formatForCommandLine())); + }).toList(), result.errors()); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_pathOptionMutator(OptionMutatorTest.TestType type) { + new OptionMutatorTest<>(StandardOption.pathOptionMutator(), StandardValueConverter.pathConv()) + .validValue("file.txt") + .invalidValue("\0") + .cmdlineErrorFormatKeys("error.parameter-not-path") + .propertyFileErrorFormatKeys("error.properties-parameter-not-path") + .test(OptionSpecBuilder.create(Path.class), type); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_existingPathOptionMutator(OptionMutatorTest.TestType type, @TempDir Path workDir) { + new OptionMutatorTest<>(StandardOption.existingPathOptionMutator(), StandardValueConverter.pathConv()) + .validValue(workDir.toString()) + .invalidValue(workDir.resolve("nonexistent").toString()) + .cmdlineErrorFormatKeys("error.parameter-not-directory", "error.parameter-not-file") + .propertyFileErrorFormatKeys("error.properties-parameter-not-directory", "error.properties-parameter-not-file") + .test(OptionSpecBuilder.create(Path.class), type); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_directoryOptionMutator(OptionMutatorTest.TestType type, @TempDir Path workDir) { + new OptionMutatorTest<>(StandardOption.directoryOptionMutator(), StandardValueConverter.pathConv()) + .validValue(workDir.toString()) + .invalidValue(workDir.resolve("nonexistent").toString()) + .cmdlineErrorFormatKeys("error.parameter-not-directory") + .propertyFileErrorFormatKeys("error.properties-parameter-not-directory") + .test(OptionSpecBuilder.create(Path.class), type); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_fileOptionMutator(OptionMutatorTest.TestType type, @TempDir Path workDir) throws IOException { + var test = new OptionMutatorTest<>(StandardOption.fileOptionMutator(), StandardValueConverter.pathConv()) + .invalidValue(workDir.resolve("nonexistent").toString()) + .cmdlineErrorFormatKeys("error.parameter-not-file") + .propertyFileErrorFormatKeys("error.properties-parameter-not-file"); + + switch (type) { + case TEST_CMDLINE_VALID, TEST_PROPERTY_FILE_VALID -> { + var file = workDir.resolve("file.txt"); + Files.createFile(file); + test.validValue(file.toString()); + } + default -> {} + } + + test.test(OptionSpecBuilder.create(Path.class), type); + } + + @ParameterizedTest + @EnumSource(OptionMutatorTest.TestType.class) + public void test_explodedPathOptionMapper(OptionMutatorTest.TestType type, @TempDir Path workDir) throws IOException { + + var explodePath = StandardValueConverter.explodedPathConverter().withPathFileName().create(); + + ValueConverter conv = ValueConverter.create(str -> { + var path = StandardValueConverter.pathConv().convert(str); + return explodePath.convert(path); + }, RootedPath[].class); + + var test = new OptionMutatorTest<>(_ -> {}, conv) + .invalidValue(workDir.resolve("nonexistent").toString()) + .cmdlineErrorFormatKeys("error.parameter-not-directory") + .propertyFileErrorFormatKeys("error.properties-parameter-not-directory"); + + switch (type) { + case TEST_CMDLINE_VALID, TEST_PROPERTY_FILE_VALID -> { + var dir = workDir.resolve("dir"); + Files.createDirectories(dir); + for (var file : List.of("foo.txt", "bar.txt")) { + Files.createFile(workDir.resolve(file)); + } + test.validValue(dir.toString()); + } + default -> {} + } + + test.test(OptionSpecBuilder.create(Path.class) + .mutate(StandardOption.directoryOptionMutator()) + .map(StandardOption.explodedPathOptionMapper(explodePath)), type); + } + @Test public void test_booleanOptionMutator() { @@ -214,6 +358,13 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { assertFalse(option.containsIn(empty)); } + @Test + public void test_booleanOptionMutator_in_property_file() { + new OptionMutatorTest<>(StandardOption.booleanOptionMutator(), StandardValueConverter.booleanConv()) + .validValue(Boolean.TRUE.toString()) + .test(OptionSpecBuilder.create(Boolean.class), OptionMutatorTest.TestType.TEST_PROPERTY_FILE_VALID); + } + @ParameterizedTest @MethodSource public void testLauncherShortcutOptions(LauncherShortcutTestSpec testSpec) { @@ -296,7 +447,7 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { var spec = StandardOption.ARGUMENTS.getOption().spec(); - var result = spec.converter().orElseThrow().convert(spec.name(), StringToken.of(value)); + var result = spec.convert(spec.name(), StringToken.of(value)); assertEquals(expectedTokens, List.of(result.map(String[].class::cast).orElseThrow())); } @@ -336,6 +487,18 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { assertEquals(expectedOptionTable, optionTable); } + private void test_TYPE_valid(OptionSpec spec, OperatingSystem appImageOS) { + Stream.of(StandardBundlingOperation.values()).filter(bundlingOperation -> { + // Skip app image bundle type if it is from another platform. + return !(bundlingOperation.bundleType() instanceof AppImageBundleType) + || (bundlingOperation.os() == appImageOS); + }).forEach(bundlingOperation -> { + var bundleTypeStr = bundlingOperation.bundleTypeValue(); + var bundleType = spec.convert(spec.name(), StringToken.of(bundleTypeStr)).orElseThrow(); + assertSame(bundlingOperation.bundleType(), bundleType); + }); + } + private static Collection test_ARGUMENTS() { return List.of( Arguments.of("abc", List.of("abc")), @@ -372,6 +535,100 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { } + static final class OptionMutatorTest { + + enum TestType { + TEST_CMDLINE_VALID, + TEST_PROPERTY_FILE_VALID, + TEST_CMDLINE_INVALID, + TEST_PROPERTY_FILE_INVALID; + } + + OptionMutatorTest(Consumer> testee, ValueConverter conv) { + this.testee = Objects.requireNonNull(testee); + this.conv = Objects.requireNonNull(conv); + } + + void test(OptionSpecBuilder specBuilder, TestType type) { + var srcSpec = specBuilder.name("foo").mutate(testee).createOptionSpec(); + OptionSpec spec; + + var propertyFile = Path.of("foo.properties"); + + switch (type) { + case TEST_PROPERTY_FILE_VALID, TEST_PROPERTY_FILE_INVALID -> { + spec = new StandardOptionContext().forFile(propertyFile).mapOptionSpec(srcSpec); + } + default -> { + spec = srcSpec; + } + } + + StringToken token; + switch (type) { + case TEST_CMDLINE_VALID, TEST_PROPERTY_FILE_VALID -> { + token = StringToken.of(Objects.requireNonNull(validValue)); + } + default -> { + token = StringToken.of(Objects.requireNonNull(invalidValue)); + } + } + + var result = spec.convert(spec.name(), token); + + switch (type) { + case TEST_CMDLINE_VALID, TEST_PROPERTY_FILE_VALID -> { + var expected = toFunction(conv::convert).apply(token.value()); + var actual = result.orElseThrow(); + + if (spec.valueType().isArray()) { + JUnitUtils.assertArrayEquals(expected, actual); + } else { + assertEquals(expected, actual); + } + } + case TEST_CMDLINE_INVALID -> { + assertExceptionListEquals(cmdlineErrorFormatKeys.stream().map(key -> { + return new JPackageException(I18N.format(key, token.value(), spec.name().formatForCommandLine())); + }).map(JUnitUtils::removeExceptionCause).toList(), result.errors().stream().map(JUnitUtils::removeExceptionCause).toList()); + } + case TEST_PROPERTY_FILE_INVALID -> { + assertExceptionListEquals(propertyFileErrorFormatKeys.stream().map(key -> { + return new JPackageException(I18N.format(key, token.value(), spec.name().name(), propertyFile)); + }).map(JUnitUtils::removeExceptionCause).toList(), result.errors().stream().map(JUnitUtils::removeExceptionCause).toList()); + } + } + } + + OptionMutatorTest validValue(String v) { + validValue = v; + return this; + } + + OptionMutatorTest invalidValue(String v) { + invalidValue = v; + return this; + } + + OptionMutatorTest cmdlineErrorFormatKeys(String... v) { + cmdlineErrorFormatKeys = List.of(v); + return this; + } + + OptionMutatorTest propertyFileErrorFormatKeys(String... v) { + propertyFileErrorFormatKeys = List.of(v); + return this; + } + + private final Consumer> testee; + private final ValueConverter conv; + private List cmdlineErrorFormatKeys; + private List propertyFileErrorFormatKeys; + private String validValue; + private String invalidValue; + } + + record AddLauncherTestSpec(Optional expected, List expectedErrors, Optional optionValue) { AddLauncherTestSpec { if (expected.isEmpty() == expectedErrors.isEmpty()) { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardValueConverterTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardValueConverterTest.java index 6b16b1099c7..491dae60d5f 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardValueConverterTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardValueConverterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 org.junit.jupiter.params.provider.ValueSource; public class StandardValueConverterTest { @Test - public void test_identityConv() { + public void test_identityConv() throws Exception { final var testee = StandardValueConverter.identityConv(); @@ -58,7 +58,7 @@ public class StandardValueConverterTest { @ParameterizedTest @ValueSource(booleans = {true, false}) - public void test_pathConv(boolean positive) { + public void test_pathConv(boolean positive) throws Exception { final var testee = StandardValueConverter.pathConv(); @@ -72,14 +72,14 @@ public class StandardValueConverterTest { @ParameterizedTest @MethodSource - public void test_booleanConv(String value, Boolean expected) { + public void test_booleanConv(String value, Boolean expected) throws Exception { assertEquals(expected, StandardValueConverter.booleanConv().convert(value)); } @ParameterizedTest @MethodSource - public void test_mainLauncherShortcutConv(String value, LauncherShortcut expected) { + public void test_mainLauncherShortcutConv(String value, LauncherShortcut expected) throws Exception { assertEquals(expected, StandardValueConverter.mainLauncherShortcutConv().convert(value)); } @@ -93,7 +93,7 @@ public class StandardValueConverterTest { @ParameterizedTest @MethodSource - public void test_addLauncherShortcutConv(String value, LauncherShortcut expected) { + public void test_addLauncherShortcutConv(String value, LauncherShortcut expected) throws Exception { assertEquals(expected, StandardValueConverter.addLauncherShortcutConv().convert(value)); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/TestUtils.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/TestUtils.java index d3e9ecb09e9..2acf45b663d 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/TestUtils.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/TestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; import java.util.stream.StreamSupport; +import jdk.jpackage.internal.cli.Validator.ParsedValue; +import jdk.jpackage.internal.cli.Validator.ValidatorException; import jdk.jpackage.test.JUnitUtils; final class TestUtils { @@ -152,6 +154,31 @@ final class TestUtils { } + static final class RecordingValidator implements Validator { + + RecordingValidator(Validator validator) { + this.validator = Objects.requireNonNull(validator); + } + + @Override + public List validate(OptionName optionName, ParsedValue optionValue) { + counter++; + return validator.validate(optionName, optionValue); + } + + int counter() { + return counter; + } + + void resetCounter() { + counter = 0; + } + + private final Validator validator; + private int counter; + } + + private record RecordingExceptionFactory(OptionValueExceptionFactory factory, Consumer sink) implements OptionValueExceptionFactory { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/ValidatorTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/ValidatorTest.java index d4c48df6a0c..d8d69027f77 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/ValidatorTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/ValidatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +32,11 @@ import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Stream; import jdk.jpackage.internal.cli.TestUtils.TestException; +import jdk.jpackage.internal.cli.TestUtils.RecordingValidator; import jdk.jpackage.internal.cli.Validator.ParsedValue; import jdk.jpackage.internal.cli.Validator.ValidatingConsumerException; import jdk.jpackage.internal.cli.Validator.ValidatorException; @@ -187,46 +188,97 @@ public class ValidatorTest { } @Test - public void test_andThen() { - - Function> createFailingValidator = exceptionMessage -> { - Objects.requireNonNull(exceptionMessage); - var exceptionFactory = OptionValueExceptionFactory.build().ctor(TestException::new).messageFormatter((_, _) -> { - return exceptionMessage; - }).create(); - - return Validator.build() - .predicate(_ -> false) - .formatString("") - .exceptionFactory(exceptionFactory).create(); - }; + public void test_and() { Function, List> validate = validator -> { return validator.validate(OptionName.of("a"), ParsedValue.create("str", StringToken.of("str"))); }; - var pass = Validator.build().predicate(_ -> true).create(); + var pass = new RecordingValidator<>(Validator.build().predicate(_ -> true).create()); - var foo = createFailingValidator.apply("foo"); - var bar = createFailingValidator.apply("bar"); - var buz = createFailingValidator.apply("buz"); + var foo = failingValidator("foo"); + var bar = failingValidator("bar"); + var buz = failingValidator("buz"); assertExceptionListEquals(List.of( new TestException("foo"), new TestException("bar"), new TestException("buz") - ), validate.apply(foo.andThen(bar).andThen(pass).andThen(buz))); + ), validate.apply(foo.and(bar).and(pass).and(buz))); + assertEquals(1, pass.counter()); + pass.resetCounter(); assertExceptionListEquals(List.of( new TestException("bar"), new TestException("buz"), new TestException("foo") - ), validate.apply(pass.andThen(bar).andThen(buz).andThen(foo))); + ), validate.apply(pass.and(bar).and(buz).and(foo))); + assertEquals(1, pass.counter()); assertExceptionListEquals(List.of( new TestException("foo"), new TestException("foo") - ), validate.apply(foo.andThen(foo))); + ), validate.apply(foo.and(foo))); + + pass.resetCounter(); + assertExceptionListEquals(List.of( + ), validate.apply(pass.and(pass))); + assertEquals(2, pass.counter()); + } + + @Test + public void test_or() { + + Function, List> validate = validator -> { + return validator.validate(OptionName.of("a"), ParsedValue.create("str", StringToken.of("str"))); + }; + + var pass = new RecordingValidator<>(Validator.build().predicate(_ -> true).create()); + + var foo = new RecordingValidator<>(failingValidator("foo")); + var bar = new RecordingValidator<>(failingValidator("bar")); + var buz = new RecordingValidator<>(failingValidator("buz")); + + Runnable resetCounters = () -> { + Stream.of(pass, foo, bar, buz).forEach(RecordingValidator::resetCounter); + }; + + assertExceptionListEquals(List.of( + new TestException("foo"), + new TestException("bar"), + new TestException("buz") + ), validate.apply(foo.or(bar).or(buz))); + assertEquals(1, foo.counter()); + assertEquals(1, bar.counter()); + assertEquals(1, buz.counter()); + + resetCounters.run(); + assertExceptionListEquals(List.of( + ), validate.apply(foo.or(bar).or(pass).or(buz))); + assertEquals(1, foo.counter()); + assertEquals(1, bar.counter()); + assertEquals(1, pass.counter()); + assertEquals(0, buz.counter()); + + resetCounters.run(); + assertExceptionListEquals(List.of( + ), validate.apply(pass.or(bar).or(buz).or(foo))); + assertEquals(1, pass.counter()); + assertEquals(0, bar.counter()); + assertEquals(0, buz.counter()); + assertEquals(0, foo.counter()); + + resetCounters.run(); + assertExceptionListEquals(List.of( + new TestException("foo"), + new TestException("foo") + ), validate.apply(foo.or(foo))); + assertEquals(2, foo.counter()); + + resetCounters.run(); + assertExceptionListEquals(List.of( + ), validate.apply(pass.or(pass))); + assertEquals(1, pass.counter()); } @ParameterizedTest @@ -269,6 +321,17 @@ public class ValidatorTest { return data; } + private static Validator failingValidator(String exceptionMessage) { + var exceptionFactory = OptionValueExceptionFactory.build().ctor(TestException::new).messageFormatter((_, _) -> { + return exceptionMessage; + }).create(); + + return Validator.build() + .predicate(_ -> false) + .formatString("") + .exceptionFactory(exceptionFactory).create(); + } + static final class FooException extends Exception { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CommandOutputControlTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CommandOutputControlTest.java index f1d8c142eb9..d71cf7c4d41 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CommandOutputControlTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CommandOutputControlTest.java @@ -203,11 +203,11 @@ public class CommandOutputControlTest { exec = coc.createExecutable(new ProcessBuilder("runme", "--foo", "--baz=10")); } - assertEquals("runme --foo --baz=10", exec.attributes().toString()); + assertEquals("runme --foo --baz=10", exec.attributes().printableCommandLine()); } @Test - public void test_Result_no_args_ctor() { + public void test_Result_single_arg_ctor() { var result = new CommandOutputControl.Result(7); assertFalse(result.findContent().isPresent()); assertFalse(result.findStdout().isPresent()); @@ -216,6 +216,18 @@ public class CommandOutputControlTest { assertSame(Objects.requireNonNull(CommandOutputControl.EMPTY_EXECUTABLE_ATTRIBUTES), result.execAttrs()); } + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_Result_unexpected(boolean customMessage) throws IOException { + var result = new CommandOutputControl.Result(7); + + if (customMessage) { + assertEquals("Kaput!", result.unexpected("Kaput!").getMessage()); + } else { + assertEquals("Unexpected result from executing the command ", result.unexpected().getMessage()); + } + } + @Test public void test_Result_expectExitCode() throws IOException { var result = new CommandOutputControl.Result(7); @@ -276,14 +288,9 @@ public class CommandOutputControlTest { var empty = new CommandOutputControl.Result(0); var execAttrs = new CommandOutputControl.ExecutableAttributes() { - @Override - public String toString() { - return "foo"; - } - @Override public List commandLine() { - return List.of(); + return List.of("foo"); } }; @@ -295,6 +302,20 @@ public class CommandOutputControlTest { assertSame(execAttrs, copy.execAttrs()); } + @Test + public void test_UnexpectedExitCodeException_no_exit_code() { + + var resultWithoutExitCode = CommandOutputControl.Result.build().create(); + + assertThrowsExactly(IllegalArgumentException.class, () -> { + new CommandOutputControl.UnexpectedExitCodeException(resultWithoutExitCode); + }); + + assertThrowsExactly(IllegalArgumentException.class, () -> { + new CommandOutputControl.UnexpectedExitCodeException(resultWithoutExitCode, "Kaput!"); + }); + } + @ParameterizedTest @EnumSource(ExecutableType.class) public void test_timeout_expires(ExecutableType mode) throws InterruptedException, IOException { @@ -1781,7 +1802,7 @@ public class CommandOutputControlTest { } } - private final static class InterruptibleToolProvider implements ToolProvider { + private static final class InterruptibleToolProvider implements ToolProvider { InterruptibleToolProvider(ToolProvider impl) { this.impl = impl; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/FileUtilsTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/FileUtilsTest.java index 2067f0fa628..b7639dbfad4 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/FileUtilsTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/FileUtilsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,92 +24,36 @@ 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.assertTrue; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.ValueSource; public class FileUtilsTest { - @ParameterizedTest - @EnumSource(ExcludeType.class) - public void test_copyRecursive_dir(ExcludeType exclude, @TempDir Path workdir) throws IOException { + @Test + public void test_copyRecursive_dir(@TempDir Path workdir) throws IOException { Files.createDirectories(workdir.resolve("from/foo/bar")); Files.createDirectories(workdir.resolve("from/foo/buz")); Files.writeString(workdir.resolve("from/foo/bar/file.txt"), "Hello"); - List excludes = new ArrayList<>(); - switch (exclude) { - case EXCLUDE_FILE -> { - excludes.add(Path.of("file.txt")); - } - case EXCLUDE_DIR -> { - excludes.add(Path.of("bar")); - } - case EXCLUDE_SUBDIR -> { - excludes.add(Path.of("foo")); - } - case EXCLUDE_NONE -> { - } - } - - FileUtils.copyRecursive(workdir.resolve("from"), workdir.resolve("to"), excludes); + FileUtils.copyRecursive(workdir.resolve("from"), workdir.resolve("to")); assertEquals("Hello", Files.readString(workdir.resolve("from/foo/bar/file.txt"))); - - switch (exclude) { - case EXCLUDE_FILE -> { - assertFalse(Files.exists(workdir.resolve("to/foo/bar/file.txt"))); - assertTrue(Files.isDirectory(workdir.resolve("to/foo/bar"))); - } - case EXCLUDE_DIR -> { - assertFalse(Files.exists(workdir.resolve("to/foo/bar"))); - assertTrue(Files.isDirectory(workdir.resolve("to/foo/buz"))); - } - case EXCLUDE_SUBDIR -> { - assertFalse(Files.exists(workdir.resolve("to/foo"))); - assertTrue(Files.isDirectory(workdir.resolve("to"))); - } - case EXCLUDE_NONE -> { - assertEquals("Hello", Files.readString(workdir.resolve("to/foo/bar/file.txt"))); - } - } + assertEquals("Hello", Files.readString(workdir.resolve("to/foo/bar/file.txt"))); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void test_copyRecursive_file(boolean exclude, @TempDir Path workdir) throws IOException { + @Test + public void test_copyRecursive_file(@TempDir Path workdir) throws IOException { Files.createDirectories(workdir.resolve("from/foo/bar")); Files.writeString(workdir.resolve("from/foo/bar/file.txt"), "Hello"); - List excludes = new ArrayList<>(); - if (exclude) { - excludes.add(Path.of("bar/file.txt")); - } - - FileUtils.copyRecursive(workdir.resolve("from/foo/bar/file.txt"), workdir.resolve("to/foo/bar/file.txt"), excludes); + FileUtils.copyRecursive(workdir.resolve("from/foo/bar/file.txt"), workdir.resolve("to/foo/bar/file.txt")); assertEquals("Hello", Files.readString(workdir.resolve("from/foo/bar/file.txt"))); - if (exclude) { - assertFalse(Files.exists(workdir.resolve("to"))); - } else { - assertEquals("Hello", Files.readString(workdir.resolve("to/foo/bar/file.txt"))); - } - } - - enum ExcludeType { - EXCLUDE_NONE, - EXCLUDE_FILE, - EXCLUDE_DIR, - EXCLUDE_SUBDIR, + assertEquals("Hello", Files.readString(workdir.resolve("to/foo/bar/file.txt"))); } } 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 952b4b520d5..4ab2c89873c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +29,11 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import jdk.jpackage.internal.util.TeeOutputStream; import jdk.jpackage.internal.util.function.ThrowingRunnable; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; @@ -70,12 +70,16 @@ public class JUnitAdapter { static List captureJPackageTestLog(ThrowingRunnable runnable) { final var buf = new ByteArrayOutputStream(); - try (PrintStream ps = new PrintStream(buf, true, StandardCharsets.UTF_8)) { - TKit.withExtraLogStream(runnable, ps); - } + var ps = new PrintStream(buf, false, TKit.state().out().charset()); + + final var out = new PrintStream(new TeeOutputStream(List.of(TKit.state().out(), ps)), true, ps.charset()); + + TKit.withOutput(runnable, out, TKit.state().err()); + + ps.flush(); try (final var in = new ByteArrayInputStream(buf.toByteArray()); - final var reader = new InputStreamReader(in, StandardCharsets.UTF_8); + final var reader = new InputStreamReader(in, ps.charset()); final var bufReader = new BufferedReader(reader)) { return bufReader.lines().map(line -> { // Skip timestamp diff --git a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java index 0b63688ee20..530a0d5cb1f 100644 --- a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java +++ b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +64,10 @@ public final class JUnitUtils { return EXCEPTION_OM.toMap(ex); } + public static Exception removeExceptionCause(Exception ex) { + return new ExceptionCauseRemover(ex); + } + public static final class ExceptionPattern { @@ -117,6 +121,23 @@ public final class JUnitUtils { } + private static final class ExceptionCauseRemover extends Exception { + + ExceptionCauseRemover(Exception ex) { + super(ex.getMessage()); + type = ex.getClass(); + } + + public Class getType() { + return type; + } + + private final Class type; + + private static final long serialVersionUID = 1L; + } + + @FunctionalInterface private interface ArrayEqualsAsserter { void accept(T expected, T actual); diff --git a/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java b/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java index 1a42a30c00e..e4adf3b9616 100644 --- a/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java +++ b/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +49,10 @@ public class ArgumentsFilteringTest { public void test1() { JPackageCommand cmd = JPackageCommand.helloAppImage(); cmd.executeAndAssertHelloAppImageCreated(); - var appVerifier = HelloApp.assertMainLauncher(cmd); - if (appVerifier != null) { + HelloApp.assertMainLauncher(cmd).ifPresent(appVerifier -> { appVerifier.execute("-psn_1_1"); appVerifier.verifyOutput(); - } + }); } @Test @@ -61,10 +60,9 @@ public class ArgumentsFilteringTest { JPackageCommand cmd = JPackageCommand.helloAppImage() .addArguments("--arguments", "-psn_2_2"); cmd.executeAndAssertHelloAppImageCreated(); - var appVerifier = HelloApp.assertMainLauncher(cmd); - if (appVerifier != null) { + HelloApp.assertMainLauncher(cmd).ifPresent(appVerifier -> { appVerifier.execute("-psn_1_1"); appVerifier.verifyOutput("-psn_2_2"); - } + }); } } diff --git a/test/jdk/tools/jpackage/macosx/EntitlementsTest.java b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java index 6e03c858db3..052e301a9ae 100644 --- a/test/jdk/tools/jpackage/macosx/EntitlementsTest.java +++ b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ import jdk.jpackage.test.TKit; * @test * @summary jpackage with --type app-image "--mac-entitlements" parameter * @library /test/jdk/tools/jpackage/helpers - * @library base - * @build SigningBase * @build jdk.jpackage.test.* - * @build EntitlementsTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror EntitlementsTest.java * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=EntitlementsTest @@ -142,7 +141,8 @@ public class EntitlementsTest { cmd.mutate(MacHelper.useKeychain(keychain)).mutate(new SignKeyOption( SignKeyOption.Type.SIGN_KEY_IDENTITY, - SigningBase.StandardCertificateRequest.CODESIGN.spec() + SigningBase.StandardCertificateRequest.CODESIGN, + keychain )::addTo); cmd.mutate(new AdditionalLauncher("x")::applyTo); diff --git a/test/jdk/tools/jpackage/macosx/MacSignTest.java b/test/jdk/tools/jpackage/macosx/MacSignTest.java index af7cf448bdc..a824fdb0925 100644 --- a/test/jdk/tools/jpackage/macosx/MacSignTest.java +++ b/test/jdk/tools/jpackage/macosx/MacSignTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +21,16 @@ * questions. */ +import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_IDENTITY; +import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_USER_FULL_NAME; +import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME; +import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_IDENTITY_APP_IMAGE; + import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -37,8 +41,11 @@ import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacHelper.NamedCertificateRequestSupplier; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; +import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; -import jdk.jpackage.test.MacSign.CertificateRequest; import jdk.jpackage.test.MacSign.CertificateType; import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageType; @@ -48,10 +55,9 @@ import jdk.jpackage.test.TKit; * @test * @summary jpackage with --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base - * @build SigningBase * @build jdk.jpackage.test.* - * @build MacSignTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror MacSignTest.java * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MacSignTest @@ -79,22 +85,28 @@ public class MacSignTest { } MacSign.withKeychain(keychain -> { + + var signingKeyOption = new SignKeyOptionWithKeychain( + SIGN_KEY_IDENTITY, + SigningBase.StandardCertificateRequest.CODESIGN, + keychain); + // --app-content and --type app-image // Expect `message.codesign.failed.reason.app.content` message in the log. // This is not a fatal error, just a warning. // To make jpackage fail, specify bad additional content. - final var cmd = JPackageCommand.helloAppImage() + JPackageCommand.helloAppImage() .ignoreDefaultVerbose(true) .validateOutput(expectedStrings.toArray(CannedFormattedString[]::new)) .addArguments("--app-content", appContent) - .addArguments("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec().name()); + .mutate(signingKeyOption::addTo) + .mutate(cmd -> { + if (MacHelper.isXcodeDevToolsInstalled()) { + // Check there is no warning about missing xcode command line developer tools. + cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); + } + }).execute(1); - if (MacHelper.isXcodeDevToolsInstalled()) { - // Check there is no warning about missing xcode command line developer tools. - cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); - } - - MacHelper.useKeychain(cmd, keychain).execute(1); }, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.MAIN.keychain()); } @@ -116,13 +128,19 @@ public class MacSignTest { expectedStrings.add(JPackageStringBundle.MAIN.cannedFormattedString("error.tool.failed.with.output", "codesign")); MacSign.withKeychain(keychain -> { - final var cmd = new JPackageCommand().setPackageType(PackageType.IMAGE) + + var signingKeyOption = new SignKeyOptionWithKeychain( + SIGN_KEY_IDENTITY, + SigningBase.StandardCertificateRequest.CODESIGN, + keychain); + + new JPackageCommand().setPackageType(PackageType.IMAGE) .ignoreDefaultVerbose(true) .validateOutput(expectedStrings.toArray(CannedFormattedString[]::new)) .addArguments("--app-image", appImageCmd.outputBundle()) - .addArguments("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec().name()); + .mutate(signingKeyOption::addTo) + .execute(1); - MacHelper.useKeychain(cmd, keychain).execute(1); }, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.MAIN.keychain()); } @@ -189,71 +207,78 @@ public class MacSignTest { @Test @ParameterSupplier @ParameterSupplier("testSelectSigningIdentity_JDK_8371094") - public static void testSelectSigningIdentity(String signingKeyUserName, CertificateRequest certRequest) { + public static void testSelectSigningIdentity(SignKeyOptionWithKeychain signKeyOption) { MacSign.withKeychain(keychain -> { - final var cmd = MacHelper.useKeychain(JPackageCommand.helloAppImage(), keychain) - .setFakeRuntime() - .addArguments("--mac-signing-key-user-name", signingKeyUserName); + final var cmd = JPackageCommand.helloAppImage().setFakeRuntime().mutate(signKeyOption::addTo); - cmd.executeAndAssertHelloAppImageCreated(); + cmd.executeAndAssertImageCreated(); - MacSignVerify.assertSigned(cmd.outputBundle(), certRequest); + MacSignVerify.verifyAppImageSigned(cmd, signKeyOption.certRequest()); }, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.MAIN.keychain()); } public static Collection testSelectSigningIdentity() { + var keychain = SigningBase.StandardKeychain.MAIN.keychain(); return Stream.of( SigningBase.StandardCertificateRequest.CODESIGN, SigningBase.StandardCertificateRequest.CODESIGN_UNICODE - ).map(SigningBase.StandardCertificateRequest::spec).mapMulti((certRequest, acc) -> { - acc.accept(new Object[] {certRequest.shortName(), certRequest}); - acc.accept(new Object[] {certRequest.name(), certRequest}); + ).map(certRequest -> { + return Stream.of( + SIGN_KEY_USER_FULL_NAME, + SIGN_KEY_USER_SHORT_NAME + ).map(type -> { + return new SignKeyOptionWithKeychain(type, certRequest, keychain); + }); + }).flatMap(x -> x).map(v -> { + return new Object[] {v}; }).toList(); } public static Collection testSelectSigningIdentity_JDK_8371094() { return List.of(new Object[] { - "ACME Technologies Limited", SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD.spec() + new SignKeyOptionWithKeychain( + "ACME Technologies Limited", + SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD, + SigningBase.StandardKeychain.MAIN.keychain()) }); } enum SignOption { - EXPIRED_SIGNING_KEY_USER_NAME("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), true, false), - EXPIRED_SIGNING_KEY_USER_NAME_PKG("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.PKG_EXPIRED.spec(), true, false), - EXPIRED_SIGN_IDENTITY("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), false, false), - EXPIRED_CODESIGN_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), false, true), - EXPIRED_PKG_SIGN_IDENTITY("--mac-installer-sign-identity", SigningBase.StandardCertificateRequest.PKG_EXPIRED.spec(), false, true), - GOOD_SIGNING_KEY_USER_NAME("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN.spec(), true, false), - GOOD_SIGNING_KEY_USER_NAME_PKG("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.PKG.spec(), true, false), - GOOD_CODESIGN_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec(), false, true), - GOOD_PKG_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.PKG.spec(), false, true); + EXPIRED_SIGNING_KEY_USER_NAME(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED), + EXPIRED_SIGNING_KEY_USER_NAME_PKG(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.PKG_EXPIRED), + EXPIRED_SIGN_IDENTITY(SIGN_KEY_USER_FULL_NAME, SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED), + EXPIRED_CODESIGN_SIGN_IDENTITY(SIGN_KEY_IDENTITY, SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED), + EXPIRED_PKG_SIGN_IDENTITY(SIGN_KEY_IDENTITY, SigningBase.StandardCertificateRequest.PKG_EXPIRED), + GOOD_SIGNING_KEY_USER_NAME(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.CODESIGN), + GOOD_SIGNING_KEY_USER_NAME_PKG(SIGN_KEY_USER_SHORT_NAME, SigningBase.StandardCertificateRequest.PKG), + GOOD_CODESIGN_SIGN_IDENTITY(SIGN_KEY_IDENTITY, SigningBase.StandardCertificateRequest.CODESIGN), + GOOD_PKG_SIGN_IDENTITY(SIGN_KEY_IDENTITY_APP_IMAGE, SigningBase.StandardCertificateRequest.PKG); - SignOption(String option, MacSign.CertificateRequest cert, boolean shortName, boolean passThrough) { - this.option = Objects.requireNonNull(option); - this.cert = Objects.requireNonNull(cert); - this.shortName = shortName; - this.passThrough = passThrough; + SignOption(SignKeyOption.Type optionType, NamedCertificateRequestSupplier certRequestSupplier) { + this.option = new SignKeyOption(optionType, new ResolvableCertificateRequest(certRequestSupplier.certRequest(), _ -> { + throw new UnsupportedOperationException(); + }, certRequestSupplier.name())); } boolean passThrough() { - return passThrough; + return option.type().mapOptionName(option.certRequest().type()).orElseThrow().passThrough(); } boolean expired() { - return cert.expired(); + return option.certRequest().expired(); } String identityName() { - return cert.name(); + return option.certRequest().name(); } CertificateType identityType() { - return cert.type(); + return option.certRequest().type(); } List args() { - return List.of(option, shortName ? cert.shortName() : cert.name()); + return option.asCmdlineArgs(); } static JPackageCommand configureOutputValidation(JPackageCommand cmd, List options, @@ -274,9 +299,6 @@ public class MacSignTest { return cmd; } - private final String option; - private final MacSign.CertificateRequest cert; - private final boolean shortName; - private final boolean passThrough; + private final SignKeyOption option; } } diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java index 37ba8a6c299..0f299cb5a24 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,90 +21,76 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - -import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import jdk.jpackage.test.AdditionalLauncher; -import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSignVerify; /** - * Tests generation of app image with --mac-sign and related arguments. Test will - * generate app image and verify signature of main launcher and app bundle itself. - * This test requires that machine is configured with test certificate for - * "Developer ID Application: jpackage.openjdk.java.net" or alternately - * "Developer ID Application: " + name specified by system property: - * "jpackage.mac.signing.key.user.name" - * in the jpackagerTest keychain (or alternately the keychain specified with - * the system property "jpackage.mac.signing.keychain". - * If this certificate is self-signed, it must have be set to - * always allowed access to this keychain" for user which runs test. - * (If cert is real (not self signed), the do not set trust to allow.) + * Tests signing of an app image. + * + *

+ * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ /* * @test * @summary jpackage with --type app-image --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningAppImageTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningAppImageTest.java * @requires (jpackage.test.MacSignTests == "run") - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTest * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningAppImageTest { @Test - // ({"sign or not", "signing-key or sign-identity", "certificate index"}) - // Sign, signing-key and ASCII certificate - @Parameter({"true", "true", "ASCII_INDEX"}) - // Sign, signing-key and UNICODE certificate - @Parameter({"true", "true", "UNICODE_INDEX"}) - // Sign, signing-indentity and UNICODE certificate - @Parameter({"true", "false", "UNICODE_INDEX"}) - // Unsigned - @Parameter({"false", "true", "INVALID_INDEX"}) - public void test(boolean doSign, boolean signingKey, SigningBase.CertIndex certEnum) throws Exception { - MacSign.withKeychain(toConsumer(keychain -> { - test(keychain, doSign, signingKey, certEnum); - }), SigningBase.StandardKeychain.MAIN.keychain()); - } + @ParameterSupplier + public static void test(SignKeyOptionWithKeychain sign) { - private void test(MacSign.ResolvedKeychain keychain, boolean doSign, boolean signingKey, SigningBase.CertIndex certEnum) throws Exception { - final var certIndex = certEnum.value(); + var cmd = JPackageCommand.helloAppImage(); - JPackageCommand cmd = JPackageCommand.helloAppImage(); - if (doSign) { - cmd.addArguments("--mac-sign", - "--mac-signing-keychain", - keychain.name()); - if (signingKey) { - cmd.addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(certIndex)); - } else { - cmd.addArguments("--mac-app-image-sign-identity", - SigningBase.getAppCert(certIndex)); - } - } - AdditionalLauncher testAL = new AdditionalLauncher("testAL"); + var testAL = new AdditionalLauncher("testAL"); testAL.applyTo(cmd); cmd.executeAndAssertHelloAppImageCreated(); - Path launcherPath = cmd.appLauncherPath(); - SigningBase.verifyCodesign(launcherPath, doSign, certIndex); + MacSign.withKeychain(keychain -> { + sign.addTo(cmd); + cmd.executeAndAssertHelloAppImageCreated(); + MacSignVerify.verifyAppImageSigned(cmd, sign.certRequest()); + }, sign.keychain()); + } - Path testALPath = launcherPath.getParent().resolve("testAL"); - SigningBase.verifyCodesign(testALPath, doSign, certIndex); + public static Collection test() { - Path appImage = cmd.outputBundle(); - SigningBase.verifyCodesign(appImage, doSign, certIndex); - if (doSign) { - SigningBase.verifySpctl(appImage, "exec", certIndex); + List data = new ArrayList<>(); + + for (var certRequest : List.of( + SigningBase.StandardCertificateRequest.CODESIGN, + SigningBase.StandardCertificateRequest.CODESIGN_UNICODE + )) { + for (var signIdentityType : SignKeyOption.Type.defaultValues()) { + data.add(new SignKeyOptionWithKeychain( + signIdentityType, + certRequest, + SigningBase.StandardKeychain.MAIN.keychain())); + } } + + return data.stream().map(v -> { + return new Object[] {v}; + }).toList(); } } diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java index 906734e6a9c..2c7ae205e69 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,38 +21,40 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - -import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; import jdk.jpackage.test.AdditionalLauncher; -import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; /** - * Tests generation of app image and then signs generated app image with --mac-sign - * and related arguments. Test will generate app image and verify signature of main - * launcher and app bundle itself. This test requires that machine is configured with - * test certificate for "Developer ID Application: jpackage.openjdk.java.net" or - * alternately "Developer ID Application: " + name specified by system property: - * "jpackage.mac.signing.key.user.name" in the jpackagerTest keychain - * (or alternately the keychain specified with the system property - * "jpackage.mac.signing.keychain". If this certificate is self-signed, it must - * have be set to always allowed access to this keychain" for user which runs test. - * (If cert is real (not self signed), the do not set trust to allow.) + * Tests signing of a signed/unsigned predefined app image. + * + *

+ * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ /* * @test * @summary jpackage with --type app-image --app-image "appImage" --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningAppImageTwoStepsTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningAppImageTwoStepsTest.java * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTwoStepsTest @@ -61,67 +63,123 @@ import jdk.jpackage.test.TKit; public class SigningAppImageTwoStepsTest { @Test - // ({"sign or not", "signing-key or sign-identity"}) - // Sign and signing-key - @Parameter({"true", "true"}) - // Sign and sign-identity - @Parameter({"true", "false"}) - // Unsigned - @Parameter({"false", "true"}) - public void test(boolean signAppImage, boolean signingKey) throws Exception { - MacSign.withKeychain(toConsumer(keychain -> { - test(keychain, signAppImage, signingKey); - }), SigningBase.StandardKeychain.MAIN.keychain()); + @ParameterSupplier + public static void test(TestSpec spec) { + spec.test(); } - private static void test(MacSign.ResolvedKeychain keychain, boolean signAppImage, boolean signingKey) throws Exception { + public record TestSpec(Optional signAppImage, SignKeyOptionWithKeychain sign) { - Path appimageOutput = TKit.createTempDirectory("appimage"); + public TestSpec { + Objects.requireNonNull(signAppImage); + Objects.requireNonNull(sign); + } - // Generate app image. Signed or unsigned based on test - // parameter. We should able to sign predfined app images - // which are signed or unsigned. - JPackageCommand appImageCmd = JPackageCommand.helloAppImage() - .setArgumentValue("--dest", appimageOutput); - if (signAppImage) { - appImageCmd.addArguments("--mac-sign", - "--mac-signing-keychain", - keychain.name()); - if (signingKey) { - appImageCmd.addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); - } else { - appImageCmd.addArguments("--mac-app-image-sign-identity", - SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + @Override + public String toString() { + return Stream.of( + String.format("app-image=%s", signAppImage.map(Objects::toString).orElse("unsigned")), + sign.toString() + ).collect(Collectors.joining("; ")); + } + + static Builder build() { + return new Builder(); + } + + static class Builder { + + TestSpec create() { + return new TestSpec(Optional.ofNullable(signAppImage), sign); + } + + Builder certRequest(SigningBase.StandardCertificateRequest v) { + certRequest = Objects.requireNonNull(v); + return this; + } + + Builder signIdentityType(SignKeyOption.Type v) { + signIdentityType = Objects.requireNonNull(v); + return this; + } + + Builder sign() { + sign = createSignKeyOption(); + return this; + } + + Builder signAppImage() { + signAppImage = createSignKeyOption(); + return this; + } + + private SignKeyOptionWithKeychain createSignKeyOption() { + return new SignKeyOptionWithKeychain( + signIdentityType, + certRequest, + SigningBase.StandardKeychain.MAIN.keychain()); + } + + private SigningBase.StandardCertificateRequest certRequest = SigningBase.StandardCertificateRequest.CODESIGN; + private SignKeyOption.Type signIdentityType = SignKeyOption.Type.SIGN_KEY_IDENTITY; + + private SignKeyOptionWithKeychain signAppImage; + private SignKeyOptionWithKeychain sign; + } + + void test() { + var appImageCmd = JPackageCommand.helloAppImage() + .setFakeRuntime() + .setArgumentValue("--dest", TKit.createTempDirectory("appimage")); + + // Add an additional launcher + AdditionalLauncher testAL = new AdditionalLauncher("testAL"); + testAL.applyTo(appImageCmd); + + signAppImage.ifPresentOrElse(signOption -> { + MacSign.withKeychain(keychain -> { + signOption.addTo(appImageCmd); + appImageCmd.execute(); + MacSignVerify.verifyAppImageSigned(appImageCmd, signOption.certRequest()); + }, signOption.keychain()); + }, appImageCmd::execute); + + var cmd = new JPackageCommand() + .setPackageType(PackageType.IMAGE) + .addArguments("--app-image", appImageCmd.outputBundle()) + .mutate(sign::addTo); + + cmd.executeAndAssertHelloAppImageCreated(); + MacSignVerify.verifyAppImageSigned(cmd, sign.certRequest()); + } + } + + public static Collection test() { + + List data = new ArrayList<>(); + + for (var appImageSign : withAndWithout(SignKeyOption.Type.SIGN_KEY_IDENTITY)) { + var builder = TestSpec.build(); + appImageSign.ifPresent(signIdentityType -> { + // Sign the input app image bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of the input app image bundle. + builder.signIdentityType(signIdentityType) + .certRequest(SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD) + .signAppImage(); + }); + for (var signIdentityType : SignKeyOption.Type.defaultValues()) { + builder.signIdentityType(signIdentityType) + .certRequest(SigningBase.StandardCertificateRequest.CODESIGN); + data.add(builder.sign().create()); } } - // Add addtional launcher - AdditionalLauncher testAL = new AdditionalLauncher("testAL"); - testAL.applyTo(appImageCmd); + return data.stream().map(v -> { + return new Object[] {v}; + }).toList(); + } - // Generate app image - appImageCmd.executeAndAssertHelloAppImageCreated(); - - // Double check if it is signed or unsigned based on signAppImage - SigningBase.verifyAppImageSignature(appImageCmd, signAppImage, "testAL"); - - // Sign app image - JPackageCommand cmd = new JPackageCommand(); - cmd.setPackageType(PackageType.IMAGE) - .addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath()) - .addArguments("--mac-sign") - .addArguments("--mac-signing-keychain", keychain.name()); - if (signingKey) { - cmd.addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); - } else { - cmd.addArguments("--mac-app-image-sign-identity", - SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); - } - cmd.executeAndAssertImageCreated(); - - // Should be signed app image - SigningBase.verifyAppImageSignature(appImageCmd, true, "testAL"); + private static List> withAndWithout(T value) { + return List.of(Optional.empty(), Optional.of(value)); } } diff --git a/test/jdk/tools/jpackage/macosx/SigningBase.java b/test/jdk/tools/jpackage/macosx/SigningBase.java new file mode 100644 index 00000000000..5f4367e6096 --- /dev/null +++ b/test/jdk/tools/jpackage/macosx/SigningBase.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. + * 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.security.cert.X509Certificate; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; +import jdk.jpackage.test.MacHelper.NamedCertificateRequestSupplier; +import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSign.CertificateRequest; +import jdk.jpackage.test.MacSign.CertificateType; +import jdk.jpackage.test.MacSign.KeychainWithCertsSpec; +import jdk.jpackage.test.MacSign.ResolvedKeychain; +import jdk.jpackage.test.TKit; + + +/* + * @test + * @summary Setup the environment for jpackage macos signing tests. + * Creates required keychains and signing identities. + * Does NOT run any jpackag tests. + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @compile -Xlint:all -Werror SigningBase.java + * @requires (jpackage.test.MacSignTests == "setup") + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningBase.setUp + */ + +/* + * @test + * @summary Tear down the environment for jpackage macos signing tests. + * Deletes required keychains and signing identities. + * Does NOT run any jpackag tests. + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @compile -Xlint:all -Werror SigningBase.java + * @requires (jpackage.test.MacSignTests == "teardown") + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningBase.tearDown + */ + +public class SigningBase { + + public enum StandardCertificateRequest implements NamedCertificateRequestSupplier { + CODESIGN(cert().userName(NAME_ASCII)), + CODESIGN_COPY(cert().days(100).userName(NAME_ASCII)), + CODESIGN_ACME_TECH_LTD(cert().days(100).userName("ACME Technologies Limited (ABC12345)")), + PKG(cert().type(CertificateType.INSTALLER).userName(NAME_ASCII)), + PKG_COPY(cert().type(CertificateType.INSTALLER).days(100).userName(NAME_ASCII)), + CODESIGN_UNICODE(cert().userName(NAME_UNICODE)), + PKG_UNICODE(cert().type(CertificateType.INSTALLER).userName(NAME_UNICODE)), + CODESIGN_EXPIRED(cert().expired().userName("expired jpackage test")), + PKG_EXPIRED(cert().expired().type(CertificateType.INSTALLER).userName("expired jpackage test")); + + StandardCertificateRequest(CertificateRequest.Builder specBuilder) { + this.spec = specBuilder.create(); + } + + @Override + public CertificateRequest certRequest() { + return spec; + } + + private static CertificateRequest.Builder cert() { + return new CertificateRequest.Builder(); + } + + private final CertificateRequest spec; + } + + /** + * Standard keychains used in signing tests. + */ + public enum StandardKeychain { + /** + * The primary keychain with good certificates. + */ + MAIN("jpackagerTest.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_UNICODE, + StandardCertificateRequest.PKG_UNICODE, + StandardCertificateRequest.CODESIGN_ACME_TECH_LTD), + /** + * A keychain with some good and some expired certificates. + */ + EXPIRED("jpackagerTest-expired.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_EXPIRED, + StandardCertificateRequest.PKG_EXPIRED), + /** + * A keychain with duplicated certificates. + */ + DUPLICATE("jpackagerTest-duplicate.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_COPY, + StandardCertificateRequest.PKG_COPY), + ; + + StandardKeychain(String keychainName, StandardCertificateRequest... certs) { + this(keychainName, + certs[0].certRequest(), + Stream.of(certs).skip(1).map(StandardCertificateRequest::certRequest).toArray(CertificateRequest[]::new)); + } + + StandardKeychain(String keychainName, CertificateRequest cert, CertificateRequest... otherCerts) { + final var builder = keychain(keychainName).addCert(cert); + List.of(otherCerts).forEach(builder::addCert); + this.keychain = new ResolvedKeychain(builder.create()); + } + + public ResolvedKeychain keychain() { + return keychain; + } + + public X509Certificate mapCertificateRequest(CertificateRequest certRequest) { + return Objects.requireNonNull(keychain.mapCertificateRequests().get(certRequest)); + } + + public boolean contains(StandardCertificateRequest certRequest) { + return keychain.spec().certificateRequests().contains(certRequest.spec); + } + + private static KeychainWithCertsSpec.Builder keychain(String name) { + return new KeychainWithCertsSpec.Builder().name(name); + } + + private static List signingEnv() { + return Stream.of(values()).map(StandardKeychain::keychain).map(ResolvedKeychain::spec).toList(); + } + + private final ResolvedKeychain keychain; + } + + public static void setUp() { + MacSign.setUp(StandardKeychain.signingEnv()); + } + + public static void tearDown() { + MacSign.tearDown(StandardKeychain.signingEnv()); + } + + public static void verifySignTestEnvReady() { + if (!Inner.SIGN_ENV_READY) { + TKit.throwSkippedException(new IllegalStateException("Misconfigured signing test environment")); + } + } + + private final class Inner { + private static final boolean SIGN_ENV_READY = MacSign.isDeployed(StandardKeychain.signingEnv()); + } + + private static final String NAME_ASCII = "jpackage.openjdk.java.net"; + private static final String NAME_UNICODE = "jpackage.openjdk.java.net (รถ)"; +} diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index b1e9155dacb..8a93ce5f749 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,180 +21,247 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - -import java.nio.file.Path; -import jdk.jpackage.test.Annotations.Parameter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.SequencedSet; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.ApplicationLayout; -import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; +import jdk.jpackage.test.MacHelper.SignKeyOption; import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; /** - * Tests generation of dmg and pkg with --mac-sign and related arguments. - * Test will generate pkg and verifies its signature. It verifies that dmg - * is not signed, but app image inside dmg is signed. This test requires that - * the machine is configured with test certificate for - * "Developer ID Installer: jpackage.openjdk.java.net" in - * jpackagerTest keychain with - * always allowed access to this keychain for user which runs test. - * note: - * "jpackage.openjdk.java.net" can be over-ridden by system property - * "jpackage.mac.signing.key.user.name", and - * "jpackagerTest" can be over-ridden by system property - * "jpackage.mac.signing.keychain" + * Tests bundling of .pkg and .dmg packages with various signing options. + * + *

+ * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ + /* * @test * @summary jpackage with --type pkg,dmg --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base * @key jpackagePlatformPackage - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningPackageTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningPackageTest.java * @requires (jpackage.test.MacSignTests == "run") * @requires (jpackage.test.SQETest != null) * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningPackageTest - * --jpt-space-subst=* - * --jpt-include=SigningPackageTest.test(true,*true,*true,*ASCII_INDEX) - * --jpt-before-run=SigningBase.verifySignTestEnvReady + * --jpt-run=SigningPackageTest.test + * --jpt-space-subst=* + * --jpt-include=({--mac-signing-key-user-name:*CODESIGN},*{--mac-signing-key-user-name:*PKG},*MAC_DMG+MAC_PKG) + * --jpt-before-run=SigningBase.verifySignTestEnvReady */ /* * @test * @summary jpackage with --type pkg,dmg --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base * @key jpackagePlatformPackage - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningPackageTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningPackageTest.java * @requires (jpackage.test.MacSignTests == "run") * @requires (jpackage.test.SQETest == null) - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningPackageTest + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningPackageTest.test * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningPackageTest { - private static boolean isAppImageSigned(JPackageCommand cmd) { - return cmd.hasArgument("--mac-signing-key-user-name") || - cmd.hasArgument("--mac-app-image-sign-identity"); + @Test + @ParameterSupplier + public static void test(TestSpec spec) { + MacSign.withKeychain(_ -> { + spec.test(); + }, spec.keychain()); } - private static boolean isPKGSigned(JPackageCommand cmd) { - return cmd.hasArgument("--mac-signing-key-user-name") || - cmd.hasArgument("--mac-installer-sign-identity"); + public static Collection test() { + return TestSpec.testCases(true).stream().map(v -> { + return new Object[] {v}; + }).toList(); } - private static void verifyPKG(JPackageCommand cmd) { - Path outputBundle = cmd.outputBundle(); - SigningBase.verifyPkgutil(outputBundle, isPKGSigned(cmd), getCertIndex(cmd)); - if (isPKGSigned(cmd)) { - SigningBase.verifySpctl(outputBundle, "install", getCertIndex(cmd)); - } - } + record TestSpec( + Optional appImageSignOption, + Optional packageSignOption, + Set packageTypes) { - private static void verifyDMG(JPackageCommand cmd) { - Path outputBundle = cmd.outputBundle(); - SigningBase.verifyDMG(outputBundle); - } + TestSpec { + Objects.requireNonNull(appImageSignOption); + Objects.requireNonNull(packageSignOption); + Objects.requireNonNull(packageTypes); - private static void verifyAppImageInDMG(JPackageCommand cmd) { - MacHelper.withExplodedDmg(cmd, dmgImage -> { - Path launcherPath = ApplicationLayout.platformAppImage() - .resolveAt(dmgImage).launchersDirectory().resolve(cmd.name()); - // We will be called with all folders in DMG since JDK-8263155, but - // we only need to verify app. - if (dmgImage.endsWith(cmd.name() + ".app")) { - SigningBase.verifyCodesign(launcherPath, isAppImageSigned(cmd), - getCertIndex(cmd)); - SigningBase.verifyCodesign(dmgImage, isAppImageSigned(cmd), - getCertIndex(cmd)); - if (isAppImageSigned(cmd)) { - SigningBase.verifySpctl(dmgImage, "exec", getCertIndex(cmd)); + if (appImageSignOption.isEmpty() && packageSignOption.isEmpty()) { + // No signing. + throw new IllegalArgumentException(); + } + + if (packageTypes.isEmpty() || !PackageType.MAC.containsAll(packageTypes)) { + // Invalid package types. + throw new IllegalArgumentException(); + } + + if (packageSignOption.isPresent()) { + if (!packageTypes.contains(PackageType.MAC_PKG)) { + // .pkg installer should be signed, but .pkg type is missing. + throw new IllegalArgumentException(); + } + + if (appImageSignOption.isEmpty()) { + if (packageSignOption.get().type() != SignKeyOption.Type.SIGN_KEY_IDENTITY) { + // They request to sign the .pkg installer without + // the "--mac-installer-sign-identity" option, + // but didn't specify a signing option for the packaged app image. + // This is wrong because only the "--mac-installer-sign-identity" option + // allows signing a .pkg installer without signing its packaged app image. + throw new IllegalArgumentException(); + } + } else if (appImageSignOption.get().type() != packageSignOption.get().type()) { + // Signing option types should be the same. + throw new IllegalArgumentException(); } } - }); - } - private static int getCertIndex(JPackageCommand cmd) { - if (cmd.hasArgument("--mac-signing-key-user-name")) { - String devName = cmd.getArgumentValue("--mac-signing-key-user-name"); - return SigningBase.getDevNameIndex(devName); - } else { - // Signing-indentity - return SigningBase.CertIndex.UNICODE_INDEX.value(); + if (!(packageTypes instanceof SequencedSet)) { + packageTypes = new TreeSet<>(packageTypes); + } + } + + TestSpec( + Optional appImageSignOption, + Optional packageSignOption, + PackageType... packageTypes) { + this(appImageSignOption, packageSignOption, Set.of(packageTypes)); + } + + @Override + public String toString() { + return Stream.of( + signKeyOptions(), + Stream.of(packageTypes.stream().map(Object::toString).collect(Collectors.joining("+"))) + ).flatMap(x -> x).map(Object::toString).collect(Collectors.joining(", ")); + } + + Stream signKeyOptions() { + return Stream.concat(appImageSignOption.stream(), packageSignOption.stream()); + } + + Optional bundleSignIdentity(PackageType type) { + switch (type) { + case MAC_DMG -> { + return Optional.empty(); + } + case MAC_PKG -> { + return packageSignOption.map(SignKeyOption::certRequest); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + + void test() { + initTest().configureHelloApp().addInstallVerifier(cmd -> { + appImageSignOption.map(SignKeyOption::certRequest).ifPresent(signIdentity -> { + MacSignVerify.verifyAppImageSigned(cmd, signIdentity); + }); + }).run(); + } + + PackageTest initTest() { + return new PackageTest().forTypes(packageTypes).mutate(test -> { + appImageSignOption.ifPresent(signOption -> { + test.addInitializer(signOption::setTo); + }); + packageSignOption.ifPresent(signOption -> { + test.forTypes(PackageType.MAC_PKG, () -> { + test.addInitializer(signOption::setTo); + }); + }); + }).addBundleVerifier(cmd -> { + bundleSignIdentity(cmd.packageType()).ifPresent(signIdentity -> { + MacSignVerify.verifyPkgSigned(cmd, signIdentity); + }); + }).addInitializer(MacHelper.useKeychain(keychain())::accept); + } + + MacSign.ResolvedKeychain keychain() { + return SigningBase.StandardKeychain.MAIN.keychain(); + } + + static List testCases(boolean withUnicode) { + + List data = new ArrayList<>(); + + List> certRequestGroups; + if (withUnicode) { + certRequestGroups = List.of( + List.of(SigningBase.StandardCertificateRequest.CODESIGN, SigningBase.StandardCertificateRequest.PKG), + List.of(SigningBase.StandardCertificateRequest.CODESIGN_UNICODE, SigningBase.StandardCertificateRequest.PKG_UNICODE) + ); + } else { + certRequestGroups = List.of( + List.of(SigningBase.StandardCertificateRequest.CODESIGN, SigningBase.StandardCertificateRequest.PKG) + ); + } + + for (var certRequests : certRequestGroups) { + for (var signIdentityType : SignKeyOption.Type.defaultValues()) { + var keychain = SigningBase.StandardKeychain.MAIN.keychain(); + var appImageSignKeyOption = new SignKeyOption(signIdentityType, certRequests.getFirst(), keychain); + var pkgSignKeyOption = new SignKeyOption(signIdentityType, certRequests.getLast(), keychain); + + switch (signIdentityType) { + case SIGN_KEY_IDENTITY -> { + // Use "--mac-installer-sign-identity" and "--mac-app-image-sign-identity" signing options. + // They allows to sign the packaged app image and the installer (.pkg) separately. + data.add(new TestSpec(Optional.of(appImageSignKeyOption), Optional.empty(), PackageType.MAC)); + data.add(new TestSpec(Optional.empty(), Optional.of(pkgSignKeyOption), PackageType.MAC_PKG)); + } + case SIGN_KEY_USER_SHORT_NAME -> { + // Use "--mac-signing-key-user-name" signing option with short user name or implicit signing option. + // It signs both the packaged app image and the installer (.pkg). + // Thus, if the installer is not signed, it can be used only with .dmg packaging. + data.add(new TestSpec(Optional.of(appImageSignKeyOption), Optional.empty(), PackageType.MAC_DMG)); + } + case SIGN_KEY_USER_FULL_NAME -> { + // Use "--mac-signing-key-user-name" signing option with the full user name. + // Like SIGN_KEY_USER_SHORT_NAME, jpackage will try to use it to sign both + // the packaged app image and the installer (.pkg). + // It will fail to sign the installer, though, because the signing identity is unsuitable. + // That is why, use it with .dmg packaging only and not with .pkg packaging. + data.add(new TestSpec(Optional.of(appImageSignKeyOption), Optional.empty(), PackageType.MAC_DMG)); + continue; + } + default -> { + // SignKeyOption.Type.defaultValues() should return + // such a sequence that makes this code location unreachable. + throw ExceptionBox.reachedUnreachable(); + } + } + data.add(new TestSpec(Optional.of(appImageSignKeyOption), Optional.of(pkgSignKeyOption), PackageType.MAC)); + } + } + + return data; } } - - @Test - // ("signing-key or sign-identity", "sign app-image", "sign pkg", "certificate index"}) - // Signing-key and ASCII certificate - @Parameter({"true", "true", "true", "ASCII_INDEX"}) - // Signing-key and UNICODE certificate - @Parameter({"true", "true", "true", "UNICODE_INDEX"}) - // Signing-indentity and UNICODE certificate - @Parameter({"false", "true", "true", "UNICODE_INDEX"}) - // Signing-indentity, but sign app-image only and UNICODE certificate - @Parameter({"false", "true", "false", "UNICODE_INDEX"}) - // Signing-indentity, but sign pkg only and UNICODE certificate - @Parameter({"false", "false", "true", "UNICODE_INDEX"}) - public static void test(boolean signingKey, boolean signAppImage, boolean signPKG, SigningBase.CertIndex certEnum) throws Exception { - MacSign.withKeychain(toConsumer(keychain -> { - test(keychain, signingKey, signAppImage, signPKG, certEnum); - }), SigningBase.StandardKeychain.MAIN.keychain()); - } - - private static void test(MacSign.ResolvedKeychain keychain, boolean signingKey, boolean signAppImage, boolean signPKG, SigningBase.CertIndex certEnum) throws Exception { - final var certIndex = certEnum.value(); - - new PackageTest() - .configureHelloApp() - .forTypes(PackageType.MAC) - .addInitializer(cmd -> { - cmd.addArguments("--mac-sign", - "--mac-signing-keychain", keychain.name()); - if (signingKey) { - cmd.addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(certIndex)); - } else { - if (signAppImage) { - cmd.addArguments("--mac-app-image-sign-identity", - SigningBase.getAppCert(certIndex)); - } - if (signPKG) { - cmd.addArguments("--mac-installer-sign-identity", - SigningBase.getInstallerCert(certIndex)); - } - } - }) - .forTypes(PackageType.MAC_PKG) - .addBundleVerifier(SigningPackageTest::verifyPKG) - .forTypes(PackageType.MAC_DMG) - .addInitializer(cmd -> { - if (!signingKey) { - // jpackage throws expected error with - // --mac-installer-sign-identity and DMG type - cmd.removeArgumentWithValue("--mac-installer-sign-identity"); - // In case of not signing app image and DMG we need to - // remove signing completely, otherwise we will default - // to --mac-signing-key-user-name once - // --mac-installer-sign-identity is removed. - if (!signAppImage) { - cmd.removeArgumentWithValue("--mac-signing-keychain"); - cmd.removeArgument("--mac-sign"); - } - } - }) - .addBundleVerifier(SigningPackageTest::verifyDMG) - .addBundleVerifier(SigningPackageTest::verifyAppImageInDMG) - .run(); - } } diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java index 586d8d68444..70ec0e600de 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,25 +21,22 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; - import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.SortedMap; -import java.util.TreeMap; +import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; -import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageFile; @@ -52,22 +49,23 @@ import jdk.jpackage.test.TKit; * signed/unsigned .pkg or .dmg package. * *

- * Prerequisites: A keychain with self-signed certificates as specified in - * {@link SigningBase.StandardKeychain#MAIN}. + * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ /* * @test * @summary jpackage with --type pkg,dmg --app-image * @library /test/jdk/tools/jpackage/helpers - * @library base * @key jpackagePlatformPackage - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningPackageTwoStepTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningPackageTest.java + * @compile -Xlint:all -Werror SigningPackageTwoStepTest.java * @requires (jpackage.test.MacSignTests == "run") * @requires (jpackage.test.SQETest == null) - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageTwoStepTest * --jpt-before-run=SigningBase.verifySignTestEnvReady */ @@ -75,176 +73,148 @@ public class SigningPackageTwoStepTest { @Test @ParameterSupplier - public static void test(TestSpec spec) { - MacSign.withKeychain(toConsumer(keychain -> { - spec.test(keychain); - }), SigningBase.StandardKeychain.MAIN.keychain()); + public static void test(TwoStepsTestSpec spec) { + spec.test(); } - public record TestSpec(Optional signAppImage, Map signPackage) { + @Test + public static void testBundleSignedAppImage() { - public TestSpec { - Objects.requireNonNull(signAppImage); - Objects.requireNonNull(signPackage); + var appImageCmd = JPackageCommand.helloAppImage(); - if ((signAppImage.isEmpty() && signPackage.isEmpty()) || !PackageType.MAC.containsAll(signPackage.keySet())) { - // Unexpected package types. - throw new IllegalArgumentException(); - } + var predefinedAppImageSignOption = predefinedAppImageSignOption(); - // Ensure stable result of toString() call. - if (!SortedMap.class.isInstance(signPackage)) { - signPackage = new TreeMap<>(signPackage); - } - } - - @Override - public String toString() { - var sb = new StringBuilder(); - - signAppImage.ifPresent(signOption -> { - sb.append(String.format("app-image=%s", signOption)); - }); - - if (!sb.isEmpty() && !signPackage.isEmpty()) { - sb.append("; "); - } - - if (!signPackage.isEmpty()) { - sb.append(signPackage); - } - - return sb.toString(); - } - - boolean signNativeBundle() { - return signPackage.isEmpty(); - } - - static Builder build() { - return new Builder(); - } - - static class Builder { - - TestSpec create() { - return new TestSpec(Optional.ofNullable(signAppImage), signPackage); - } - - Builder certRequest(SigningBase.StandardCertificateRequest v) { - return certRequest(v.spec()); - } - - Builder certRequest(MacSign.CertificateRequest v) { - certRequest = Objects.requireNonNull(v); - return this; - } - - Builder signIdentityType(SignKeyOption.Type v) { - signIdentityType = Objects.requireNonNull(v); - return this; - } - - Builder signAppImage() { - signAppImage = createSignKeyOption(); - return this; - } - - Builder signPackage(PackageType type) { - Objects.requireNonNull(type); - signPackage.put(type, createSignKeyOption()); - return this; - } - - Builder signPackage() { - PackageType.MAC.forEach(this::signPackage); - return this; - } - - private SignKeyOption createSignKeyOption() { - return new SignKeyOption(signIdentityType, certRequest); - } - - private MacSign.CertificateRequest certRequest = SigningBase.StandardCertificateRequest.CODESIGN.spec(); - private SignKeyOption.Type signIdentityType = SignKeyOption.Type.SIGN_KEY_IDENTITY; - - private SignKeyOption signAppImage; - private Map signPackage = new HashMap<>(); - } - - void test(MacSign.ResolvedKeychain keychain) { - - var appImageCmd = JPackageCommand.helloAppImage().setFakeRuntime(); - MacHelper.useKeychain(appImageCmd, keychain); - signAppImage.ifPresent(signOption -> { - signOption.setTo(appImageCmd); - }); - - var test = new PackageTest(); - - signAppImage.map(SignKeyOption::certRequest).ifPresent(certRequest -> { - // The predefined app image is signed, verify bundled app image is signed too. - test.addInstallVerifier(cmd -> { - MacSignVerify.verifyAppImageSigned(cmd, certRequest, keychain); - }); - }); - - Optional.ofNullable(signPackage.get(PackageType.MAC_PKG)).map(SignKeyOption::certRequest).ifPresent(certRequest -> { - test.forTypes(PackageType.MAC_PKG, () -> { - test.addBundleVerifier(cmd -> { - MacSignVerify.verifyPkgSigned(cmd, certRequest, keychain); - }); - }); - }); - - test.forTypes(signPackage.keySet()).addRunOnceInitializer(() -> { - appImageCmd.setArgumentValue("--dest", TKit.createTempDirectory("appimage")).execute(0); - }).usePredefinedAppImage(appImageCmd).addInitializer(cmd -> { - MacHelper.useKeychain(cmd, keychain); - Optional.ofNullable(signPackage.get(cmd.packageType())).ifPresent(signOption -> { - signOption.setTo(cmd); - }); - - if (signAppImage.isPresent()) { - // Predefined app image is signed. Expect a warning. - cmd.validateOutput(JPackageStringBundle.MAIN.cannedFormattedString( - "warning.per.user.app.image.signed", - PackageFile.getPathInAppImage(Path.of("")))); - } else if (cmd.packageType() == PackageType.MAC_PKG && signPackage.containsKey(cmd.packageType())) { - // Create signed ".pkg" bundle from the unsigned predefined app image. Expect a warning. - cmd.validateOutput(JPackageStringBundle.MAIN.cannedFormattedString("warning.unsigned.app.image", "pkg")); - } - }) - .run(); - } + new PackageTest().addRunOnceInitializer(() -> { + createPredefinedAppImage(appImageCmd, Optional.of(predefinedAppImageSignOption)); + }).usePredefinedAppImage(appImageCmd).addInitializer(cmd -> { + configureOutputValidator(cmd, true, false); + }).addInstallVerifier(cmd -> { + MacSignVerify.verifyAppImageSigned(cmd, predefinedAppImageSignOption.certRequest()); + }).run(); } public static Collection test() { - List data = new ArrayList<>(); + List data = new ArrayList<>(); - Stream.of(SignKeyOption.Type.values()).flatMap(signIdentityType -> { - return Stream.of( - // Sign both predefined app image and native package. - TestSpec.build().signIdentityType(signIdentityType) - .signAppImage() - .signPackage() - .certRequest(SigningBase.StandardCertificateRequest.PKG) - .signPackage(PackageType.MAC_PKG), + for (var signAppImage : List.of(true, false)) { + Optional appImageSignOption; + if (signAppImage) { + // Sign the predefined app image bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of + // the predefined app image bundle when backing it in the pkg or dmg installer. + appImageSignOption = Optional.of(predefinedAppImageSignOption()); + } else { + appImageSignOption = Optional.empty(); + } - // Don't sign predefined app image, sign native package. - TestSpec.build().signIdentityType(signIdentityType) - .signPackage() - .certRequest(SigningBase.StandardCertificateRequest.PKG) - .signPackage(PackageType.MAC_PKG), + for (var signPackage : SigningPackageTest.TestSpec.testCases(false)) { + data.add(new TwoStepsTestSpec(appImageSignOption, signPackage)); + } + } - // Sign predefined app image, don't sign native package. - TestSpec.build().signIdentityType(signIdentityType).signAppImage() - ); - }).forEach(data::add); - - return data.stream().map(TestSpec.Builder::create).map(v -> { + return data.stream().map(v -> { return new Object[] {v}; }).toList(); } + + record TwoStepsTestSpec(Optional signAppImage, SigningPackageTest.TestSpec signPackage) { + + TwoStepsTestSpec { + Objects.requireNonNull(signAppImage); + Objects.requireNonNull(signPackage); + } + + @Override + public String toString() { + return Stream.of( + String.format("app-image=%s", signAppImage.map(Objects::toString).orElse("unsigned")), + signPackage.toString() + ).collect(Collectors.joining("; ")); + } + + Optional packagedAppImageSignIdentity() { + return signAppImage.map(SignKeyOptionWithKeychain::certRequest); + } + + void test() { + + var appImageCmd = JPackageCommand.helloAppImage(); + + var test = signPackage.initTest().addRunOnceInitializer(() -> { + createPredefinedAppImage(appImageCmd, signAppImage); + }).usePredefinedAppImage(appImageCmd).addInitializer(cmd -> { + configureOutputValidator(cmd, + signAppImage.isPresent(), + (cmd.packageType() == PackageType.MAC_PKG) && signPackage.packageSignOption().isPresent()); + }).addInstallVerifier(cmd -> { + packagedAppImageSignIdentity().ifPresent(certRequest -> { + MacSignVerify.verifyAppImageSigned(cmd, certRequest); + }); + }); + + MacSign.withKeychain(_ -> { + test.run(); + }, signPackage.keychain()); + } + } + + private static SignKeyOptionWithKeychain predefinedAppImageSignOption() { + // Sign the predefined app image bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of the input app image bundle. + return new SignKeyOptionWithKeychain( + SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME, + SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD, + SigningBase.StandardKeychain.MAIN.keychain()); + } + + private static void createPredefinedAppImage(JPackageCommand appImageCmd, Optional signAppImage) { + Objects.requireNonNull(appImageCmd); + Objects.requireNonNull(signAppImage); + + appImageCmd.setFakeRuntime().setArgumentValue("--dest", TKit.createTempDirectory("appimage")); + + signAppImage.ifPresentOrElse(signOption -> { + signOption.setTo(appImageCmd); + + MacSign.withKeychain(_ -> { + appImageCmd.execute(0); + }, signOption.keychain()); + + // Verify that the predefined app image is signed. + MacSignVerify.verifyAppImageSigned(appImageCmd, signOption.certRequest()); + }, () -> { + appImageCmd.execute(0); + }); + } + + private static void configureOutputValidator(JPackageCommand cmd, boolean signAppImage, boolean signPackage) { + var signedPredefinedAppImageWarning = JPackageStringBundle.MAIN.cannedFormattedString( + "warning.per.user.app.image.signed", + PackageFile.getPathInAppImage(Path.of(""))); + + var signedInstallerFromUnsignedPredefinedAppImageWarning = + JPackageStringBundle.MAIN.cannedFormattedString("warning.unsigned.app.image", "pkg"); + + // The warnings are mutually exclusive + final Optional expected; + final List unexpected = new ArrayList<>(); + + if (signAppImage) { + expected = Optional.of(signedPredefinedAppImageWarning); + } else { + unexpected.add(signedPredefinedAppImageWarning); + if (signPackage) { + expected = Optional.of(signedInstallerFromUnsignedPredefinedAppImageWarning); + } else { + expected = Optional.empty(); + unexpected.add(signedInstallerFromUnsignedPredefinedAppImageWarning); + } + } + + expected.ifPresent(cmd::validateOutput); + unexpected.forEach(str -> { + cmd.validateOutput(TKit.assertTextStream(cmd.getValue(str)).negate()); + }); + } } diff --git a/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java b/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java index ccc39f7a367..604399ebd7a 100644 --- a/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +21,31 @@ * questions. */ -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import static jdk.jpackage.test.JPackageCommand.RuntimeImageType.RUNTIME_TYPE_FAKE; import java.nio.file.Path; -import java.util.function.Predicate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.internal.util.MacBundle; +import jdk.jpackage.internal.util.Slot; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacHelper.ResolvableCertificateRequest; +import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSignVerify; +import jdk.jpackage.test.MacSignVerify.SpctlType; import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.TKit; /** * Tests generation of dmg and pkg with --mac-sign and related arguments. Test @@ -43,126 +57,182 @@ import jdk.jpackage.test.PackageTest; * app image signing and it will be covered by SigningPackageTest. * *

- * Following combinations are tested: - *

    - *
  1. "--runtime-image" points to unsigned JDK bundle and --mac-sign is not - * provided. Expected result: runtime image ad-hoc signed. - *
  2. "--runtime-image" points to unsigned JDK bundle and --mac-sign is - * provided. Expected result: Everything is signed with provided certificate. - *
  3. "--runtime-image" points to signed JDK bundle and --mac-sign is not - * provided. Expected result: runtime image is signed with original certificate. - *
  4. "--runtime-image" points to signed JDK bundle and --mac-sign is provided. - * Expected result: runtime image is signed with provided certificate. - *
  5. "--runtime-image" points to JDK image and --mac-sign is not provided. - * Expected result: runtime image ad-hoc signed. - *
  6. "--runtime-image" points to JDK image and --mac-sign is provided. - * Expected result: Everything is signed with provided certificate. - *
- * - * This test requires that the machine is configured with test certificate for - * "Developer ID Installer: jpackage.openjdk.java.net" in jpackagerTest keychain - * with always allowed access to this keychain for user which runs test. note: - * "jpackage.openjdk.java.net" can be over-ridden by system property - * "jpackage.mac.signing.key.user.name" + * Prerequisites: Keychains with self-signed certificates as specified in + * {@link SigningBase.StandardKeychain#MAIN} and + * {@link SigningBase.StandardKeychain#SINGLE}. */ /* * @test * @summary jpackage with --type pkg,dmg --runtime-image --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library base * @key jpackagePlatformPackage - * @build SigningBase * @build jdk.jpackage.test.* - * @build SigningRuntimeImagePackageTest + * @compile -Xlint:all -Werror SigningBase.java + * @compile -Xlint:all -Werror SigningPackageTest.java + * @compile -Xlint:all -Werror SigningRuntimeImagePackageTest.java * @requires (jpackage.test.MacSignTests == "run") * @requires (jpackage.test.SQETest == null) - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningRuntimeImagePackageTest * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningRuntimeImagePackageTest { - private static JPackageCommand addSignOptions(JPackageCommand cmd, MacSign.ResolvedKeychain keychain, int certIndex) { - if (certIndex != SigningBase.CertIndex.INVALID_INDEX.value()) { - cmd.addArguments( - "--mac-sign", - "--mac-signing-keychain", keychain.name(), - "--mac-signing-key-user-name", SigningBase.getDevName(certIndex)); - } - return cmd; - } - - private static Path createInputRuntimeBundle(MacSign.ResolvedKeychain keychain, int certIndex) { - return MacHelper.createRuntimeBundle(cmd -> { - addSignOptions(cmd, keychain, certIndex); - }); + @Test + @ParameterSupplier + public static void test(RuntimeTestSpec spec) { + spec.test(); } @Test - // useJDKBundle - If "true" predefined runtime image will be converted to - // JDK bundle. If "false" JDK image will be used. - // JDKBundleCert - Certificate to sign JDK bundle before calling jpackage. - // signCert - Certificate to sign bundle produced by jpackage. - // 1) unsigned JDK bundle and --mac-sign is not provided - @Parameter({"true", "INVALID_INDEX", "INVALID_INDEX"}) - // 2) unsigned JDK bundle and --mac-sign is provided - @Parameter({"true", "INVALID_INDEX", "ASCII_INDEX"}) - // 3) signed JDK bundle and --mac-sign is not provided - @Parameter({"true", "UNICODE_INDEX", "INVALID_INDEX"}) - // 4) signed JDK bundle and --mac-sign is provided - @Parameter({"true", "UNICODE_INDEX", "ASCII_INDEX"}) - // 5) JDK image and --mac-sign is not provided - @Parameter({"false", "INVALID_INDEX", "INVALID_INDEX"}) - // 6) JDK image and --mac-sign is provided - @Parameter({"false", "INVALID_INDEX", "ASCII_INDEX"}) - public static void test(boolean useJDKBundle, - SigningBase.CertIndex jdkBundleCert, - SigningBase.CertIndex signCert) throws Exception { - MacSign.withKeychain(toConsumer(keychain -> { - test(keychain, useJDKBundle, jdkBundleCert, signCert); - }), SigningBase.StandardKeychain.MAIN.keychain()); + public static void testBundleSignedRuntime() { + + Slot predefinedRuntime = Slot.createEmpty(); + + var signRuntime = runtimeImageSignOption(); + + new PackageTest().addRunOnceInitializer(() -> { + predefinedRuntime.set(createRuntime(Optional.of(signRuntime), RuntimeType.BUNDLE)); + }).addInitializer(cmd -> { + cmd.ignoreDefaultRuntime(true); + cmd.removeArgumentWithValue("--input"); + cmd.setArgumentValue("--runtime-image", predefinedRuntime.get()); + }).addInstallVerifier(cmd -> { + MacSignVerify.verifyAppImageSigned(cmd, signRuntime.certRequest()); + }).run(); } - private static void test(MacSign.ResolvedKeychain keychain, boolean useJDKBundle, - SigningBase.CertIndex jdkBundleCert, - SigningBase.CertIndex signCert) throws Exception { + public static Collection test() { - final Path inputRuntime[] = new Path[1]; + List data = new ArrayList<>(); - new PackageTest() - .addRunOnceInitializer(() -> { - if (useJDKBundle) { - inputRuntime[0] = createInputRuntimeBundle(keychain, jdkBundleCert.value()); - } else { - inputRuntime[0] = JPackageCommand.createInputRuntimeImage(); - } - }) - .addInitializer(cmd -> { - cmd.addArguments("--runtime-image", inputRuntime[0]); - // Remove --input parameter from jpackage command line as we don't - // create input directory in the test and jpackage fails - // if --input references non existent directory. - cmd.removeArgumentWithValue("--input"); - addSignOptions(cmd, keychain, signCert.value()); - }) - .addInstallVerifier(cmd -> { - final var certIndex = Stream.of(signCert, jdkBundleCert) - .filter(Predicate.isEqual(SigningBase.CertIndex.INVALID_INDEX).negate()) - .findFirst().orElse(SigningBase.CertIndex.INVALID_INDEX).value(); + for (var runtimeSpec : List.of( + Map.entry(RuntimeType.IMAGE, false /* unsigned */), + Map.entry(RuntimeType.BUNDLE, false /* unsigned */), + Map.entry(RuntimeType.BUNDLE, true /* signed */) + )) { + var runtimeType = runtimeSpec.getKey(); + var signRuntime = runtimeSpec.getValue(); - final var signed = certIndex != SigningBase.CertIndex.INVALID_INDEX.value(); + Optional runtimeSignOption; + if (signRuntime) { + // Sign the runtime bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of + // the predefined runtime bundle when backing it in the pkg or dmg installer. + runtimeSignOption = Optional.of(runtimeImageSignOption()); + } else { + runtimeSignOption = Optional.empty(); + } - final var unfoldedBundleDir = cmd.appRuntimeDirectory(); + for (var signPackage : SigningPackageTest.TestSpec.testCases(false)) { + data.add(new RuntimeTestSpec(runtimeSignOption, runtimeType, signPackage)); + } + } - final var libjli = unfoldedBundleDir.resolve("Contents/MacOS/libjli.dylib"); + return data.stream().map(v -> { + return new Object[] {v}; + }).toList(); + } - SigningBase.verifyCodesign(libjli, signed, certIndex); - SigningBase.verifyCodesign(unfoldedBundleDir, signed, certIndex); - if (signed) { - SigningBase.verifySpctl(unfoldedBundleDir, "exec", certIndex); - } - }) - .run(); + enum RuntimeType { + IMAGE, + BUNDLE, + ; + } + + record RuntimeTestSpec( + Optional signRuntime, + RuntimeType runtimeType, + SigningPackageTest.TestSpec signPackage) { + + RuntimeTestSpec { + Objects.requireNonNull(signRuntime); + Objects.requireNonNull(runtimeType); + Objects.requireNonNull(signPackage); + } + + @Override + public String toString() { + var runtimeToken = new StringBuilder(); + runtimeToken.append("runtime={").append(runtimeType); + signRuntime.ifPresent(v -> { + runtimeToken.append(", ").append(v); + }); + runtimeToken.append('}'); + return Stream.of(runtimeToken, signPackage).map(Objects::toString).collect(Collectors.joining("; ")); + } + + Optional packagedAppImageSignIdentity() { + if (runtimeType == RuntimeType.IMAGE) { + return signPackage.appImageSignOption().map(SignKeyOption::certRequest); + } else { + return signPackage.appImageSignOption().or(() -> { + return signRuntime.map(SignKeyOptionWithKeychain::signKeyOption); + }).map(SignKeyOption::certRequest); + } + } + + void test() { + + Slot predefinedRuntime = Slot.createEmpty(); + + var test = signPackage.initTest().addRunOnceInitializer(() -> { + predefinedRuntime.set(createRuntime(signRuntime, runtimeType)); + }).addInitializer(cmd -> { + cmd.ignoreDefaultRuntime(true); + cmd.removeArgumentWithValue("--input"); + cmd.setArgumentValue("--runtime-image", predefinedRuntime.get()); + }).addInstallVerifier(cmd -> { + packagedAppImageSignIdentity().ifPresent(certRequest -> { + MacSignVerify.verifyAppImageSigned(cmd, certRequest); + }); + }); + + MacSign.withKeychain(_ -> { + test.run(); + }, signPackage.keychain()); + } + } + + private static SignKeyOptionWithKeychain runtimeImageSignOption() { + // Sign the runtime bundle with the key not used in the jpackage command line being tested. + // This way we can test if jpackage keeps or replaces the signature of + // the predefined runtime bundle when backing it in the pkg or dmg installer. + return new SignKeyOptionWithKeychain( + SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME, + SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD, + SigningBase.StandardKeychain.MAIN.keychain()); + } + + private static Path createRuntime(Optional signRuntime, RuntimeType runtimeType) { + if (runtimeType == RuntimeType.IMAGE && signRuntime.isEmpty()) { + return JPackageCommand.createInputRuntimeImage(RUNTIME_TYPE_FAKE); + } else { + Slot runtimeBundle = Slot.createEmpty(); + + MacSign.withKeychain(keychain -> { + var runtimeBundleBuilder = MacHelper.buildRuntimeBundle(); + signRuntime.ifPresent(signingOption -> { + runtimeBundleBuilder.mutator(signingOption::setTo); + }); + runtimeBundle.set(runtimeBundleBuilder.type(RUNTIME_TYPE_FAKE).create()); + }, SigningBase.StandardKeychain.MAIN.keychain()); + + if (runtimeType == RuntimeType.IMAGE) { + return MacBundle.fromPath(runtimeBundle.get()).orElseThrow().homeDir(); + } else { + // Verify the runtime bundle is properly signed/unsigned. + signRuntime.map(SignKeyOptionWithKeychain::certRequest).ifPresentOrElse(certRequest -> { + MacSignVerify.assertSigned(runtimeBundle.get(), certRequest); + var signOrigin = MacSignVerify.findSpctlSignOrigin(SpctlType.EXEC, runtimeBundle.get()).orElse(null); + TKit.assertEquals(certRequest.name(), signOrigin, + String.format("Check [%s] has sign origin as expected", runtimeBundle.get())); + }, () -> { + MacSignVerify.assertAdhocSigned(runtimeBundle.get()); + }); + return runtimeBundle.get(); + } + } } } diff --git a/test/jdk/tools/jpackage/macosx/base/SigningBase.java b/test/jdk/tools/jpackage/macosx/base/SigningBase.java deleted file mode 100644 index b1a709c9cf0..00000000000 --- a/test/jdk/tools/jpackage/macosx/base/SigningBase.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * 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 - * 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.nio.file.Path; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; -import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.MacSign; -import jdk.jpackage.test.MacSign.CertificateRequest; -import jdk.jpackage.test.MacSign.CertificateType; -import jdk.jpackage.test.MacSign.KeychainWithCertsSpec; -import jdk.jpackage.test.MacSign.ResolvedKeychain; -import jdk.jpackage.test.MacSignVerify; -import jdk.jpackage.test.TKit; - - -/* - * @test - * @summary Setup the environment for jpackage macos signing tests. - * Creates required keychains and signing identities. - * Does NOT run any jpackag tests. - * @library /test/jdk/tools/jpackage/helpers - * @build jdk.jpackage.test.* - * @compile -Xlint:all -Werror SigningBase.java - * @requires (jpackage.test.MacSignTests == "setup") - * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningBase.setUp - */ - -/* - * @test - * @summary Tear down the environment for jpackage macos signing tests. - * Deletes required keychains and signing identities. - * Does NOT run any jpackag tests. - * @library /test/jdk/tools/jpackage/helpers - * @build jdk.jpackage.test.* - * @compile -Xlint:all -Werror SigningBase.java - * @requires (jpackage.test.MacSignTests == "teardown") - * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningBase.tearDown - */ - -public class SigningBase { - - public enum StandardCertificateRequest { - CODESIGN(cert().userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - CODESIGN_COPY(cert().days(100).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - CODESIGN_ACME_TECH_LTD(cert().days(100).userName("ACME Technologies Limited (ABC12345)")), - PKG(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - PKG_COPY(cert().type(CertificateType.INSTALLER).days(100).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - CODESIGN_UNICODE(cert().userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), - PKG_UNICODE(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), - CODESIGN_EXPIRED(cert().expired().userName("expired jpackage test")), - PKG_EXPIRED(cert().expired().type(CertificateType.INSTALLER).userName("expired jpackage test")); - - StandardCertificateRequest(CertificateRequest.Builder specBuilder) { - this.spec = specBuilder.create(); - } - - public CertificateRequest spec() { - return spec; - } - - private static CertificateRequest.Builder cert() { - return new CertificateRequest.Builder(); - } - - private final CertificateRequest spec; - } - - /** - * Standard keychains used in signing tests. - */ - public enum StandardKeychain { - /** - * The primary keychain with good certificates. - */ - MAIN("jpackagerTest.keychain", - StandardCertificateRequest.CODESIGN, - StandardCertificateRequest.PKG, - StandardCertificateRequest.CODESIGN_UNICODE, - StandardCertificateRequest.PKG_UNICODE, - StandardCertificateRequest.CODESIGN_ACME_TECH_LTD), - /** - * A keychain with some good and some expired certificates. - */ - EXPIRED("jpackagerTest-expired.keychain", - StandardCertificateRequest.CODESIGN, - StandardCertificateRequest.PKG, - StandardCertificateRequest.CODESIGN_EXPIRED, - StandardCertificateRequest.PKG_EXPIRED), - /** - * A keychain with duplicated certificates. - */ - DUPLICATE("jpackagerTest-duplicate.keychain", - StandardCertificateRequest.CODESIGN, - StandardCertificateRequest.PKG, - StandardCertificateRequest.CODESIGN_COPY, - StandardCertificateRequest.PKG_COPY); - - StandardKeychain(String keychainName, StandardCertificateRequest... certs) { - this(keychainName, certs[0].spec(), Stream.of(certs).skip(1).map(StandardCertificateRequest::spec).toArray(CertificateRequest[]::new)); - } - - StandardKeychain(String keychainName, CertificateRequest cert, CertificateRequest... otherCerts) { - final var builder = keychain(keychainName).addCert(cert); - List.of(otherCerts).forEach(builder::addCert); - this.keychain = new ResolvedKeychain(builder.create()); - } - - public ResolvedKeychain keychain() { - return keychain; - } - - public X509Certificate mapCertificateRequest(CertificateRequest certRequest) { - return Objects.requireNonNull(keychain.mapCertificateRequests().get(certRequest)); - } - - private static KeychainWithCertsSpec.Builder keychain(String name) { - return new KeychainWithCertsSpec.Builder().name(name); - } - - private static List signingEnv() { - return Stream.of(values()).map(StandardKeychain::keychain).map(ResolvedKeychain::spec).toList(); - } - - private final ResolvedKeychain keychain; - } - - public static void setUp() { - MacSign.setUp(StandardKeychain.signingEnv()); - } - - public static void tearDown() { - MacSign.tearDown(StandardKeychain.signingEnv()); - } - - public static void verifySignTestEnvReady() { - if (!Inner.SIGN_ENV_READY) { - TKit.throwSkippedException(new IllegalStateException("Misconfigured signing test environment")); - } - } - - private final class Inner { - private static final boolean SIGN_ENV_READY = MacSign.isDeployed(StandardKeychain.signingEnv()); - } - - enum CertIndex { - ASCII_INDEX(0), - UNICODE_INDEX(1), - INVALID_INDEX(-1); - - CertIndex(int value) { - this.value = value; - } - - int value() { - return value; - } - - private final int value; - } - - public static int DEFAULT_INDEX = 0; - private static String [] DEV_NAMES = { - "jpackage.openjdk.java.net", - "jpackage.openjdk.java.net (รถ)", - }; - - public static String getDevName(int certIndex) { - // Always use values from system properties if set - String value = System.getProperty("jpackage.mac.signing.key.user.name"); - if (value != null) { - return value; - } - - return DEV_NAMES[certIndex]; - } - - public static int getDevNameIndex(String devName) { - return Arrays.binarySearch(DEV_NAMES, devName); - } - - public static String getAppCert(int certIndex) { - return "Developer ID Application: " + getDevName(certIndex); - } - - public static String getInstallerCert(int certIndex) { - return "Developer ID Installer: " + getDevName(certIndex); - } - - public static void verifyCodesign(Path target, boolean signed, int certIndex) { - if (signed) { - final var certRequest = getCertRequest(certIndex); - MacSignVerify.assertSigned(target, certRequest); - } else { - MacSignVerify.assertAdhocSigned(target); - } - } - - // Since we no longer have unsigned app image, but we need to check - // DMG which is not adhoc or certificate signed and we cannot use verifyCodesign - // for this. verifyDMG() is introduced to check that DMG is unsigned. - // Should not be used to validated anything else. - public static void verifyDMG(Path target) { - if (!target.toString().toLowerCase().endsWith(".dmg")) { - throw new IllegalArgumentException("Unexpected target: " + target); - } - - MacSignVerify.assertUnsigned(target); - } - - public static void verifySpctl(Path target, String type, int certIndex) { - final var standardCertIndex = Stream.of(CertIndex.values()).filter(v -> { - return v.value() == certIndex; - }).findFirst().orElseThrow(); - - final var standardType = Stream.of(MacSignVerify.SpctlType.values()).filter(v -> { - return v.value().equals(type); - }).findFirst().orElseThrow(); - - final String expectedSignOrigin; - if (standardCertIndex == CertIndex.INVALID_INDEX) { - expectedSignOrigin = null; - } else if (standardType == MacSignVerify.SpctlType.EXEC) { - expectedSignOrigin = getCertRequest(certIndex).name(); - } else if (standardType == MacSignVerify.SpctlType.INSTALL) { - expectedSignOrigin = getPkgCertRequest(certIndex).name(); - } else { - throw new IllegalArgumentException(); - } - - final var signOrigin = MacSignVerify.findSpctlSignOrigin(standardType, target).orElse(null); - - TKit.assertEquals(signOrigin, expectedSignOrigin, - String.format("Check [%s] has sign origin as expected", target)); - } - - public static void verifyPkgutil(Path target, boolean signed, int certIndex) { - if (signed) { - final var certRequest = getPkgCertRequest(certIndex); - MacSignVerify.assertPkgSigned(target, certRequest, StandardKeychain.MAIN.mapCertificateRequest(certRequest)); - } else { - MacSignVerify.assertUnsigned(target); - } - } - - public static void verifyAppImageSignature(JPackageCommand appImageCmd, - boolean isSigned, String... launchers) throws Exception { - Path launcherPath = appImageCmd.appLauncherPath(); - SigningBase.verifyCodesign(launcherPath, isSigned, SigningBase.DEFAULT_INDEX); - - final List launchersList = List.of(launchers); - launchersList.forEach(launcher -> { - Path testALPath = launcherPath.getParent().resolve(launcher); - SigningBase.verifyCodesign(testALPath, isSigned, SigningBase.DEFAULT_INDEX); - }); - - Path appImage = appImageCmd.outputBundle(); - SigningBase.verifyCodesign(appImage, isSigned, SigningBase.DEFAULT_INDEX); - if (isSigned) { - SigningBase.verifySpctl(appImage, "exec", SigningBase.DEFAULT_INDEX); - } - } - - private static CertificateRequest getCertRequest(int certIndex) { - switch (CertIndex.values()[certIndex]) { - case ASCII_INDEX -> { - return StandardCertificateRequest.CODESIGN.spec(); - } - case UNICODE_INDEX -> { - return StandardCertificateRequest.CODESIGN_UNICODE.spec(); - } - default -> { - throw new IllegalArgumentException(); - } - } - } - - private static CertificateRequest getPkgCertRequest(int certIndex) { - switch (CertIndex.values()[certIndex]) { - case ASCII_INDEX -> { - return StandardCertificateRequest.PKG.spec(); - } - case UNICODE_INDEX -> { - return StandardCertificateRequest.PKG_UNICODE.spec(); - } - default -> { - throw new IllegalArgumentException(); - } - } - } -} diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index b6066bb9cc4..e275fae262c 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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 java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TreeMap; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; @@ -85,6 +86,7 @@ public class AppContentTest { @Test @ParameterSupplier("test") @ParameterSupplier(value="testSymlink", ifNotOS = WINDOWS) + @ParameterSupplier public void testAppImage(TestSpec testSpec) throws Exception { testSpec.test(new ConfigurationTarget(JPackageCommand.helloAppImage())); } @@ -126,6 +128,14 @@ public class AppContentTest { }).toList(); } + public static Collection testAppImage() { + return Stream.of( + build().add(NonExistentPath.create("*output-app-image*", JPackageCommand::outputBundle)) + ).map(TestSpec.Builder::create).map(v -> { + return new Object[] {v}; + }).toList(); + } + public static Collection testSymlink() { return Stream.of( build().add(TEST_JAVA) @@ -150,7 +160,7 @@ public class AppContentTest { void test(ConfigurationTarget target) { final int expectedJPackageExitCode; - if (contentFactories.stream().flatMap(List::stream).anyMatch(TEST_BAD::equals)) { + if (contentFactories.stream().flatMap(List::stream).anyMatch(NonExistentPath.class::isInstance)) { expectedJPackageExitCode = 1; } else { expectedJPackageExitCode = 0; @@ -159,9 +169,11 @@ public class AppContentTest { final List> allContent = new ArrayList<>(); target.addInitializer(JPackageCommand::setFakeRuntime) - .addRunOnceInitializer(_ -> { + .addInitializer(cmd -> { contentFactories.stream().map(group -> { - return group.stream().map(ContentFactory::create).toList(); + return group.stream().map(contentFactory -> { + return contentFactory.create(cmd); + }).toList(); }).forEach(allContent::add); }).addInitializer(cmd -> { allContent.stream().map(group -> { @@ -192,6 +204,10 @@ public class AppContentTest { }); target.addInstallVerifier(cmd -> { + if (expectedJPackageExitCode != 0) { + return; + } + var appContentRoot = getAppContentRoot(cmd); Set disabledVerifiers = new HashSet<>(); @@ -329,7 +345,7 @@ public class AppContentTest { @FunctionalInterface private interface ContentFactory { - Content create(); + Content create(JPackageCommand cmd); } private interface Content { @@ -337,12 +353,7 @@ public class AppContentTest { Iterable verifiers(Path appContentRoot); } - private sealed interface PathVerifier permits - RegularFileVerifier, - DirectoryVerifier, - SymlinkTargetVerifier, - NoPathVerifier { - + private sealed interface PathVerifier { Path path(); void verify(); } @@ -467,22 +478,45 @@ public class AppContentTest { /** * Non-existing content. */ - private static final class NonExistantPath implements ContentFactory { + private static final class NonExistentPath implements ContentFactory { + + private NonExistentPath(String label, Function makePath) { + this.label = Objects.requireNonNull(label); + this.makePath = Objects.requireNonNull(makePath); + } + @Override - public Content create() { - var nonExistant = TKit.createTempFile("non-existant"); - try { - TKit.deleteIfExists(nonExistant); - } catch (IOException ex) { - throw new UncheckedIOException(ex); + public Content create(JPackageCommand cmd) { + var nonexistent = makePath.apply(cmd); + if (Files.exists(nonexistent)) { + throw new IllegalStateException(); } - return new FileContent(nonExistant, 0); + return new FileContent(nonexistent, 0); } @Override public String toString() { - return "*non-existant*"; + return label; } + + static NonExistentPath create(String label, Function makePath) { + return new NonExistentPath(label, makePath); + } + + static NonExistentPath create(String path) { + return new NonExistentPath(String.format("*%s*", Objects.requireNonNull(path)), _ -> { + var nonexistent = TKit.createTempFile(path); + try { + TKit.deleteIfExists(nonexistent); + return nonexistent; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + } + + private final String label; + private final Function makePath; } /** @@ -565,7 +599,7 @@ public class AppContentTest { } @Override - public Content create() { + public Content create(JPackageCommand cmd) { final var appContentRoot = createAppContentRoot(); final var symlinkPath = appContentRoot.resolve(symlinkPath()); @@ -639,7 +673,7 @@ public class AppContentTest { } @Override - public Content create() { + public Content create(JPackageCommand cmd) { Path srcPath = factory.get(); if (!srcPath.endsWith(pathInAppContentRoot)) { throw new IllegalArgumentException(); @@ -672,7 +706,7 @@ public class AppContentTest { private static final ContentFactory TEST_JAVA = createTextFileContent("apps/PrintEnv.java", "Not what someone would expect"); private static final ContentFactory TEST_DUKE = createTextFileContent("duke.txt", "Hi Duke!"); private static final ContentFactory TEST_DIR = createDirTreeContent("apps"); - private static final ContentFactory TEST_BAD = new NonExistantPath(); + private static final ContentFactory TEST_BAD = NonExistentPath.create("non-existent"); // On OSX `--app-content` paths will be copied into the "Contents" folder // of the output app image. diff --git a/test/jdk/tools/jpackage/share/AppImagePackageTest.java b/test/jdk/tools/jpackage/share/AppImagePackageTest.java index bfd731b67d5..ce2300c92d1 100644 --- a/test/jdk/tools/jpackage/share/AppImagePackageTest.java +++ b/test/jdk/tools/jpackage/share/AppImagePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.function.Predicate; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Test; @@ -133,8 +134,7 @@ public class AppImagePackageTest { */ @Test public static void testBadAppImage() throws IOException { - Path appImageDir = TKit.createTempDirectory("appimage"); - Files.createFile(appImageDir.resolve("foo")); + Path appImageDir = createInvalidAppImage(); configureBadAppImage(appImageDir).addInitializer(cmd -> { cmd.removeArgumentWithValue("--name"); }).run(Action.CREATE); @@ -145,8 +145,7 @@ public class AppImagePackageTest { */ @Test public static void testBadAppImage2() throws IOException { - Path appImageDir = TKit.createTempDirectory("appimage"); - Files.createFile(appImageDir.resolve("foo")); + Path appImageDir = createInvalidAppImage(); configureBadAppImage(appImageDir).run(Action.CREATE); } @@ -227,4 +226,19 @@ public class AppImagePackageTest { + TKit.ICON_SUFFIX)); } + private static Path createInvalidAppImage() throws IOException { + Path appImageDir = TKit.createTempDirectory("appimage"); + if (TKit.isOSX()) { + // Create minimal macOS bundle to prevent jpackage bail out early + // with "error.parameter-not-mac-bundle" error. + var bundle = new MacBundle(appImageDir); + Files.createDirectories(bundle.macOsDir()); + Files.createFile(bundle.infoPlistFile()); + } else { + Files.createFile(appImageDir.resolve("foo")); + } + + return appImageDir; + } + } diff --git a/test/jdk/tools/jpackage/share/AsyncTest.java b/test/jdk/tools/jpackage/share/AsyncTest.java index e3a3f7e3cb8..b7dd13f91fa 100644 --- a/test/jdk/tools/jpackage/share/AsyncTest.java +++ b/test/jdk/tools/jpackage/share/AsyncTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.Collection; @@ -34,15 +33,12 @@ import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; 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; import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.JavaAppDesc; import jdk.jpackage.test.Main; import jdk.jpackage.test.PackageTest; @@ -66,10 +62,10 @@ public class AsyncTest { // Create test jar only once. // Besides of saving time, this avoids asynchronous invocations of java tool provider that randomly fail. - APP_JAR.set(HelloApp.createBundle(JavaAppDesc.parse("Hello!"), TKit.workDir())); + var appJar = HelloApp.createBundle(JavaAppDesc.parse("Hello!"), TKit.workDir()); // - // Run test cases from InternalAsyncTest class asynchronously. + // Run test cases from AsyncInnerTest class asynchronously. // Spawn a thread for every test case. // Input data for test cases will be cooked asynchronously but in a safe way because every test case has an isolated work directory. // Multiple jpackage tool provider instances will be invoked asynchronously. @@ -79,14 +75,10 @@ public class AsyncTest { var testFuncNames = List.of("testAppImage", "testNativeBundle"); - var runArg = String.format("--jpt-run=%s", AsyncInnerTest.class.getName()); - var futures = executor.invokeAll(IntStream.range(0, JOB_COUNT).mapToObj(Integer::toString).mapMulti((idx, consumer) -> { for (var testFuncName : testFuncNames) { var id = String.format("%s(%s)", testFuncName, idx); - consumer.accept(new Workload(() -> { - Main.main(runArg, String.format("--jpt-include=%s", id)); - }, id)); + consumer.accept(new Workload(id, appJar)); } }).toList()); @@ -99,10 +91,8 @@ public class AsyncTest { for (var future : futures) { var result = future.get(); - TKit.trace(String.format("[%s] STDOUT BEGIN\n%s", result.id(), result.stdoutBuffer())); - 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())); + TKit.trace(String.format("[%s] OUTPUT BEGIN\n%s", result.testCaseId(), result.testOutput())); + TKit.trace(String.format("[%s] OUTPUT END", result.testCaseId())); result.exception().filter(Predicate.not(TKit::isSkippedException)).ifPresent(fatalError::set); } @@ -142,80 +132,56 @@ public class AsyncTest { } - private record Result(String stdoutBuffer, String stderrBuffer, String id, Optional exception) { + private record Result(String testOutput, String testCaseId, Optional exception) { Result { - Objects.requireNonNull(stdoutBuffer); - Objects.requireNonNull(stderrBuffer); - Objects.requireNonNull(id); + Objects.requireNonNull(testOutput); + Objects.requireNonNull(testCaseId); Objects.requireNonNull(exception); } } private record Workload( - ByteArrayOutputStream stdoutBuffer, - ByteArrayOutputStream stderrBuffer, - ThrowingRunnable runnable, - String id) implements Callable { + String testCaseId, + ByteArrayOutputStream outputSink, + Path appJar) implements Callable { Workload { - Objects.requireNonNull(stdoutBuffer); - Objects.requireNonNull(stderrBuffer); - Objects.requireNonNull(runnable); - Objects.requireNonNull(id); + Objects.requireNonNull(testCaseId); + Objects.requireNonNull(outputSink); + Objects.requireNonNull(appJar); } - Workload(ThrowingRunnable runnable, String id) { - this(new ByteArrayOutputStream(), new ByteArrayOutputStream(), runnable, id); + Workload(String testCaseId, Path appJar) { + this(testCaseId, new ByteArrayOutputStream(), appJar); } - private String stdoutBufferAsString() { - return new String(stdoutBuffer.toByteArray(), StandardCharsets.UTF_8); - } - - private String stderrBufferAsString() { - return new String(stderrBuffer.toByteArray(), StandardCharsets.UTF_8); + private String testOutput() { + return new String(outputSink.toByteArray(), StandardCharsets.UTF_8); } @Override public Result call() { - // Reset the current test inherited in the state from the parent thread. - TKit.state(DEFAULT_STATE); - - var defaultToolProvider = JavaTool.JPACKAGE.asToolProvider(); - - JPackageCommand.useToolProviderByDefault(new ToolProvider() { - - @Override - public int run(PrintWriter out, PrintWriter err, String... args) { - try (var bufOut = new PrintWriter(stdoutBuffer, true, StandardCharsets.UTF_8); - var bufErr = new PrintWriter(stderrBuffer, true, StandardCharsets.UTF_8)) { - return defaultToolProvider.run(bufOut, bufErr, args); - } - } - - @Override - public String name() { - return defaultToolProvider.name(); - } - }); + var runArg = String.format("--jpt-run=%s", AsyncInnerTest.class.getName()); 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); + try { + try (var out = new PrintStream(outputSink, false, System.out.charset())) { + ScopedValue.where(APP_JAR, appJar).run(() -> { + TKit.withOutput(() -> { + JPackageCommand.useToolProviderByDefault(); + Main.main("--jpt-ignore-logfile", runArg, String.format("--jpt-include=%s", testCaseId)); + }, out, out); + }); + } } catch (Exception ex) { err = Optional.of(ex); } - return new Result(stdoutBufferAsString(), stderrBufferAsString(), id, err); + return new Result(testOutput(), testCaseId, err); } } - private static final int JOB_COUNT = 30; - private static final TKit.State DEFAULT_STATE = TKit.state(); - private static final InheritableThreadLocal APP_JAR = new InheritableThreadLocal<>(); + private static final ScopedValue APP_JAR = ScopedValue.newInstance(); } diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index afa847f6e1b..977b7c7c057 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +22,7 @@ */ +import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE; import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; import java.io.IOException; @@ -32,6 +33,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Pattern; @@ -41,6 +43,7 @@ import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.CannedFormattedString; +import jdk.jpackage.test.ConfigurationTarget; import jdk.jpackage.test.Executor; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; @@ -176,57 +179,74 @@ public final class BasicTest { } @Test - @SuppressWarnings("unchecked") - public void testVerbose() { - JPackageCommand cmd = JPackageCommand.helloAppImage() - // Disable default logic adding `--verbose` option - // to jpackage command line. - .ignoreDefaultVerbose(true) - .saveConsoleOutput(true) - .setFakeRuntime().executePrerequisiteActions(); + @Parameter("false") + @Parameter("true") + public void testQuiet(boolean appImage) { - List expectedVerboseOutputStrings = new ArrayList<>(); - expectedVerboseOutputStrings.add("Creating app package:"); - if (TKit.isWindows()) { - expectedVerboseOutputStrings.add( - "Succeeded in building Windows Application Image package"); - } else if (TKit.isLinux()) { - expectedVerboseOutputStrings.add( - "Succeeded in building Linux Application Image package"); - } else if (TKit.isOSX()) { - expectedVerboseOutputStrings.add("Preparing Info.plist:"); - expectedVerboseOutputStrings.add( - "Succeeded in building Mac Application Image package"); + ConfigurationTarget target; + if (appImage) { + target = new ConfigurationTarget(JPackageCommand.helloAppImage()); } else { - TKit.throwUnknownPlatformError(); + target = new ConfigurationTarget(new PackageTest().configureHelloApp()); } - TKit.deleteDirectoryContentsRecursive(cmd.outputDir()); - List nonVerboseOutput = cmd.execute().getOutput(); - List[] verboseOutput = (List[])new List[1]; - - // Directory clean up is not 100% reliable on Windows because of - // antivirus software that can lock .exe files. Setup - // different output directory instead of cleaning the default one for - // verbose jpackage run. - TKit.withTempDirectory("verbose-output", tempDir -> { - cmd.setArgumentValue("--dest", tempDir); - cmd.addArgument("--verbose"); - verboseOutput[0] = cmd.execute().getOutput(); + target.addInitializer(cmd -> { + // Disable the default logic adding `--verbose` option to jpackage command line. + cmd.ignoreDefaultVerbose(true) + .useToolProvider(true) + .saveConsoleOutput(true) + .setFakeRuntime(); }); - TKit.assertTrue(nonVerboseOutput.size() < verboseOutput[0].size(), - "Check verbose output is longer than regular"); + Consumer asserter = result -> { + TKit.assertStringListEquals(List.of(), result.getOutput(), "Check output is empty"); + }; - expectedVerboseOutputStrings.forEach(str -> { - TKit.assertTextStream(str).label("regular output") - .predicate(String::contains).negate() - .apply(nonVerboseOutput); + target.cmd().map(JPackageCommand::execute).ifPresent(asserter); + target.test().ifPresent(test -> { + test.addBundleVerifier((_, result) -> { + asserter.accept(result); + }).run(CREATE); + }); + } + + @Test + @Parameter("false") + @Parameter("true") + public void testVerbose(boolean appImage) { + + ConfigurationTarget target; + if (appImage) { + target = new ConfigurationTarget(JPackageCommand.helloAppImage()); + } else { + target = new ConfigurationTarget(new PackageTest().configureHelloApp()); + } + + target.addInitializer(cmd -> { + // Disable the default logic adding `--verbose` option to jpackage command line. + cmd.ignoreDefaultVerbose(true) + .useToolProvider(true) + .addArgument("--verbose") + .saveConsoleOutput(true) + .setFakeRuntime(); + + List verboseContent; + if (appImage) { + verboseContent = List.of( + JPackageStringBundle.MAIN.cannedFormattedString("message.create-app-image"), + JPackageStringBundle.MAIN.cannedFormattedString("message.app-image-created")); + } else { + verboseContent = List.of( + JPackageStringBundle.MAIN.cannedFormattedString("message.create-package"), + JPackageStringBundle.MAIN.cannedFormattedString("message.package-created")); + } + + cmd.validateOutput(verboseContent.toArray(CannedFormattedString[]::new)); }); - expectedVerboseOutputStrings.forEach(str -> { - TKit.assertTextStream(str).label("verbose output") - .apply(verboseOutput[0]); + target.cmd().ifPresent(JPackageCommand::execute); + target.test().ifPresent(test -> { + test.run(CREATE); }); } diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index ca1189a191e..f31ac42dea0 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -643,7 +643,12 @@ public final class ErrorTest { .error("message.invalid-identifier", "#1"), // Bundle for mac app store should not have runtime commands testSpec().nativeType().addArgs("--mac-app-store", "--jlink-options", "--bind-services") - .error("ERR_MissingJLinkOptMacAppStore", "--strip-native-commands") + .error("ERR_MissingJLinkOptMacAppStore", "--strip-native-commands"), + // Predefined app image must be a valid macOS bundle. + testSpec().noAppDesc().nativeType().addArgs("--app-image", Token.EMPTY_DIR.token()) + .error("error.parameter-not-mac-bundle", JPackageCommand.cannedArgument(cmd -> { + return Path.of(cmd.getArgumentValue("--app-image")); + }, Token.EMPTY_DIR.token()), "--app-image") ).map(TestSpec.Builder::create).toList()); macInvalidRuntime(testCases::add); diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index 6956f66df42..a9fa48dc1c6 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,26 +24,28 @@ import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.ApplicationLayout; +import jdk.jpackage.test.ConfigurationTarget; 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 jdk.jpackage.test.TKit; +import jdk.jpackage.internal.util.function.ThrowingConsumer; /* * @test @@ -76,25 +78,6 @@ public final class InOutPathTest { return data; } - @Parameters(ifNotOS = OperatingSystem.MACOS) - public static Collection appContentInputOther() { - return List.of(new Object[][]{ - {PackageTypeAlias.IMAGE, wrap(cmd -> { - additionalContent(cmd, "--app-content", cmd.outputBundle()); - }, "--app-content same as output bundle")}, - }); - } - - @Parameters(ifOS = OperatingSystem.MACOS) - public static Collection appContentInputOSX() { - var contentsFolder = "Contents/MacOS"; - return List.of(new Object[][]{ - {PackageTypeAlias.IMAGE, wrap(cmd -> { - additionalContent(cmd, "--app-content", cmd.outputBundle().resolve(contentsFolder)); - }, String.format("--app-content same as the \"%s\" folder in the output bundle", contentsFolder))}, - }); - } - @Parameters(ifOS = OperatingSystem.MACOS) public static Collection inputOSX() { return List.of(additionalContentInput(PackageType.MAC_DMG, "--mac-dmg-content").toArray(Object[][]::new)); @@ -146,67 +129,54 @@ public final class InOutPathTest { } @Test - public void test() throws Exception { + public void test() { runTest(packageTypes, configure); } private static Envelope wrap(ThrowingConsumer v, String label) { - return new Envelope(v, label); - } - - private static boolean isAppImageValid(JPackageCommand cmd) { - return !cmd.hasArgument("--app-content") && !cmd.hasArgument("--mac-dmg-content"); + return new Envelope(ThrowingConsumer.toConsumer(v), label); } private static void runTest(Set packageTypes, - ThrowingConsumer configure) throws Exception { - ThrowingConsumer configureWrapper = cmd -> { + Consumer configure) { + + ConfigurationTarget cfg; + if (packageTypes.contains(PackageType.IMAGE)) { + cfg = new ConfigurationTarget( + JPackageCommand.helloAppImage(JAR_PATH.toString() + ":")); + } else { + cfg = new ConfigurationTarget(new PackageTest() + .forTypes(packageTypes) + .configureHelloApp(JAR_PATH.toString() + ":")); + } + + var verifier = new AppDirContentVerifier(); + + cfg.addInitializer(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. cmd.setInputToEmptyDirectory(); configure.accept(cmd); if (cmd.hasArgument("--temp") && cmd.isImagePackageType()) { - // Request to build app image wit user supplied temp directory, + // Request to build app image with user supplied temp directory, // ignore external runtime if any to make use of the temp directory // for runtime generation. cmd.ignoreDefaultRuntime(true); } else { cmd.setFakeRuntime(); } + }) + .addInitializer(JPackageCommand::executePrerequisiteActions) + .addInitializer(verifier::captureInputDir); - if (!isAppImageValid(cmd)) { - // Standard asserts for .jpackage.xml fail in messed up app image. Disable them. - // Other standard asserts for app image contents should pass. - cmd.excludeStandardAsserts(StandardAssert.APP_IMAGE_FILE); - } - }; + cfg.cmd().ifPresent(JPackageCommand::executeAndAssertHelloAppImageCreated); - if (packageTypes.contains(PackageType.IMAGE)) { - JPackageCommand cmd = JPackageCommand.helloAppImage(JAR_PATH.toString() + ":"); - configureWrapper.accept(cmd); - cmd.executeAndAssertHelloAppImageCreated(); - if (isAppImageValid(cmd)) { - verifyAppImage(cmd); - } + cfg.addInstallVerifier(verifier::verify); - if (cmd.hasArgument("--app-content")) { - // `--app-content` can be set to the app image directory which - // should not exist before jpackage is executed: - // jpackage --name Foo --dest output --app-content output/Foo - // Verify the directory exists after jpackage execution. - // At least this will catch the case when the value of - // `--app-content` option refers to a path unrelated to jpackage I/O. - TKit.assertDirectoryExists(Path.of(cmd.getArgumentValue("--app-content"))); - } - } else { - new PackageTest() - .forTypes(packageTypes) - .configureHelloApp(JAR_PATH.toString() + ":") - .addInitializer(configureWrapper) - .addInstallVerifier(InOutPathTest::verifyAppImage) - .run(CREATE_AND_UNPACK); - } + cfg.test().ifPresent(pkg -> { + pkg.run(CREATE_AND_UNPACK); + }); } private static void outputDirInInputDir(JPackageCommand cmd) throws @@ -217,8 +187,7 @@ public final class InOutPathTest { cmd.setArgumentValue("--dest", outputDir); } - private static void outputDirSameAsInputDir(JPackageCommand cmd) throws - IOException { + private static void outputDirSameAsInputDir(JPackageCommand cmd) { // Set output dir the same as the input dir cmd.setArgumentValue("--dest", cmd.inputDir()); } @@ -238,38 +207,7 @@ public final class InOutPathTest { cmd.addArguments(argName, appContentFile.getParent()); } - private static void verifyAppImage(JPackageCommand cmd) throws IOException { - if (!isAppImageValid(cmd)) { - // Don't verify the contents of app image as it is invalid. - // jpackage exited without getting stuck in infinite spiral. - // No more expectations from the tool for the give arguments. - return; - } - - final Path rootDir = cmd.isImagePackageType() ? cmd.outputBundle() : cmd.pathToUnpackedPackageFile( - cmd.appInstallationDirectory()); - final Path appDir = ApplicationLayout.platformAppImage().resolveAt( - rootDir).appDirectory(); - - final var knownFiles = Set.of( - JAR_PATH.getName(0).toString(), - PackageFile.getPathInAppImage(Path.of("")).getFileName().toString(), - AppImageFile.getPathInAppImage(Path.of("")).getFileName().toString(), - cmd.name() + ".cfg" - ); - - TKit.assertFileExists(appDir.resolve(JAR_PATH)); - - try (Stream actualFilesStream = Files.list(appDir)) { - var unexpectedFiles = actualFilesStream.map(path -> { - return path.getFileName().toString(); - }).filter(Predicate.not(knownFiles::contains)).toList(); - TKit.assertStringListEquals(List.of(), unexpectedFiles, - "Check there are no unexpected files in `app` folder"); - } - } - - private static final record Envelope(ThrowingConsumer value, String label) { + private record Envelope(Consumer value, String label) { @Override public String toString() { // Will produce the same test description for the same label every @@ -291,8 +229,49 @@ public final class InOutPathTest { private final Set packageTypes; } + private static final class AppDirContentVerifier { + + void captureInputDir(JPackageCommand cmd) { + var root = Path.of(cmd.getArgumentValue("--input")); + try (var walk = Files.walk(root)) { + inputDirFiles = walk.map(root::relativize).toList(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + void verify(JPackageCommand cmd) { + var expectedContent = new HashSet<>(inputDirFiles); + + expectedContent.add(Path.of(cmd.name() + ".cfg")); + if (cmd.isImagePackageType()) { + expectedContent.add(AppImageFile.getPathInAppImage(Path.of("")).getFileName()); + } else { + expectedContent.add(PackageFile.getPathInAppImage(Path.of("")).getFileName()); + } + + final var rootDir = cmd.isImagePackageType() ? cmd.outputBundle() : cmd.pathToUnpackedPackageFile( + cmd.appInstallationDirectory()); + final var appDir = ApplicationLayout.platformAppImage().resolveAt(rootDir).appDirectory(); + + try (var walk = Files.walk(appDir)) { + var unexpectedFiles = walk + .map(appDir::relativize) + .filter(Predicate.not(expectedContent::contains)) + .map(Path::toString) + .toList(); + TKit.assertStringListEquals(List.of(), unexpectedFiles, + "Check there are no unexpected files in `app` folder"); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private Collection inputDirFiles; + } + private final Set packageTypes; - private final ThrowingConsumer configure; + private final Consumer 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/LicenseTest.java b/test/jdk/tools/jpackage/share/LicenseTest.java index 1c6bfd51b62..9c2d1077584 100644 --- a/test/jdk/tools/jpackage/share/LicenseTest.java +++ b/test/jdk/tools/jpackage/share/LicenseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ import jdk.jpackage.test.TKit; * * Mac: * + * For DMG license should be displayed on command line when "hdiutil attach" + * is called. + * * Windows * * Installer should display license text matching contents of the license file @@ -96,6 +99,7 @@ public class LicenseTest { LICENSE_FILE)); }); + initMacDmgLicenseVerifier(test.forTypes(PackageType.MAC_DMG)); initLinuxLicenseVerifier(test.forTypes(PackageType.LINUX)); test.run(); @@ -131,6 +135,33 @@ public class LicenseTest { new CustomDebianCopyrightTest().withSubstitution(true).run(); } + private static PackageTest initMacDmgLicenseVerifier(PackageTest test) { + return test + .addBundleVerifier(cmd -> { + verifyLicenseFileInDMGPackage(cmd); + }); + } + + private static void verifyLicenseFileInDMGPackage(JPackageCommand cmd) + throws IOException { + // DMG should have license, so attach with "no", since we only need license. + // With "no" attach will be canceled. + final var attachExec = Executor.of("sh", "-c", String.join(" ", + "no", + "|", + "/usr/bin/hdiutil", + "attach", + JPackageCommand.escapeAndJoin(cmd.outputBundle().toString()) + )).saveOutput().storeOutputInFiles(); + + // Expected exit code is 1, since we canceling license. + final var attachResult = attachExec.executeAndRepeatUntilExitCode(1, 10, 6); + TKit.assertStringListEquals(Files.readAllLines(LICENSE_FILE), + attachResult.stdout(), String.format( + "Check output of \"hdiutil attach\" has the same license as contents of source license file [%s]", + LICENSE_FILE)); + } + private static PackageTest initLinuxLicenseVerifier(PackageTest test) { return test .addBundleVerifier(cmd -> { diff --git a/test/jdk/tools/jpackage/share/MainClassTest.java b/test/jdk/tools/jpackage/share/MainClassTest.java index bc813c4ec15..72e77bbbff5 100644 --- a/test/jdk/tools/jpackage/share/MainClassTest.java +++ b/test/jdk/tools/jpackage/share/MainClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -240,8 +240,7 @@ public final class MainClassTest { cmd.executeAndAssertHelloAppImageCreated(); } else { cmd.executeAndAssertImageCreated(); - var appVerifier = HelloApp.assertMainLauncher(cmd); - if (appVerifier != null) { + HelloApp.assertMainLauncher(cmd).ifPresent(appVerifier -> { List output = appVerifier .saveOutput(true) .expectedExitCode(1) @@ -249,7 +248,7 @@ public final class MainClassTest { TKit.assertTextStream(String.format( "Error: Could not find or load main class %s", nonExistingMainClass)).apply(output); - } + }); } CfgFile cfg = cmd.readLauncherCfgFile(); diff --git a/test/jdk/tools/jpackage/share/OutputErrorTest.java b/test/jdk/tools/jpackage/share/OutputErrorTest.java new file mode 100644 index 00000000000..110e86e67d9 --- /dev/null +++ b/test/jdk/tools/jpackage/share/OutputErrorTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * 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.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.spi.ToolProvider; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageStringBundle; +import jdk.jpackage.test.JavaTool; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.TKit; + +/* + * @test + * @summary Test how jpackage handles errors writing output bundle + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @compile -Xlint:all -Werror OutputErrorTest.java + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=OutputErrorTest + */ + +public final class OutputErrorTest { + + @Test + @Parameter("DIR") + // "Locked file error" reliably works only on Windows + @Parameter(value = "LOCKED_FILE", ifOS = OperatingSystem.WINDOWS) + public void testPackage(ExistingOutputBundleType existingOutputBundleType) { + + new PackageTest().configureHelloApp().addInitializer(cmd -> { + + cmd.setFakeRuntime(); + cmd.setArgumentValue("--dest", TKit.createTempDirectory("output")); + cmd.removeOldOutputBundle(false); + cmd.validateOutput(JPackageCommand.makeError(JPackageStringBundle.MAIN.cannedFormattedString( + "error.output-bundle-cannot-be-overwritten", cmd.outputBundle().toAbsolutePath()))); + + var outputBundle = cmd.outputBundle(); + + switch (existingOutputBundleType) { + case DIR -> { + Files.createDirectories(outputBundle); + Files.writeString(outputBundle.resolve("foo.txt"), "Hello"); + } + case LOCKED_FILE -> { + Files.writeString(outputBundle, "Hello"); + cmd.useToolProvider(createToolProviderWithLockedFile( + JavaTool.JPACKAGE.asToolProvider(), outputBundle)); + } + } + + }).setExpectedExitCode(1).run(); + } + + enum ExistingOutputBundleType { + DIR, + LOCKED_FILE, + ; + } + + private static ToolProvider createToolProviderWithLockedFile(ToolProvider tp, Path lockedFile) { + Objects.requireNonNull(tp); + if (!Files.isRegularFile(lockedFile)) { + throw new IllegalArgumentException(); + } + + return new ToolProvider() { + + @Override + public String name() { + return "jpackage-mock"; + } + + @SuppressWarnings("try") + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + try { + var lastModifiedTime = Files.getLastModifiedTime(lockedFile); + try (var fos = new FileOutputStream(lockedFile.toFile()); var lock = fos.getChannel().lock()) { + Files.setLastModifiedTime(lockedFile, lastModifiedTime); + return tp.run(out, err, args); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + }; + } +} diff --git a/test/jdk/tools/jpackage/windows/Win8301247Test.java b/test/jdk/tools/jpackage/windows/Win8301247Test.java index 2f98141dcb4..bed795281f4 100644 --- a/test/jdk/tools/jpackage/windows/Win8301247Test.java +++ b/test/jdk/tools/jpackage/windows/Win8301247Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +21,14 @@ * questions. */ -import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; - import java.time.Duration; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.TKit; /** * Test that terminating of the parent app launcher process automatically @@ -46,7 +48,7 @@ import jdk.jpackage.test.JPackageCommand; public class Win8301247Test { @Test - public void test() throws InterruptedException { + public void test() throws InterruptedException, ExecutionException { var cmd = JPackageCommand.helloAppImage().ignoreFakeRuntime(); // Launch the app in a way it doesn't exit to let us trap app laucnher @@ -54,20 +56,44 @@ public class Win8301247Test { cmd.addArguments("--java-options", "-Djpackage.test.noexit=true"); cmd.executeAndAssertImageCreated(); + var state = TKit.state(); + var f = new CompletableFuture(); + // Launch the app in a separate thread new Thread(() -> { - HelloApp.executeLauncher(cmd); + TKit.withState(() -> { + HelloApp.assertMainLauncher(cmd).get().processListener(f::complete).execute(); + }, state); }).start(); - // Wait a bit to let the app start - Thread.sleep(Duration.ofSeconds(10)); + var mainLauncherProcess = f.get(); - // Find the main app launcher process and kill it - killAppLauncherProcess(cmd, null, 2); + Optional childProcess = Optional.empty(); - // Wait a bit and check if child app launcher process is still running (it must NOT) - Thread.sleep(Duration.ofSeconds(5)); + try { + // Wait a bit to let the app start + Thread.sleep(Duration.ofSeconds(10)); - killAppLauncherProcess(cmd, null, 0); + try (var children = mainLauncherProcess.children()) { + childProcess = children.filter(p -> { + return mainLauncherProcess.info().command().equals(p.info().command()); + }).findFirst(); + } + + TKit.assertTrue(childProcess.isPresent(), + String.format("Check the main launcher process with PID=%d restarted", mainLauncherProcess.pid())); + } finally { + // Kill the main app launcher process + TKit.trace("About to kill the main launcher process..."); + mainLauncherProcess.destroyForcibly(); + + // Wait a bit and check if child app launcher process is still running (it must NOT) + Thread.sleep(Duration.ofSeconds(5)); + + childProcess.ifPresent(p -> { + TKit.assertTrue(!p.isAlive(), String.format( + "Check restarted main launcher process with PID=%d is not alive", p.pid())); + }); + } } } diff --git a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java index a83ef837331..e5de19d182a 100644 --- a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java +++ b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import static jdk.jpackage.test.HelloApp.configureAndExecute; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Executor; import jdk.jpackage.test.TKit; -import static jdk.jpackage.test.WindowsHelper.killProcess; public class WinChildProcessTest { private static final Path TEST_APP_JAVA = TKit.TEST_SRC_ROOT @@ -52,7 +51,7 @@ public class WinChildProcessTest { @Test public static void test() { - long childPid = 0; + Optional child = Optional.empty(); try { JPackageCommand cmd = JPackageCommand .helloAppImage(TEST_APP_JAVA + "*Hello") @@ -69,21 +68,18 @@ public class WinChildProcessTest { String pidStr = output.get(0); // parse child PID - childPid = Long.parseLong(pidStr.split("=", 2)[1]); + var childPid = Long.parseLong(pidStr.split("=", 2)[1]); // Check whether the termination of third party application launcher // also terminating the launched third party application // If third party application is not terminated the test is // successful else failure - Optional processHandle = ProcessHandle.of(childPid); - boolean isAlive = processHandle.isPresent() - && processHandle.get().isAlive(); - TKit.assertTrue(isAlive, "Check child process is alive"); + child = ProcessHandle.of(childPid); + boolean isAlive = child.map(ProcessHandle::isAlive).orElse(false); + TKit.assertTrue(isAlive, String.format("Check child process with PID=%d is alive", childPid)); } finally { - if (childPid != 0) { - // Kill only a specific child instance - killProcess(childPid); - } + TKit.trace("About to kill the child process..."); + child.ifPresent(ProcessHandle::destroyForcibly); } } } diff --git a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java index 909ee06b01a..7390b2f79a3 100644 --- a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java +++ b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 @@ * questions. */ -import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; import java.io.IOException; import java.time.Duration; import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.CfgFile; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.TKit; /* @test * @bug 8340311 @@ -47,7 +50,7 @@ import jdk.jpackage.test.JPackageCommand; public class WinNoRestartTest { @Test - public static void test() throws InterruptedException, IOException { + public static void test() throws InterruptedException, IOException, ExecutionException { var cmd = JPackageCommand.helloAppImage().ignoreFakeRuntime(); // Configure test app to launch in a way it will not exit @@ -77,7 +80,7 @@ public class WinNoRestartTest { private static record NoRerunConfig(NoRerunSectionConfig firstSection, NoRerunSectionConfig secondSection, boolean expectedNoRestarted) { - void apply(JPackageCommand cmd, CfgFile origCfgFile) throws InterruptedException { + void apply(JPackageCommand cmd, CfgFile origCfgFile) throws InterruptedException, ExecutionException { // Alter the main launcher .cfg file var cfgFile = new CfgFile(); if (firstSection != null) { @@ -92,16 +95,43 @@ public class WinNoRestartTest { // Save updated main launcher .cfg file cfgFile.save(cmd.appLauncherCfgPath(null)); + var state = TKit.state(); + var f = new CompletableFuture(); + // Launch the app in a separate thread new Thread(() -> { - HelloApp.executeLauncher(cmd); + TKit.withState(() -> { + HelloApp.assertMainLauncher(cmd).get().processListener(f::complete).execute(); + }, state); }).start(); - // Wait a bit to let the app start - Thread.sleep(Duration.ofSeconds(10)); + var mainLauncherProcess = f.get(); - // Find the main app launcher process and kill it - killAppLauncherProcess(cmd, null, expectedNoRestarted ? 1 : 2); + try { + // Wait a bit to let the app start + Thread.sleep(Duration.ofSeconds(10)); + + try (var children = mainLauncherProcess.children()) { + Optional childPid = children.filter(p -> { + return mainLauncherProcess.info().command().equals(p.info().command()); + }).map(ProcessHandle::pid).map(Object::toString).findFirst(); + + Optional expectedChildPid; + if (expectedNoRestarted) { + expectedChildPid = Optional.empty(); + } else { + expectedChildPid = childPid.or(() -> { + return Optional.of(""); + }); + } + TKit.assertEquals(expectedChildPid, childPid, String.format( + "Check the main launcher process with PID=%d restarted", + mainLauncherProcess.pid())); + } + } finally { + TKit.trace("About to kill the main launcher process..."); + mainLauncherProcess.destroyForcibly(); + } } } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java index 803e0c8865b..a65c4503238 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ public class TestNewCastArray { // 'b' tests fail with only even numbers of annotations (8005681). String[] testclasses = {"Test1", "Test2a", "Test3a", "Test4a", "Test5a", - "Test2b", "Test3b", "Test4b", "Test5b" + "Test2b", "Test3b", "Test4b", "Test5b", + "Test6a" }; public static void main(String[] args) throws Exception { @@ -182,6 +183,11 @@ public class TestNewCastArray { case "ci2": expected = 0; break; case "ci22": expected = 0; break; + case "Test6a": cexpected=4; break; + case "test6aPrimitiveArray": expected = 0; break; + case "test6aRefArray": expected = 0; break; + case "test6aMethod": cexpected = 4; break; + default: expected = 0; break; } if(codeattr) @@ -353,6 +359,18 @@ public class TestNewCastArray { Integer ci22 = (@A @A @B @B Integer)o; // FAIL expect 3, got 1 } + static class Test6a { + Test6a(){} + long l = 0; + // Cast expressions inside new array dimensions: + int[] test6aPrimitiveArray = new int[(@A @A @B @B int) l]; + Integer[] test6aRefArray = new Integer[(@A @A @B @B int) l]; + private void test6aMethod() { + int[] primitiveArray = new int[(@A @A @B @B int) l]; + Integer[] refArray = new Integer[(@A @A @B @B int) l]; + } + } + @Retention(RUNTIME) @Target({TYPE_USE}) @Repeatable( AC.class ) @interface A { } @Retention(RUNTIME) @Target({TYPE_USE}) @Repeatable( BC.class ) @interface B { } @Retention(RUNTIME) @Target({FIELD}) @Repeatable( FC.class ) @interface F { }