diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp index 6d5492b86b3..28b797a639e 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp @@ -34,16 +34,6 @@ // Implementation of the platform-specific part of StubRoutines - for // a description of how to extend it, see the stubRoutines.hpp file. -address StubRoutines::riscv::_get_previous_sp_entry = nullptr; - -address StubRoutines::riscv::_f2i_fixup = nullptr; -address StubRoutines::riscv::_f2l_fixup = nullptr; -address StubRoutines::riscv::_d2i_fixup = nullptr; -address StubRoutines::riscv::_d2l_fixup = nullptr; -address StubRoutines::riscv::_float_sign_mask = nullptr; -address StubRoutines::riscv::_float_sign_flip = nullptr; -address StubRoutines::riscv::_double_sign_mask = nullptr; -address StubRoutines::riscv::_double_sign_flip = nullptr; address StubRoutines::riscv::_zero_blocks = nullptr; address StubRoutines::riscv::_compare_long_string_LL = nullptr; address StubRoutines::riscv::_compare_long_string_UU = nullptr; @@ -52,7 +42,6 @@ address StubRoutines::riscv::_compare_long_string_UL = nullptr; address StubRoutines::riscv::_string_indexof_linear_ll = nullptr; address StubRoutines::riscv::_string_indexof_linear_uu = nullptr; address StubRoutines::riscv::_string_indexof_linear_ul = nullptr; -address StubRoutines::riscv::_large_byte_array_inflate = nullptr; bool StubRoutines::riscv::_completed = false; diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp index 3d1f4a61f00..a099d71475e 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp @@ -47,18 +47,6 @@ class riscv { friend class StubGenerator; private: - static address _get_previous_sp_entry; - - static address _f2i_fixup; - static address _f2l_fixup; - static address _d2i_fixup; - static address _d2l_fixup; - - static address _float_sign_mask; - static address _float_sign_flip; - static address _double_sign_mask; - static address _double_sign_flip; - static address _zero_blocks; static address _compare_long_string_LL; @@ -68,48 +56,11 @@ class riscv { static address _string_indexof_linear_ll; static address _string_indexof_linear_uu; static address _string_indexof_linear_ul; - static address _large_byte_array_inflate; static bool _completed; public: - static address get_previous_sp_entry() { - return _get_previous_sp_entry; - } - - static address f2i_fixup() { - return _f2i_fixup; - } - - static address f2l_fixup() { - return _f2l_fixup; - } - - static address d2i_fixup() { - return _d2i_fixup; - } - - static address d2l_fixup() { - return _d2l_fixup; - } - - static address float_sign_mask() { - return _float_sign_mask; - } - - static address float_sign_flip() { - return _float_sign_flip; - } - - static address double_sign_mask() { - return _double_sign_mask; - } - - static address double_sign_flip() { - return _double_sign_flip; - } - static address zero_blocks() { return _zero_blocks; } @@ -142,10 +93,6 @@ class riscv { return _string_indexof_linear_uu; } - static address large_byte_array_inflate() { - return _large_byte_array_inflate; - } - static bool complete() { return _completed; } diff --git a/src/hotspot/cpu/s390/assembler_s390.hpp b/src/hotspot/cpu/s390/assembler_s390.hpp index c98c100a068..60e347a2d92 100644 --- a/src/hotspot/cpu/s390/assembler_s390.hpp +++ b/src/hotspot/cpu/s390/assembler_s390.hpp @@ -1236,6 +1236,9 @@ class Assembler : public AbstractAssembler { // NOR #define VNO_ZOPC (unsigned long)(0xe7L << 40 | 0x6bL << 0) // V1 := !(V2 | V3), element size = 2**m + //NOT-XOR +#define VNX_ZOPC (unsigned long)(0xe7L << 40 | 0x6cL << 0) // V1 := !(V2 | V3), element size = 2**m + // OR #define VO_ZOPC (unsigned long)(0xe7L << 40 | 0x6aL << 0) // V1 := V2 | V3, element size = 2**m @@ -1287,6 +1290,13 @@ class Assembler : public AbstractAssembler { #define VSTRC_ZOPC (unsigned long)(0xe7L << 40 | 0x8aL << 0) // String range compare #define VISTR_ZOPC (unsigned long)(0xe7L << 40 | 0x5cL << 0) // Isolate String +#define VFA_ZOPC (unsigned long)(0xe7L << 40 | 0xE3L << 0) // V1 := V2 + V3, element size = 2**m +#define VFS_ZOPC (unsigned long)(0xe7L << 40 | 0xE2L << 0) // V1 := V2 - V3, element size = 2**m +#define VFM_ZOPC (unsigned long)(0xe7L << 40 | 0xE7L << 0) // V1 := V2 * V3, element size = 2**m +#define VFD_ZOPC (unsigned long)(0xe7L << 40 | 0xE5L << 0) // V1 := V2 / V3, element size = 2**m +#define VFSQ_ZOPC (unsigned long)(0xe7L << 40 | 0xCEL << 0) // V1 := sqrt of V2, element size = 2**m +#define VFLR_ZOPC (unsigned long)(0xe7L << 40 | 0xC5L << 0) // vector fp load rounded, element size = 2**m + //-------------------------------- //-- Miscellaneous Operations -- @@ -2322,22 +2332,22 @@ class Assembler : public AbstractAssembler { inline void z_xilf(Register r1, int64_t i2); // xor r1 = r1 ^ i2_imm32 ; or only for bits 32-63 // shift - inline void z_sla( Register r1, int64_t d2, Register b2=Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, only 31 bits shifted, sign preserved! - inline void z_slak(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int32, only 31 bits shifted, sign preserved! - inline void z_slag(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, only 63 bits shifted, sign preserved! - inline void z_sra( Register r1, int64_t d2, Register b2=Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, sign extended - inline void z_srak(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int32, sign extended - inline void z_srag(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, sign extended - inline void z_sll( Register r1, int64_t d2, Register b2=Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, zeros added - inline void z_sllk(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int32, zeros added - inline void z_sllg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, zeros added - inline void z_srl( Register r1, int64_t d2, Register b2=Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, zero extended - inline void z_srlk(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int32, zero extended - inline void z_srlg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, zero extended + inline void z_sla( Register r1, int64_t d2, Register b2 = Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, only 31 bits shifted, sign preserved! + inline void z_slak(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int32, only 31 bits shifted, sign preserved! + inline void z_slag(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, only 63 bits shifted, sign preserved! + inline void z_sra( Register r1, int64_t d2, Register b2 = Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, sign extended + inline void z_srak(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int32, sign extended + inline void z_srag(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, sign extended + inline void z_sll( Register r1, int64_t d2, Register b2 = Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, zeros added + inline void z_sllk(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int32, zeros added + inline void z_sllg(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, zeros added + inline void z_srl( Register r1, int64_t d2, Register b2 = Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, zero extended + inline void z_srlk(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int32, zero extended + inline void z_srlg(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, zero extended // rotate - inline void z_rll( Register r1, Register r3, int64_t d2, Register b2=Z_R0); // rot r1 = r3 << (d2+b2 & 0x3f) ; int32 -- z10 - inline void z_rllg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // rot r1 = r3 << (d2+b2 & 0x3f) ; int64 -- z10 + inline void z_rll( Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // rot r1 = r3 << (d2+b2 & 0x3f) ; int32 -- z10 + inline void z_rllg(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // rot r1 = r3 << (d2+b2 & 0x3f) ; int64 -- z10 // rotate the AND/XOR/OR/insert inline void z_rnsbg( Register r1, Register r2, int64_t spos3, int64_t epos4, int64_t nrot5, bool test_only = false); // rotate then AND selected bits -- z196 @@ -2459,7 +2469,7 @@ class Assembler : public AbstractAssembler { inline void z_mvc(const Address& d, const Address& s, int64_t l); // move l bytes inline void z_mvc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2); // move l+1 bytes inline void z_mvcin(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2); // move l+1 bytes - inline void z_mvcle(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // move region of memory + inline void z_mvcle(Register r1, Register r3, int64_t d2, Register b2 = Z_R0); // move region of memory inline void z_stfle(int64_t d2, Register b2); // store facility list extended @@ -2491,6 +2501,7 @@ class Assembler : public AbstractAssembler { // Load (transfer from memory) inline void z_vlm( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); inline void z_vl( VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vl( VectorRegister v1, const Address& a); inline void z_vleb( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); inline void z_vleh( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); inline void z_vlef( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); @@ -2529,10 +2540,10 @@ class Assembler : public AbstractAssembler { inline void z_vlgvg( Register r1, VectorRegister v3, int64_t d2, Register b2); inline void z_vlvg( VectorRegister v1, Register r3, int64_t d2, Register b2, int64_t m4); - inline void z_vlvgb( VectorRegister v1, Register r3, int64_t d2, Register b2); - inline void z_vlvgh( VectorRegister v1, Register r3, int64_t d2, Register b2); - inline void z_vlvgf( VectorRegister v1, Register r3, int64_t d2, Register b2); - inline void z_vlvgg( VectorRegister v1, Register r3, int64_t d2, Register b2); + inline void z_vlvgb( VectorRegister v1, Register r3, int64_t d2, Register b2 = Z_R0); + inline void z_vlvgh( VectorRegister v1, Register r3, int64_t d2, Register b2 = Z_R0); + inline void z_vlvgf( VectorRegister v1, Register r3, int64_t d2, Register b2 = Z_R0); + inline void z_vlvgg( VectorRegister v1, Register r3, int64_t d2, Register b2 = Z_R0); inline void z_vlvgp( VectorRegister v1, Register r2, Register r3); @@ -2619,6 +2630,7 @@ class Assembler : public AbstractAssembler { // Store inline void z_vstm( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2); inline void z_vst( VectorRegister v1, int64_t d2, Register x2, Register b2); + inline void z_vst( VectorRegister v1, const Address& a); inline void z_vsteb( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); inline void z_vsteh( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); inline void z_vstef( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t m3); @@ -2679,13 +2691,16 @@ class Assembler : public AbstractAssembler { inline void z_vscbiq( VectorRegister v1, VectorRegister v2, VectorRegister v3); // MULTIPLY - inline void z_vml( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); - inline void z_vmh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); - inline void z_vmlh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); - inline void z_vme( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); - inline void z_vmle( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); - inline void z_vmo( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); - inline void z_vmlo( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vml( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmlb( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmlhw(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmlf( VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vmh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmlh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vme( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmle( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmo( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vmlo( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); // MULTIPLY & ADD inline void z_vmal( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t m5); @@ -2744,6 +2759,9 @@ class Assembler : public AbstractAssembler { // NOR inline void z_vno( VectorRegister v1, VectorRegister v2, VectorRegister v3); + //NOT-XOR + inline void z_vnx( VectorRegister v1, VectorRegister v2, VectorRegister v3); + // OR inline void z_vo( VectorRegister v1, VectorRegister v2, VectorRegister v3); @@ -2810,6 +2828,10 @@ class Assembler : public AbstractAssembler { inline void z_vctzf( VectorRegister v1, VectorRegister v2); inline void z_vctzg( VectorRegister v1, VectorRegister v2); inline void z_vpopct( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vpopctb(VectorRegister v1, VectorRegister v2); + inline void z_vpopcth(VectorRegister v1, VectorRegister v2); + inline void z_vpopctf(VectorRegister v1, VectorRegister v2); + inline void z_vpopctg(VectorRegister v1, VectorRegister v2); // Rotate/Shift inline void z_verllv( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); @@ -2898,9 +2920,39 @@ class Assembler : public AbstractAssembler { inline void z_vistrfs(VectorRegister v1, VectorRegister v2); - // Floatingpoint instructions + // Vector Floatingpoint instructions // ========================== + // Add + inline void z_vfa( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vfasb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vfadb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + + //SUB + inline void z_vfs( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vfssb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vfsdb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + + //MUL + inline void z_vfm( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vfmsb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vfmdb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + + //DIV + inline void z_vfd( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4); + inline void z_vfdsb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + inline void z_vfddb(VectorRegister v1, VectorRegister v2, VectorRegister v3); + + //square root + inline void z_vfsq( VectorRegister v1, VectorRegister v2, int64_t m3); + inline void z_vfsqsb(VectorRegister v1, VectorRegister v2); + inline void z_vfsqdb(VectorRegister v1, VectorRegister v2); + + //vector fp load rounded + inline void z_vflr( VectorRegister v1, VectorRegister v2, int64_t m3, int64_t m5); + inline void z_vflrd( VectorRegister v1, VectorRegister v2, int64_t m5); + // Floatingpoint instructions + // ========================== // compare instructions inline void z_cebr(FloatRegister r1, FloatRegister r2); // compare (r1, r2) ; float inline void z_ceb(FloatRegister r1, int64_t d2, Register x2, Register b2); // compare (r1, *(d2_imm12+x2+b2)) ; float diff --git a/src/hotspot/cpu/s390/assembler_s390.inline.hpp b/src/hotspot/cpu/s390/assembler_s390.inline.hpp index 78ce87ddeb7..e9277b8bb6f 100644 --- a/src/hotspot/cpu/s390/assembler_s390.inline.hpp +++ b/src/hotspot/cpu/s390/assembler_s390.inline.hpp @@ -787,6 +787,7 @@ inline void Assembler::z_vleb( VectorRegister v1, int64_t d2, Register x2, Reg inline void Assembler::z_vleh( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t ix3){emit_48(VLEH_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | uimm4(ix3, 32, 48)); } inline void Assembler::z_vlef( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t ix3){emit_48(VLEF_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | uimm4(ix3, 32, 48)); } inline void Assembler::z_vleg( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t ix3){emit_48(VLEG_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | uimm4(ix3, 32, 48)); } +inline void Assembler::z_vl(VectorRegister v1, const Address& a) { z_vl(v1, a.disp(), a.indexOrR0(), a.baseOrR0()); } // Gather/Scatter inline void Assembler::z_vgef( VectorRegister v1, int64_t d2, VectorRegister vx2, Register b2, int64_t ix3) {emit_48(VGEF_ZOPC | vreg(v1, 8) | rvmask_48(d2, vx2, b2) | uimm4(ix3, 32, 48)); } @@ -820,7 +821,7 @@ inline void Assembler::z_vlgvh( Register r1, VectorRegister v3, int64_t d2, Reg inline void Assembler::z_vlgvf( Register r1, VectorRegister v3, int64_t d2, Register b2) {z_vlgv(r1, v3, d2, b2, VRET_FW); } // load FW from VR element (index d2(b2)) into GR (logical) inline void Assembler::z_vlgvg( Register r1, VectorRegister v3, int64_t d2, Register b2) {z_vlgv(r1, v3, d2, b2, VRET_DW); } // load DW from VR element (index d2(b2)) into GR. -inline void Assembler::z_vlvg( VectorRegister v1, Register r3, int64_t d2, Register b2, int64_t m4) {emit_48(VLVG_ZOPC | vreg(v1, 8) | reg(r3, 12, 48) | rsmask_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vlvg( VectorRegister v1, Register r3, int64_t d2, Register b2, int64_t m4) {emit_48(VLVG_ZOPC | vreg(v1, 8) | reg(r3, 12, 48) | rsmaskt_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } inline void Assembler::z_vlvgb( VectorRegister v1, Register r3, int64_t d2, Register b2) {z_vlvg(v1, r3, d2, b2, VRET_BYTE); } inline void Assembler::z_vlvgh( VectorRegister v1, Register r3, int64_t d2, Register b2) {z_vlvg(v1, r3, d2, b2, VRET_HW); } inline void Assembler::z_vlvgf( VectorRegister v1, Register r3, int64_t d2, Register b2) {z_vlvg(v1, r3, d2, b2, VRET_FW); } @@ -916,6 +917,7 @@ inline void Assembler::z_vsteh( VectorRegister v1, int64_t d2, Register x2, Reg inline void Assembler::z_vstef( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t ix3){emit_48(VSTEF_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | uimm4(ix3, 32, 48)); } inline void Assembler::z_vsteg( VectorRegister v1, int64_t d2, Register x2, Register b2, int64_t ix3){emit_48(VSTEG_ZOPC | vreg(v1, 8) | rxmask_48(d2, x2, b2) | uimm4(ix3, 32, 48)); } inline void Assembler::z_vstl( VectorRegister v1, Register r3, int64_t d2, Register b2) {emit_48(VSTL_ZOPC | vreg(v1, 8) | reg(r3, 12, 48) | rsmask_48(d2, b2)); } +inline void Assembler::z_vst(VectorRegister v1, const Address& a) { z_vst(v1, a.disp(), a.indexOrR0(), a.baseOrR0()); } // Misc inline void Assembler::z_vgm( VectorRegister v1, int64_t imm2, int64_t imm3, int64_t m4) {emit_48(VGM_ZOPC | vreg(v1, 8) | uimm8( imm2, 16, 48) | uimm8(imm3, 24, 48) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } @@ -973,6 +975,9 @@ inline void Assembler::z_vscbiq( VectorRegister v1, VectorRegister v2, VectorReg // MULTIPLY inline void Assembler::z_vml( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VML_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } inline void Assembler::z_vmh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } +inline void Assembler::z_vmlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vml(v1, v2, v3, VRET_BYTE);} // vector element type 'B' +inline void Assembler::z_vmlhw( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vml(v1, v2, v3, VRET_HW);} // vector element type 'H' +inline void Assembler::z_vmlf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vml(v1, v2, v3, VRET_FW);} // vector element type 'F' inline void Assembler::z_vmlh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMLH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } inline void Assembler::z_vme( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VME_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } inline void Assembler::z_vmle( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMLE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_FW, 32)); } @@ -1035,6 +1040,9 @@ inline void Assembler::z_vx( VectorRegister v1, VectorRegister v2, VectorReg // NOR inline void Assembler::z_vno( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VNO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } +//NOT-XOR +inline void Assembler::z_vnx( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VNX_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } + // OR inline void Assembler::z_vo( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); } @@ -1101,6 +1109,10 @@ inline void Assembler::z_vctzh( VectorRegister v1, VectorRegister v2) inline void Assembler::z_vctzf( VectorRegister v1, VectorRegister v2) {z_vctz(v1, v2, VRET_FW); } // vector element type 'F' inline void Assembler::z_vctzg( VectorRegister v1, VectorRegister v2) {z_vctz(v1, v2, VRET_DW); } // vector element type 'G' inline void Assembler::z_vpopct( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VPOPCT_ZOPC| vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_vpopctb( VectorRegister v1, VectorRegister v2) {z_vpopct(v1, v2, VRET_BYTE); } +inline void Assembler::z_vpopcth( VectorRegister v1, VectorRegister v2) {z_vpopct(v1, v2, VRET_HW); } +inline void Assembler::z_vpopctf( VectorRegister v1, VectorRegister v2) {z_vpopct(v1, v2, VRET_FW); } +inline void Assembler::z_vpopctg( VectorRegister v1, VectorRegister v2) {z_vpopct(v1, v2, VRET_DW); } // Rotate/Shift inline void Assembler::z_verllv( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VERLLV_ZOPC| vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } @@ -1108,7 +1120,7 @@ inline void Assembler::z_verllvb(VectorRegister v1, VectorRegister v2, VectorReg inline void Assembler::z_verllvh(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_verllv(v1, v2, v3, VRET_HW); } // vector element type 'H' inline void Assembler::z_verllvf(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_verllv(v1, v2, v3, VRET_FW); } // vector element type 'F' inline void Assembler::z_verllvg(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_verllv(v1, v2, v3, VRET_DW); } // vector element type 'G' -inline void Assembler::z_verll( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4) {emit_48(VERLL_ZOPC | vreg(v1, 8) | vreg(v3, 12) | rsmask_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } +inline void Assembler::z_verll( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2, int64_t m4) {emit_48(VERLL_ZOPC | vreg(v1, 8) | vreg(v3, 12) | rsmask_48(d2, b2) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); } inline void Assembler::z_verllb( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_verll(v1, v3, d2, b2, VRET_BYTE);}// vector element type 'B' inline void Assembler::z_verllh( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_verll(v1, v3, d2, b2, VRET_HW);} // vector element type 'H' inline void Assembler::z_verllf( VectorRegister v1, VectorRegister v3, int64_t d2, Register b2) {z_verll(v1, v3, d2, b2, VRET_FW);} // vector element type 'F' @@ -1188,12 +1200,41 @@ inline void Assembler::z_vistrbs(VectorRegister v1, VectorRegister v2) inline void Assembler::z_vistrhs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_HW, VOPRC_CCSET); } inline void Assembler::z_vistrfs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_FW, VOPRC_CCSET); } +//------------------------------- +// Vector FLOAT INSTRUCTIONS +//------------------------------- +// ADD +inline void Assembler::z_vfa( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VFA_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_FW, VRET_QW, 32)); } +inline void Assembler::z_vfasb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vfa(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vfadb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vfa(v1, v2, v3, VRET_DW); } // vector element type 'G' + +// SUB +inline void Assembler::z_vfs( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VFS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_FW, VRET_QW, 32)); } +inline void Assembler::z_vfssb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vfs(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vfsdb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vfs(v1, v2, v3, VRET_DW); } // vector element type 'G' + +// MUL +inline void Assembler::z_vfm( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VFM_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_FW, VRET_QW, 32)); } +inline void Assembler::z_vfmsb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vfm(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vfmdb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vfm(v1, v2, v3, VRET_DW); } // vector element type 'G' + +// DIV +inline void Assembler::z_vfd( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VFD_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_FW, VRET_QW, 32)); } +inline void Assembler::z_vfdsb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vfd(v1, v2, v3, VRET_FW); } // vector element type 'F' +inline void Assembler::z_vfddb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vfd(v1, v2, v3, VRET_DW); } // vector element type 'G' + +// square root +inline void Assembler::z_vfsq( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VFSQ_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_FW, VRET_QW, 32)); } +inline void Assembler::z_vfsqsb( VectorRegister v1, VectorRegister v2) {z_vfsq(v1, v2, VRET_FW); } +inline void Assembler::z_vfsqdb( VectorRegister v1, VectorRegister v2) {z_vfsq(v1, v2, VRET_DW); } + +// vector fp load rounded +inline void Assembler::z_vflr( VectorRegister v1, VectorRegister v2, int64_t m5, int64_t m3) {emit_48(VFLR_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m5, VRET_FW, 7, 24) | vesc_mask(m3, VRET_FW, VRET_QW, 32)); } +inline void Assembler::z_vflrd( VectorRegister v1, VectorRegister v2, int64_t m5) {z_vflr(v1, v2, m5, VRET_DW); } //------------------------------- // FLOAT INSTRUCTIONS //------------------------------- - -//---------------- // LOAD //---------------- inline void Assembler::z_ler( FloatRegister r1, FloatRegister r2) { emit_16( LER_ZOPC | fregt(r1,8,16) | freg(r2,12,16)); } diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp index 378d5e4cfe1..c8393fe0e60 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp @@ -169,6 +169,7 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R #endif clear_reg(Z_R0); // make sure register is properly initialized. +#if 0 if (VM_Version::has_VectorFacility()) { const int min_vcnt = 32; // Minimum #characters required to use vector instructions. // Otherwise just do nothing in vector mode. @@ -223,6 +224,7 @@ unsigned int C2_MacroAssembler::string_compress(Register result, Register src, R bind(VectorDone); } +#endif { const int min_cnt = 8; // Minimum #characters required to use unrolled loop. @@ -461,6 +463,7 @@ unsigned int C2_MacroAssembler::string_inflate(Register src, Register dst, Regis #endif clear_reg(Z_R0); // make sure register is properly initialized. +#if 0 if (VM_Version::has_VectorFacility()) { const int min_vcnt = 32; // Minimum #characters required to use vector instructions. // Otherwise just do nothing in vector mode. @@ -489,6 +492,7 @@ unsigned int C2_MacroAssembler::string_inflate(Register src, Register dst, Regis bind(VectorDone); } +#endif const int min_cnt = 8; // Minimum #characters required to use unrolled scalar loop. // Otherwise just do nothing in unrolled scalar mode. @@ -623,6 +627,7 @@ unsigned int C2_MacroAssembler::string_inflate_const(Register src, Register dst, bool restore_inputs = false; bool workreg_clear = false; +#if 0 if ((len >= 32) && VM_Version::has_VectorFacility()) { const int min_vcnt = 32; // Minimum #characters required to use vector instructions. // Otherwise just do nothing in vector mode. @@ -678,6 +683,7 @@ unsigned int C2_MacroAssembler::string_inflate_const(Register src, Register dst, src_off += min_vcnt; dst_off += min_vcnt*2; } +#endif if ((len-nprocessed) > 8) { const int min_cnt = 8; // Minimum #characters required to use unrolled scalar loop. diff --git a/src/hotspot/cpu/s390/c2_globals_s390.hpp b/src/hotspot/cpu/s390/c2_globals_s390.hpp index 0192cb716ba..1de38f100f6 100644 --- a/src/hotspot/cpu/s390/c2_globals_s390.hpp +++ b/src/hotspot/cpu/s390/c2_globals_s390.hpp @@ -60,7 +60,7 @@ define_pd_global(bool, UseCISCSpill, true); define_pd_global(bool, OptoBundling, false); define_pd_global(bool, OptoScheduling, false); define_pd_global(bool, OptoRegScheduling, false); -define_pd_global(bool, SuperWordLoopUnrollAnalysis, false); +define_pd_global(bool, SuperWordLoopUnrollAnalysis, true); // On s390x, we can clear the array with a single instruction, // so don't idealize it. define_pd_global(bool, IdealizeClearArrayNode, false); diff --git a/src/hotspot/cpu/s390/globals_s390.hpp b/src/hotspot/cpu/s390/globals_s390.hpp index fb5892ba62f..cf4be20397c 100644 --- a/src/hotspot/cpu/s390/globals_s390.hpp +++ b/src/hotspot/cpu/s390/globals_s390.hpp @@ -107,6 +107,11 @@ define_pd_global(intx, InitArrayShortSize, 1*BytesPerLong); /* Seems to pay off with 2 pages already. */ \ product(size_t, MVCLEThreshold, +2*(4*K), DIAGNOSTIC, \ "Threshold above which page-aligned MVCLE copy/init is used.") \ + /* special instructions */ \ + product(bool, SuperwordUseVX, false, \ + "Use Z15 Vector instructions for superword optimization.") \ + product(bool, UseSFPV, false, DIAGNOSTIC, \ + "Use SFPV Vector instructions for superword optimization.") \ \ product(bool, PreferLAoverADD, false, DIAGNOSTIC, \ "Use LA/LAY instructions over ADD instructions (z/Architecture).") \ diff --git a/src/hotspot/cpu/s390/registerSaver_s390.hpp b/src/hotspot/cpu/s390/registerSaver_s390.hpp index 97883685384..13674f1562d 100644 --- a/src/hotspot/cpu/s390/registerSaver_s390.hpp +++ b/src/hotspot/cpu/s390/registerSaver_s390.hpp @@ -47,10 +47,11 @@ class RegisterSaver { // Boolean flags to force only argument registers to be saved. static int live_reg_save_size(RegisterSet reg_set); - static int live_reg_frame_size(RegisterSet reg_set); + static int live_reg_frame_size(RegisterSet reg_set, bool save_vectors = false); + static int calculate_vregstosave_num(); // Specify the register that should be stored as the return pc in the current frame. - static OopMap* save_live_registers(MacroAssembler* masm, RegisterSet reg_set, Register return_pc = Z_R14); - static void restore_live_registers(MacroAssembler* masm, RegisterSet reg_set); + static OopMap* save_live_registers(MacroAssembler* masm, RegisterSet reg_set, Register return_pc = Z_R14, bool save_vectors = false); + static void restore_live_registers(MacroAssembler* masm, RegisterSet reg_set, bool save_vectors = false); // Generate the OopMap (again, regs where saved before). static OopMap* generate_oop_map(MacroAssembler* masm, RegisterSet reg_set); @@ -65,11 +66,13 @@ class RegisterSaver { int_reg = 0, float_reg = 1, excluded_reg = 2, // Not saved/restored. + v_reg = 3 } RegisterType; typedef enum { reg_size = 8, half_reg_size = reg_size / 2, + v_reg_size = 16 } RegisterConstants; // Remember type, number, and VMReg. diff --git a/src/hotspot/cpu/s390/register_s390.cpp b/src/hotspot/cpu/s390/register_s390.cpp index f055a1c0134..c0840add5d6 100644 --- a/src/hotspot/cpu/s390/register_s390.cpp +++ b/src/hotspot/cpu/s390/register_s390.cpp @@ -26,11 +26,6 @@ #include "precompiled.hpp" #include "register_s390.hpp" - -const int ConcreteRegisterImpl::max_gpr = Register::number_of_registers * 2; -const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::max_gpr + - FloatRegister::number_of_registers * 2; - const char* Register::name() const { const char* names[number_of_registers] = { "Z_R0", "Z_R1", "Z_R2", "Z_R3", "Z_R4", "Z_R5", "Z_R6", "Z_R7", @@ -54,5 +49,11 @@ const char* VectorRegister::name() const { "Z_V16", "Z_V17", "Z_V18", "Z_V19", "Z_V20", "Z_V21", "Z_V22", "Z_V23", "Z_V24", "Z_V25", "Z_V26", "Z_V27", "Z_V28", "Z_V29", "Z_V30", "Z_V31" }; - return is_valid() ? names[encoding()] : "fnoreg"; + return is_valid() ? names[encoding()] : "vnoreg"; +} + +// Method to convert a FloatRegister to a VectorRegister (VectorRegister) +VectorRegister FloatRegister::to_vr() const { + if (*this == fnoreg) { return vnoreg; } + return as_VectorRegister(encoding()); } diff --git a/src/hotspot/cpu/s390/register_s390.hpp b/src/hotspot/cpu/s390/register_s390.hpp index 18af232e569..6fcba746cd3 100644 --- a/src/hotspot/cpu/s390/register_s390.hpp +++ b/src/hotspot/cpu/s390/register_s390.hpp @@ -64,6 +64,7 @@ class Register { public: enum { number_of_registers = 16, + max_slots_per_register = 2, number_of_arg_registers = 5 }; @@ -164,12 +165,13 @@ constexpr ConditionRegister Z_CR = as_ConditionRegister(0); //========================= // The implementation of float registers for the z/Architecture. - +class VectorRegister; class FloatRegister { int _encoding; public: enum { number_of_registers = 16, + max_slots_per_register = 2, number_of_arg_registers = 4 }; @@ -192,6 +194,8 @@ class FloatRegister { constexpr bool is_nonvolatile() const { return (8 <= _encoding && _encoding <= 15); } const char* name() const; + // convert to VR + VectorRegister to_vr() const; }; inline constexpr FloatRegister as_FloatRegister(int encoding) { @@ -285,6 +289,7 @@ class VectorRegister { public: enum { number_of_registers = 32, + max_slots_per_register = 4, number_of_arg_registers = 0 }; @@ -379,21 +384,20 @@ constexpr VectorRegister Z_V31 = as_VectorRegister(31); // Need to know the total number of registers of all sorts for SharedInfo. // Define a class that exports it. - class ConcreteRegisterImpl : public AbstractRegisterImpl { public: enum { - number_of_registers = - (Register::number_of_registers + - FloatRegister::number_of_registers) - * 2 // register halves - + 1 // condition code register + 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_vr = max_fpr + VectorRegister::number_of_registers * VectorRegister::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. + number_of_registers = max_vr + 1 // gpr/fpr/vr + flags }; - static const int max_gpr; - static const int max_fpr; }; - // Common register declarations used in assembler code. constexpr Register Z_EXC_OOP = Z_R2; constexpr Register Z_EXC_PC = Z_R3; diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 63e150c9e9c..e1a98139992 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -97,8 +97,9 @@ register %{ // e.g. Z_R3_H, which is needed by the allocator, but is not used // for stores, loads, etc. - // Integer/Long Registers - // ---------------------------- +// ---------------------------- +// Integer/Long Registers +// ---------------------------- // z/Architecture has 16 64-bit integer registers. @@ -136,7 +137,9 @@ register %{ reg_def Z_R15 (NS, NS, Op_RegI, 15, Z_R15->as_VMReg()); // s SP reg_def Z_R15_H(NS, NS, Op_RegI, 99, Z_R15->as_VMReg()->next()); - // Float/Double Registers +// ---------------------------- +// Float/Double Registers +// ---------------------------- // The rules of ADL require that double registers be defined in pairs. // Each pair must be two 32-bit values, but not necessarily a pair of @@ -182,7 +185,169 @@ register %{ reg_def Z_F15 (SOC, SOE, Op_RegF, 15, Z_F15->as_VMReg()); reg_def Z_F15_H(SOC, SOE, Op_RegF, 99, Z_F15->as_VMReg()->next()); - +// ---------------------------- +// Vector Registers +// ---------------------------- + // 1st 16 VRs are aliases for the FPRs which are already defined above. + reg_def Z_VR0 ( SOC, SOC, Op_RegF, 0, VMRegImpl::Bad()); + reg_def Z_VR0_H ( SOC, SOC, Op_RegF, 0, VMRegImpl::Bad()); + reg_def Z_VR0_J ( SOC, SOC, Op_RegF, 0, VMRegImpl::Bad()); + reg_def Z_VR0_K ( SOC, SOC, Op_RegF, 0, VMRegImpl::Bad()); + + reg_def Z_VR1 ( SOC, SOC, Op_RegF, 1, VMRegImpl::Bad()); + reg_def Z_VR1_H ( SOC, SOC, Op_RegF, 1, VMRegImpl::Bad()); + reg_def Z_VR1_J ( SOC, SOC, Op_RegF, 1, VMRegImpl::Bad()); + reg_def Z_VR1_K ( SOC, SOC, Op_RegF, 1, VMRegImpl::Bad()); + + reg_def Z_VR2 ( SOC, SOC, Op_RegF, 2, VMRegImpl::Bad()); + reg_def Z_VR2_H ( SOC, SOC, Op_RegF, 2, VMRegImpl::Bad()); + reg_def Z_VR2_J ( SOC, SOC, Op_RegF, 2, VMRegImpl::Bad()); + reg_def Z_VR2_K ( SOC, SOC, Op_RegF, 2, VMRegImpl::Bad()); + + reg_def Z_VR3 ( SOC, SOC, Op_RegF, 3, VMRegImpl::Bad()); + reg_def Z_VR3_H ( SOC, SOC, Op_RegF, 3, VMRegImpl::Bad()); + reg_def Z_VR3_J ( SOC, SOC, Op_RegF, 3, VMRegImpl::Bad()); + reg_def Z_VR3_K ( SOC, SOC, Op_RegF, 3, VMRegImpl::Bad()); + + reg_def Z_VR4 ( SOC, SOC, Op_RegF, 4, VMRegImpl::Bad()); + reg_def Z_VR4_H ( SOC, SOC, Op_RegF, 4, VMRegImpl::Bad()); + reg_def Z_VR4_J ( SOC, SOC, Op_RegF, 4, VMRegImpl::Bad()); + reg_def Z_VR4_K ( SOC, SOC, Op_RegF, 4, VMRegImpl::Bad()); + + reg_def Z_VR5 ( SOC, SOC, Op_RegF, 5, VMRegImpl::Bad()); + reg_def Z_VR5_H ( SOC, SOC, Op_RegF, 5, VMRegImpl::Bad()); + reg_def Z_VR5_J ( SOC, SOC, Op_RegF, 5, VMRegImpl::Bad()); + reg_def Z_VR5_K ( SOC, SOC, Op_RegF, 5, VMRegImpl::Bad()); + + reg_def Z_VR6 ( SOC, SOC, Op_RegF, 6, VMRegImpl::Bad()); + reg_def Z_VR6_H ( SOC, SOC, Op_RegF, 6, VMRegImpl::Bad()); + reg_def Z_VR6_J ( SOC, SOC, Op_RegF, 6, VMRegImpl::Bad()); + reg_def Z_VR6_K ( SOC, SOC, Op_RegF, 6, VMRegImpl::Bad()); + + reg_def Z_VR7 ( SOC, SOC, Op_RegF, 7, VMRegImpl::Bad()); + reg_def Z_VR7_H ( SOC, SOC, Op_RegF, 7, VMRegImpl::Bad()); + reg_def Z_VR7_J ( SOC, SOC, Op_RegF, 7, VMRegImpl::Bad()); + reg_def Z_VR7_K ( SOC, SOC, Op_RegF, 7, VMRegImpl::Bad()); + + reg_def Z_VR8 ( SOC, SOC, Op_RegF, 8, VMRegImpl::Bad()); + reg_def Z_VR8_H ( SOC, SOC, Op_RegF, 8, VMRegImpl::Bad()); + reg_def Z_VR8_J ( SOC, SOC, Op_RegF, 8, VMRegImpl::Bad()); + reg_def Z_VR8_K ( SOC, SOC, Op_RegF, 8, VMRegImpl::Bad()); + + reg_def Z_VR9 ( SOC, SOC, Op_RegF, 9, VMRegImpl::Bad()); + reg_def Z_VR9_H ( SOC, SOC, Op_RegF, 9, VMRegImpl::Bad()); + reg_def Z_VR9_J ( SOC, SOC, Op_RegF, 9, VMRegImpl::Bad()); + reg_def Z_VR9_K ( SOC, SOC, Op_RegF, 9, VMRegImpl::Bad()); + + reg_def Z_VR10 ( SOC, SOC, Op_RegF, 10, VMRegImpl::Bad()); + reg_def Z_VR10_H ( SOC, SOC, Op_RegF, 10, VMRegImpl::Bad()); + reg_def Z_VR10_J ( SOC, SOC, Op_RegF, 10, VMRegImpl::Bad()); + reg_def Z_VR10_K ( SOC, SOC, Op_RegF, 10, VMRegImpl::Bad()); + + reg_def Z_VR11 ( SOC, SOC, Op_RegF, 11, VMRegImpl::Bad()); + reg_def Z_VR11_H ( SOC, SOC, Op_RegF, 11, VMRegImpl::Bad()); + reg_def Z_VR11_J ( SOC, SOC, Op_RegF, 11, VMRegImpl::Bad()); + reg_def Z_VR11_K ( SOC, SOC, Op_RegF, 11, VMRegImpl::Bad()); + + reg_def Z_VR12 ( SOC, SOC, Op_RegF, 12, VMRegImpl::Bad()); + reg_def Z_VR12_H ( SOC, SOC, Op_RegF, 12, VMRegImpl::Bad()); + reg_def Z_VR12_J ( SOC, SOC, Op_RegF, 12, VMRegImpl::Bad()); + reg_def Z_VR12_K ( SOC, SOC, Op_RegF, 12, VMRegImpl::Bad()); + + reg_def Z_VR13 ( SOC, SOC, Op_RegF, 13, VMRegImpl::Bad()); + reg_def Z_VR13_H ( SOC, SOC, Op_RegF, 13, VMRegImpl::Bad()); + reg_def Z_VR13_J ( SOC, SOC, Op_RegF, 13, VMRegImpl::Bad()); + reg_def Z_VR13_K ( SOC, SOC, Op_RegF, 13, VMRegImpl::Bad()); + + reg_def Z_VR14 ( SOC, SOC, Op_RegF, 14, VMRegImpl::Bad()); + reg_def Z_VR14_H ( SOC, SOC, Op_RegF, 14, VMRegImpl::Bad()); + reg_def Z_VR14_J ( SOC, SOC, Op_RegF, 14, VMRegImpl::Bad()); + reg_def Z_VR14_K ( SOC, SOC, Op_RegF, 14, VMRegImpl::Bad()); + + reg_def Z_VR15 ( SOC, SOC, Op_RegF, 15, VMRegImpl::Bad()); + reg_def Z_VR15_H ( SOC, SOC, Op_RegF, 15, VMRegImpl::Bad()); + reg_def Z_VR15_J ( SOC, SOC, Op_RegF, 15, VMRegImpl::Bad()); + reg_def Z_VR15_K ( SOC, SOC, Op_RegF, 15, VMRegImpl::Bad()); + + reg_def Z_VR16 ( SOC, SOC, Op_RegF, 16, Z_V16->as_VMReg() ); + reg_def Z_VR16_H ( SOC, SOC, Op_RegF, 16, Z_V16->as_VMReg()->next() ); + reg_def Z_VR16_J ( SOC, SOC, Op_RegF, 16, Z_V16->as_VMReg()->next(2) ); + reg_def Z_VR16_K ( SOC, SOC, Op_RegF, 16, Z_V16->as_VMReg()->next(3) ); + + reg_def Z_VR17 ( SOC, SOC, Op_RegF, 17, Z_V17->as_VMReg() ); + reg_def Z_VR17_H ( SOC, SOC, Op_RegF, 17, Z_V17->as_VMReg()->next() ); + reg_def Z_VR17_J ( SOC, SOC, Op_RegF, 17, Z_V17->as_VMReg()->next(2) ); + reg_def Z_VR17_K ( SOC, SOC, Op_RegF, 17, Z_V17->as_VMReg()->next(3) ); + + reg_def Z_VR18 ( SOC, SOC, Op_RegF, 18, Z_V18->as_VMReg() ); + reg_def Z_VR18_H ( SOC, SOC, Op_RegF, 18, Z_V18->as_VMReg()->next() ); + reg_def Z_VR18_J ( SOC, SOC, Op_RegF, 18, Z_V18->as_VMReg()->next(2) ); + reg_def Z_VR18_K ( SOC, SOC, Op_RegF, 18, Z_V18->as_VMReg()->next(3) ); + + reg_def Z_VR19 ( SOC, SOC, Op_RegF, 19, Z_V19->as_VMReg() ); + reg_def Z_VR19_H ( SOC, SOC, Op_RegF, 19, Z_V19->as_VMReg()->next() ); + reg_def Z_VR19_J ( SOC, SOC, Op_RegF, 19, Z_V19->as_VMReg()->next(2) ); + reg_def Z_VR19_K ( SOC, SOC, Op_RegF, 19, Z_V19->as_VMReg()->next(3) ); + + reg_def Z_VR20 ( SOC, SOC, Op_RegF, 20, Z_V20->as_VMReg() ); + reg_def Z_VR20_H ( SOC, SOC, Op_RegF, 20, Z_V20->as_VMReg()->next() ); + reg_def Z_VR20_J ( SOC, SOC, Op_RegF, 20, Z_V20->as_VMReg()->next(2) ); + reg_def Z_VR20_K ( SOC, SOC, Op_RegF, 20, Z_V20->as_VMReg()->next(3) ); + + reg_def Z_VR21 ( SOC, SOC, Op_RegF, 21, Z_V21->as_VMReg() ); + reg_def Z_VR21_H ( SOC, SOC, Op_RegF, 21, Z_V21->as_VMReg()->next() ); + reg_def Z_VR21_J ( SOC, SOC, Op_RegF, 21, Z_V21->as_VMReg()->next(2) ); + reg_def Z_VR21_K ( SOC, SOC, Op_RegF, 21, Z_V21->as_VMReg()->next(3) ); + + reg_def Z_VR22 ( SOC, SOC, Op_RegF, 22, Z_V22->as_VMReg() ); + reg_def Z_VR22_H ( SOC, SOC, Op_RegF, 22, Z_V22->as_VMReg()->next() ); + reg_def Z_VR22_J ( SOC, SOC, Op_RegF, 22, Z_V22->as_VMReg()->next(2) ); + reg_def Z_VR22_K ( SOC, SOC, Op_RegF, 22, Z_V22->as_VMReg()->next(3) ); + + reg_def Z_VR23 ( SOC, SOC, Op_RegF, 23, Z_V23->as_VMReg() ); + reg_def Z_VR23_H ( SOC, SOC, Op_RegF, 23, Z_V23->as_VMReg()->next() ); + reg_def Z_VR23_J ( SOC, SOC, Op_RegF, 23, Z_V23->as_VMReg()->next(2) ); + reg_def Z_VR23_K ( SOC, SOC, Op_RegF, 23, Z_V23->as_VMReg()->next(3) ); + + reg_def Z_VR24 ( SOC, SOC, Op_RegF, 24, Z_V24->as_VMReg() ); + reg_def Z_VR24_H ( SOC, SOC, Op_RegF, 24, Z_V24->as_VMReg()->next() ); + reg_def Z_VR24_J ( SOC, SOC, Op_RegF, 24, Z_V24->as_VMReg()->next(2) ); + reg_def Z_VR24_K ( SOC, SOC, Op_RegF, 24, Z_V24->as_VMReg()->next(3) ); + + reg_def Z_VR25 ( SOC, SOC, Op_RegF, 25, Z_V25->as_VMReg() ); + reg_def Z_VR25_H ( SOC, SOC, Op_RegF, 25, Z_V25->as_VMReg()->next() ); + reg_def Z_VR25_J ( SOC, SOC, Op_RegF, 25, Z_V25->as_VMReg()->next(2) ); + reg_def Z_VR25_K ( SOC, SOC, Op_RegF, 25, Z_V25->as_VMReg()->next(3) ); + + reg_def Z_VR26 ( SOC, SOC, Op_RegF, 26, Z_V26->as_VMReg() ); + reg_def Z_VR26_H ( SOC, SOC, Op_RegF, 26, Z_V26->as_VMReg()->next() ); + reg_def Z_VR26_J ( SOC, SOC, Op_RegF, 26, Z_V26->as_VMReg()->next(2) ); + reg_def Z_VR26_K ( SOC, SOC, Op_RegF, 26, Z_V26->as_VMReg()->next(3) ); + + reg_def Z_VR27 ( SOC, SOC, Op_RegF, 27, Z_V27->as_VMReg() ); + reg_def Z_VR27_H ( SOC, SOC, Op_RegF, 27, Z_V27->as_VMReg()->next() ); + reg_def Z_VR27_J ( SOC, SOC, Op_RegF, 27, Z_V27->as_VMReg()->next(2) ); + reg_def Z_VR27_K ( SOC, SOC, Op_RegF, 27, Z_V27->as_VMReg()->next(3) ); + + reg_def Z_VR28 ( SOC, SOC, Op_RegF, 28, Z_V28->as_VMReg() ); + reg_def Z_VR28_H ( SOC, SOC, Op_RegF, 28, Z_V28->as_VMReg()->next() ); + reg_def Z_VR28_J ( SOC, SOC, Op_RegF, 28, Z_V28->as_VMReg()->next(2) ); + reg_def Z_VR28_K ( SOC, SOC, Op_RegF, 28, Z_V28->as_VMReg()->next(3) ); + + reg_def Z_VR29 ( SOC, SOC, Op_RegF, 29, Z_V29->as_VMReg() ); + reg_def Z_VR29_H ( SOC, SOC, Op_RegF, 29, Z_V29->as_VMReg()->next() ); + reg_def Z_VR29_J ( SOC, SOC, Op_RegF, 29, Z_V29->as_VMReg()->next(2) ); + reg_def Z_VR29_K ( SOC, SOC, Op_RegF, 29, Z_V29->as_VMReg()->next(3) ); + + reg_def Z_VR30 ( SOC, SOC, Op_RegF, 30, Z_V30->as_VMReg() ); + reg_def Z_VR30_H ( SOC, SOC, Op_RegF, 30, Z_V30->as_VMReg()->next() ); + reg_def Z_VR30_J ( SOC, SOC, Op_RegF, 30, Z_V30->as_VMReg()->next(2) ); + reg_def Z_VR30_K ( SOC, SOC, Op_RegF, 30, Z_V30->as_VMReg()->next(3) ); + + reg_def Z_VR31 ( SOC, SOC, Op_RegF, 31, Z_V31->as_VMReg() ); + reg_def Z_VR31_H ( SOC, SOC, Op_RegF, 31, Z_V31->as_VMReg()->next() ); + reg_def Z_VR31_J ( SOC, SOC, Op_RegF, 31, Z_V31->as_VMReg()->next(2) ); + reg_def Z_VR31_K ( SOC, SOC, Op_RegF, 31, Z_V31->as_VMReg()->next(3) ); // Special Registers // Condition Codes Flag Registers @@ -194,7 +359,6 @@ register %{ reg_def Z_CR(SOC, SOC, Op_RegFlags, 0, Z_CR->as_VMReg()); // volatile - // Specify priority of register selection within phases of register // allocation. Highest priority is first. A useful heuristic is to // give registers a low priority when they are required by machine @@ -268,6 +432,41 @@ alloc_class chunk1( ); alloc_class chunk2( + Z_VR0, Z_VR0_H, Z_VR0_J, Z_VR0_K, + Z_VR1, Z_VR1_H, Z_VR1_J, Z_VR1_K, + Z_VR2, Z_VR2_H, Z_VR2_J, Z_VR2_K, + Z_VR3, Z_VR3_H, Z_VR3_J, Z_VR3_K, + Z_VR4, Z_VR4_H, Z_VR4_J, Z_VR4_K, + Z_VR5, Z_VR5_H, Z_VR5_J, Z_VR5_K, + Z_VR6, Z_VR6_H, Z_VR6_J, Z_VR6_K, + Z_VR7, Z_VR7_H, Z_VR7_J, Z_VR7_K, + Z_VR8, Z_VR8_H, Z_VR8_J, Z_VR8_K, + Z_VR9, Z_VR9_H, Z_VR9_J, Z_VR9_K, + Z_VR10, Z_VR10_H, Z_VR10_J, Z_VR10_K, + Z_VR11, Z_VR11_H, Z_VR11_J, Z_VR11_K, + Z_VR12, Z_VR12_H, Z_VR12_J, Z_VR12_K, + Z_VR13, Z_VR13_H, Z_VR13_J, Z_VR13_K, + Z_VR14, Z_VR14_H, Z_VR14_J, Z_VR14_K, + Z_VR15, Z_VR15_H, Z_VR15_J, Z_VR15_K, + Z_VR16, Z_VR16_H, Z_VR16_J, Z_VR16_K, + Z_VR17, Z_VR17_H, Z_VR17_J, Z_VR17_K, + Z_VR18, Z_VR18_H, Z_VR18_J, Z_VR18_K, + Z_VR19, Z_VR19_H, Z_VR19_J, Z_VR19_K, + Z_VR20, Z_VR20_H, Z_VR20_J, Z_VR20_K, + Z_VR21, Z_VR21_H, Z_VR21_J, Z_VR21_K, + Z_VR22, Z_VR22_H, Z_VR22_J, Z_VR22_K, + Z_VR23, Z_VR23_H, Z_VR23_J, Z_VR23_K, + Z_VR24, Z_VR24_H, Z_VR24_J, Z_VR24_K, + Z_VR25, Z_VR25_H, Z_VR25_J, Z_VR25_K, + Z_VR26, Z_VR26_H, Z_VR26_J, Z_VR26_K, + Z_VR27, Z_VR27_H, Z_VR27_J, Z_VR27_K, + Z_VR28, Z_VR28_H, Z_VR28_J, Z_VR28_K, + Z_VR29, Z_VR29_H, Z_VR29_J, Z_VR29_K, + Z_VR30, Z_VR30_H, Z_VR30_J, Z_VR30_K, + Z_VR31, Z_VR31_H, Z_VR31_J, Z_VR31_K +); + +alloc_class chunk3( Z_CR ); @@ -542,6 +741,27 @@ reg_class z_dbl_reg( ); reg_class z_rscratch1_dbl_reg(Z_F1,Z_F1_H); +reg_class z_v_reg( + // Attention: Only these ones are saved & restored at safepoint by RegisterSaver. + //1st 16 VRs overlaps with 1st 16 FPRs. + Z_VR16, Z_VR16_H, Z_VR16_J, Z_VR16_K, + Z_VR17, Z_VR17_H, Z_VR17_J, Z_VR17_K, + Z_VR18, Z_VR18_H, Z_VR18_J, Z_VR18_K, + Z_VR19, Z_VR19_H, Z_VR19_J, Z_VR19_K, + Z_VR20, Z_VR20_H, Z_VR20_J, Z_VR20_K, + Z_VR21, Z_VR21_H, Z_VR21_J, Z_VR21_K, + Z_VR22, Z_VR22_H, Z_VR22_J, Z_VR22_K, + Z_VR23, Z_VR23_H, Z_VR23_J, Z_VR23_K, + Z_VR24, Z_VR24_H, Z_VR24_J, Z_VR24_K, + Z_VR25, Z_VR25_H, Z_VR25_J, Z_VR25_K, + Z_VR26, Z_VR26_H, Z_VR26_J, Z_VR26_K, + Z_VR27, Z_VR27_H, Z_VR27_J, Z_VR27_K, + Z_VR28, Z_VR28_H, Z_VR28_J, Z_VR28_K, + Z_VR29, Z_VR29_H, Z_VR29_J, Z_VR29_K, + Z_VR30, Z_VR30_H, Z_VR30_J, Z_VR30_K, + Z_VR31, Z_VR31_H, Z_VR31_J, Z_VR31_K +); + %} //----------DEFINITION BLOCK--------------------------------------------------- @@ -953,8 +1173,8 @@ const Pipeline * MachEpilogNode::pipeline() const { //============================================================================= -// Figure out which register class each belongs in: rc_int, rc_float, rc_stack. -enum RC { rc_bad, rc_int, rc_float, rc_stack }; +// Figure out which register class each belongs in: rc_int, rc_float, rc_vector, rc_stack. +enum RC { rc_bad, rc_int, rc_float, rc_vector, rc_stack }; static enum RC rc_class(OptoReg::Name reg) { // Return the register class for the given register. The given register @@ -975,8 +1195,13 @@ static enum RC rc_class(OptoReg::Name reg) { return rc_float; } + // we have 128 vector register halves at index 64 + if (reg < 32+32+128) { + return rc_vector; + } + // Between float regs & stack are the flags regs. - assert(reg >= OptoReg::stack0(), "blow up if spilling flags"); + assert(OptoReg::is_stack(reg) || reg < 32+32+128, "blow up if spilling flags"); return rc_stack; } @@ -1035,7 +1260,7 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r "expected aligned-adjacent pairs"); // Generate spill code! - + int size = 0; if (src_lo == dst_lo && src_hi == dst_hi) { return 0; // Self copy, no move. } @@ -1049,6 +1274,37 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r const char *mnemo = nullptr; unsigned long opc = 0; + if (bottom_type()->isa_vect() != nullptr && ideal_reg() == Op_VecX) { + if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { + if (masm != nullptr) { + __ z_mvc(Address(Z_SP, 0, dst_offset), Address(Z_SP, 0, src_offset), 16); + } + size += 6; + } else if (src_lo_rc == rc_vector && dst_lo_rc == rc_stack) { + VectorRegister Rsrc = as_VectorRegister(Matcher::_regEncode[src_lo]); + if (masm != nullptr) { + __ z_vst(Rsrc, Address(Z_SP, 0, dst_offset)); + } + size += 6; + } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_vector) { + VectorRegister Rdst = as_VectorRegister(Matcher::_regEncode[dst_lo]); + if (masm != nullptr) { + __ z_vl(Rdst, Address(Z_SP, 0, src_offset)); + } + size += 6; + } else if (src_lo_rc == rc_vector && dst_lo_rc == rc_vector) { + VectorRegister Rsrc = as_VectorRegister(Matcher::_regEncode[src_lo]); + VectorRegister Rdst = as_VectorRegister(Matcher::_regEncode[dst_lo]); + if (masm != nullptr) { + __ z_vlr(Rdst, Rsrc); + } + size += 6; + } else { + ShouldNotReachHere(); + } + return size; + } + // Memory->Memory Spill. Use Z_R0 to hold the value. if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { @@ -1283,7 +1539,7 @@ source_hpp %{ // // To keep related declarations/definitions/uses close together, // we switch between source %{ }% and source_hpp %{ }% freely as needed. - +#include "opto/convertnode.hpp" #include "oops/klass.inline.hpp" //-------------------------------------------------------------- @@ -1446,6 +1702,32 @@ bool Matcher::match_rule_supported(int opcode) { case Op_PopCountL: // PopCount supported by H/W from z/Architecture G5 (z196) on. return (UsePopCountInstruction && VM_Version::has_PopCount()); + case Op_AddVB: + case Op_AddVS: + case Op_AddVI: + case Op_AddVL: + case Op_AddVD: + case Op_SubVB: + case Op_SubVS: + case Op_SubVI: + case Op_SubVL: + case Op_SubVD: + case Op_MulVB: + case Op_MulVS: + case Op_MulVI: + case Op_MulVD: + case Op_DivVD: + case Op_SqrtVD: + case Op_RoundDoubleModeV: + return SuperwordUseVX; + case Op_AddVF: + case Op_SubVF: + case Op_MulVF: + case Op_DivVF: + case Op_SqrtVF: + //PopCountVI supported by z14 onwards. + case Op_PopCountVI: + return (SuperwordUseVX && UseSFPV); case Op_FmaF: case Op_FmaD: return UseFMA; @@ -1491,14 +1773,24 @@ OptoRegPair Matcher::vector_return_value(uint ideal_reg) { // Vector width in bytes. int Matcher::vector_width_in_bytes(BasicType bt) { - assert(MaxVectorSize == 8, ""); - return 8; + if (SuperwordUseVX) { + assert(MaxVectorSize == 16, ""); + return 16; + } else { + assert(MaxVectorSize == 8, ""); + return 8; + } } // Vector ideal reg. uint Matcher::vector_ideal_reg(int size) { - assert(MaxVectorSize == 8 && size == 8, ""); - return Op_RegL; + if (SuperwordUseVX) { + assert(MaxVectorSize == 16 && size == 16, ""); + return Op_VecX; + } else { + assert(MaxVectorSize == 8 && size == 8, ""); + return Op_RegL; + } } // Limits on vector size (number of elements) loaded into vector. @@ -2391,6 +2683,14 @@ ins_attrib ins_should_rematerialize(false); // Immediate Operands // Please note: // Formats are generated automatically for constants and base registers. +operand vecX() %{ + constraint(ALLOC_IN_RC(z_v_reg)); + match(VecX); + + format %{ %} + interface(REG_INTER); +%} + //---------------------------------------------- // SIGNED (shorter than INT) immediate operands @@ -10534,6 +10834,45 @@ instruct Repl4S_immm1(iRegL dst, immS_minus1 src) %{ ins_pipe(pipe_class_dummy); %} +instruct repl8S_reg_Ex(vecX dst, iRegI src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 8 && + Matcher::vector_element_basic_type(n) == T_SHORT); + + size(12); + ins_encode %{ + __ z_vlvgh($dst$$VectorRegister, $src$$Register, 0); + __ z_vreph($dst$$VectorRegister, $dst$$VectorRegister, 0); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl8S_immIminus1(vecX dst, immI_minus1 src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 8 && + Matcher::vector_element_basic_type(n) == T_SHORT); + + format %{ "VONE $dst, $src \t// replicate8S" %} + size(6); + ins_encode %{ + __ z_vone($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl8S_immI0(vecX dst, immI_0 zero) %{ + match(Set dst (Replicate zero)); + predicate(n->as_Vector()->length() == 8 && + Matcher::vector_element_basic_type(n) == T_SHORT); + + format %{ "VZERO $dst, $zero \t// replicate8S" %} + size(6); + ins_encode %{ + __ z_vzero($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + // Exploit rotate_then_insert, if available. // Replicate scalar int to packed int values (8 Bytes). instruct Repl2I_reg_risbg(iRegL dst, iRegI src, flagsReg cr) %{ @@ -10586,7 +10925,44 @@ instruct Repl2I_immm1(iRegL dst, immI_minus1 src) %{ ins_pipe(pipe_class_dummy); %} -// +instruct repl4I_reg_Ex(vecX dst, iRegI src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 4 && + Matcher::vector_element_basic_type(n) == T_INT); + + size(12); + ins_encode %{ + __ z_vlvgf($dst$$VectorRegister, $src$$Register, 0); + __ z_vrepf($dst$$VectorRegister, $dst$$VectorRegister, 0); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl4I_immI0(vecX dst, immI_0 zero) %{ + match(Set dst (Replicate zero)); + predicate(n->as_Vector()->length() == 4 && + Matcher::vector_element_basic_type(n) == T_INT); + + format %{ "VZERO $dst, $zero \t// replicate4I" %} + size(6); + ins_encode %{ + __ z_vzero($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl4I_immIminus1(vecX dst, immI_minus1 src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 4 && + Matcher::vector_element_basic_type(n) == T_INT); + + format %{ "VONE $dst, $dst, $dst \t// replicate4I" %} + size(6); + ins_encode %{ + __ z_vone($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} instruct Repl2F_reg_indirect(iRegL dst, regF src, flagsReg cr) %{ match(Set dst (Replicate src)); @@ -10650,6 +11026,139 @@ instruct Repl2F_imm0(iRegL dst, immFp0 src) %{ ins_pipe(pipe_class_dummy); %} +instruct repl4F_reg_Ex(vecX dst, regF src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 4 && + Matcher::vector_element_basic_type(n) == T_FLOAT); + + format %{ "VREP $dst, $src \t// replicate4F" %} + size(6); + + ins_encode %{ + __ z_vrepf($dst$$VectorRegister, $src$$FloatRegister->to_vr(), 0); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl4F_immF0(vecX dst, immFp0 zero) %{ + match(Set dst (Replicate zero)); + predicate(n->as_Vector()->length() == 4 && + Matcher::vector_element_basic_type(n) == T_FLOAT); + + format %{ "VZERO $dst, $zero \t// replicate4F" %} + size(6); + ins_encode %{ + __ z_vzero($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl2D_reg_Ex(vecX dst, regD src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 2 && + Matcher::vector_element_basic_type(n) == T_DOUBLE); + + format %{ "VREP $dst, $src \t// replicate2D" %} + size(6); + + ins_encode %{ + __ z_vrepg($dst$$VectorRegister, $src$$FloatRegister->to_vr(), 0); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl2D_immD0(vecX dst, immDp0 zero) %{ + match(Set dst (Replicate zero)); + predicate(n->as_Vector()->length() == 2 && + Matcher::vector_element_basic_type(n) == T_DOUBLE); + + format %{ "VZERO $dst, $zero \t// replicate2D" %} + size(6); + ins_encode %{ + __ z_vzero($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl16B_reg_Ex(vecX dst, iRegI src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 16 && + Matcher::vector_element_basic_type(n) == T_BYTE); + + size(12); + ins_encode %{ + __ z_vlvgb($dst$$VectorRegister, $src$$Register, 0); + __ z_vrepb($dst$$VectorRegister, $dst$$VectorRegister, 0); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl16B_immIminus1(vecX dst, immI_minus1 src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 16 && + Matcher::vector_element_basic_type(n) == T_BYTE); + + format %{ "VONE $dst, $src \t// replicate16B" %} + size(6); + ins_encode %{ + __ z_vone($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl16B_immI0(vecX dst, immI_0 zero) %{ + match(Set dst (Replicate zero)); + predicate(n->as_Vector()->length() == 16 && + Matcher::vector_element_basic_type(n) == T_BYTE); + + format %{ "VZERO $dst, $zero \t// replicate16B" %} + size(6); + ins_encode %{ + __ z_vzero($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl2L_reg_Ex(vecX dst, iRegL src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 2 && + Matcher::vector_element_basic_type(n) == T_LONG); + + size(12); + ins_encode %{ + __ z_vlvgg($dst$$VectorRegister, $src$$Register, 0); + __ z_vrepg($dst$$VectorRegister, $dst$$VectorRegister, 0); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl2L_immIminus1(vecX dst, immI_minus1 src) %{ + match(Set dst (Replicate src)); + predicate(n->as_Vector()->length() == 2 && + Matcher::vector_element_basic_type(n) == T_LONG); + + format %{ "VONE $dst, $src \t// replicate2L" %} + size(6); + ins_encode %{ + __ z_vone($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct repl2L_immI0(vecX dst, immI_0 zero) %{ + match(Set dst (Replicate zero)); + predicate(n->as_Vector()->length() == 2 && + Matcher::vector_element_basic_type(n) == T_LONG); + + format %{ "VZERO $dst, $zero \t// replicate16B" %} + size(6); + ins_encode %{ + __ z_vzero($dst$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + + // Load/Store vector // Store Aligned Packed Byte register to memory (8 Bytes). @@ -10664,6 +11173,21 @@ instruct storeA8B(memory mem, iRegL src) %{ ins_pipe(pipe_class_dummy); %} +// Store Packed Byte long register to memory +instruct storeV16(memoryRX mem, vecX src) %{ + predicate(n->as_StoreVector()->memory_size() == 16); + match(Set mem (StoreVector mem src)); + ins_cost(MEMORY_REF_COST); + + format %{ "VST $mem, $src \t// store 16-byte Vector" %} + size(6); + ins_encode %{ + __ z_vst($src$$VectorRegister, + Address(reg_to_register_object($mem$$base), $mem$$index$$Register, $mem$$disp)); + %} + ins_pipe(pipe_class_dummy); +%} + instruct loadV8(iRegL dst, memory mem) %{ match(Set dst (LoadVector mem)); predicate(n->as_LoadVector()->memory_size() == 8); @@ -10675,6 +11199,21 @@ instruct loadV8(iRegL dst, memory mem) %{ ins_pipe(pipe_class_dummy); %} +// Load Aligned Packed Byte +instruct loadV16(vecX dst, memoryRX mem) %{ + predicate(n->as_LoadVector()->memory_size() == 16); + match(Set dst (LoadVector mem)); + ins_cost(MEMORY_REF_COST); + + format %{ "VL $dst, $mem \t// load 16-byte Vector" %} + size(6); + ins_encode %{ + __ z_vl($dst$$VectorRegister, + Address(reg_to_register_object($mem$$base), $mem$$index$$Register, $mem$$disp)); + %} + ins_pipe(pipe_class_dummy); +%} + // Reinterpret: only one vector size used instruct reinterpret(iRegL dst) %{ match(Set dst (VectorReinterpret dst)); @@ -10684,6 +11223,303 @@ instruct reinterpret(iRegL dst) %{ ins_pipe(pipe_class_dummy); %} +instruct reinterpretX(vecX dst) %{ + match(Set dst (VectorReinterpret dst)); + ins_cost(0); + format %{ "reinterpret $dst" %} + ins_encode( /*empty*/ ); + ins_pipe(pipe_class_dummy); +%} + +//----------Vector Arithmetic Instructions-------------------------------------- + +// Vector Addition Instructions + +instruct vadd16B_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (AddVB src1 src2)); + predicate(n->as_Vector()->length() == 16); + format %{ "VAB $dst,$src1,$src2\t// add packed16B" %} + size(6); + ins_encode %{ + __ z_vab($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vadd8S_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (AddVS src1 src2)); + predicate(n->as_Vector()->length() == 8); + format %{ "VAH $dst,$src1,$src2\t// add packed8S" %} + size(6); + ins_encode %{ + __ z_vah($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vadd4I_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (AddVI src1 src2)); + predicate(n->as_Vector()->length() == 4); + format %{ "VAF $dst,$src1,$src2\t// add packed4I" %} + size(6); + ins_encode %{ + __ z_vaf($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vadd2L_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (AddVL src1 src2)); + predicate(n->as_Vector()->length() == 2); + format %{ "VAG $dst,$src1,$src2\t// add packed2L" %} + size(6); + ins_encode %{ + __ z_vag($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vmul16B_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (MulVB src1 src2)); + predicate(n->as_Vector()->length() == 16); + format %{ "VMLB $dst,$src1,$src2\t// mul packed16B" %} + size(6); + ins_encode %{ + __ z_vmlb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vmul8S_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (MulVS src1 src2)); + predicate(n->as_Vector()->length() == 8); + format %{ "VMLHW $dst,$src1,$src2\t// mul packed8S" %} + size(6); + ins_encode %{ + __ z_vmlhw($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vmul4I_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (MulVI src1 src2)); + predicate(n->as_Vector()->length() == 4); + format %{ "VMLF $dst,$src1,$src2\t// mul packed4I" %} + size(6); + ins_encode %{ + __ z_vmlf($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vsub16B_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (SubVB src1 src2)); + predicate(n->as_Vector()->length() == 16); + format %{ "VSB $dst,$src1,$src2\t// sub packed16B" %} + size(6); + ins_encode %{ + __ z_vsb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vsub8S_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (SubVS src1 src2)); + predicate(n->as_Vector()->length() == 8); + format %{ "VSH $dst,$src1,$src2\t// sub packed8S" %} + size(6); + ins_encode %{ + __ z_vsh($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vsub4I_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (SubVI src1 src2)); + predicate(n->as_Vector()->length() == 4); + format %{ "VSF $dst,$src1,$src2\t// sub packed4I" %} + size(6); + ins_encode %{ + __ z_vsf($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vsub2L_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (SubVL src1 src2)); + predicate(n->as_Vector()->length() == 2); + format %{ "VSG $dst,$src1,$src2\t// sub packed2L" %} + size(6); + ins_encode %{ + __ z_vsg($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vadd4F_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (AddVF src1 src2)); + predicate(n->as_Vector()->length() == 4); + format %{ "VFASB $dst,$src1,$src2\t// add packed4F" %} + size(6); + ins_encode %{ + __ z_vfasb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vadd2D_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (AddVD src1 src2)); + predicate(n->as_Vector()->length() == 2); + format %{ "VFADB $dst,$src1,$src2\t// add packed2D" %} + size(6); + ins_encode %{ + __ z_vfadb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vsub4F_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (SubVF src1 src2)); + predicate(n->as_Vector()->length() == 4); + format %{ "VFSSB $dst,$src1,$src2\t// sub packed4F" %} + size(6); + ins_encode %{ + __ z_vfssb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vsub2D_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (SubVD src1 src2)); + predicate(n->as_Vector()->length() == 2); + format %{ "VFSDB $dst,$src1,$src2\t// sub packed2D" %} + size(6); + ins_encode %{ + __ z_vfsdb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vmul4F_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (MulVF src1 src2)); + predicate(n->as_Vector()->length() == 4); + format %{ "VFMSB $dst,$src1,$src2\t// mul packed4F" %} + size(6); + ins_encode %{ + __ z_vfmsb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vmul2D_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (MulVD src1 src2)); + predicate(n->as_Vector()->length() == 2); + format %{ "VFMDB $dst,$src1,$src2\t// mul packed2D" %} + size(6); + ins_encode %{ + __ z_vfmdb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vdiv4F_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (DivVF src1 src2)); + predicate(n->as_Vector()->length() == 4); + format %{ "VFDSB $dst,$src1,$src2\t// div packed4F" %} + size(6); + ins_encode %{ + __ z_vfdsb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vdiv2D_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (DivVD src1 src2)); + predicate(n->as_Vector()->length() == 2); + format %{ "VFDDB $dst,$src1,$src2\t// div packed2D" %} + size(6); + ins_encode %{ + __ z_vfddb($dst$$VectorRegister, $src1$$VectorRegister, $src2$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +// Vector Square Root Instructions + +instruct vsqrt4F_reg(vecX dst, vecX src) %{ + match(Set dst (SqrtVF src)); + predicate(n->as_Vector()->length() == 4); + format %{ "VFSQSB $dst,$src\t// sqrt packed4F" %} + size(6); + ins_encode %{ + __ z_vfsqsb($dst$$VectorRegister, $src$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct vsqrt2D_reg(vecX dst, vecX src) %{ + match(Set dst (SqrtVD src)); + predicate(n->as_Vector()->length() == 2); + format %{ "VFSQDB $dst,$src\t// sqrt packed2D" %} + size(6); + ins_encode %{ + __ z_vfsqdb($dst$$VectorRegister, $src$$VectorRegister); + %} + ins_pipe(pipe_class_dummy); +%} + +// Vector Population Count Instructions + +instruct vpopcnt_reg(vecX dst, vecX src) %{ + match(Set dst (PopCountVI src)); + format %{ "VPOPCT $dst,$src\t// pop count packed" %} + size(6); + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + switch (bt) { + case T_BYTE: + __ z_vpopctb($dst$$VectorRegister, $src$$VectorRegister); + break; + case T_SHORT: + __ z_vpopcth($dst$$VectorRegister, $src$$VectorRegister); + break; + case T_INT: + __ z_vpopctf($dst$$VectorRegister, $src$$VectorRegister); + break; + case T_LONG: + __ z_vpopctg($dst$$VectorRegister, $src$$VectorRegister); + break; + default: + ShouldNotReachHere(); + } + %} + ins_pipe(pipe_class_dummy); +%} + +// Vector Round Instructions +instruct vround2D_reg(vecX dst, vecX src, immI8 rmode) %{ + match(Set dst (RoundDoubleModeV src rmode)); + predicate(n->as_Vector()->length() == 2); + format %{ "RoundDoubleModeV $src,$rmode" %} + size(6); + ins_encode %{ + switch ($rmode$$constant) { + case RoundDoubleModeNode::rmode_rint: + __ z_vflrd($dst$$VectorRegister, $src$$VectorRegister, 0); + break; + case RoundDoubleModeNode::rmode_floor: + __ z_vflrd($dst$$VectorRegister, $src$$VectorRegister, 7); + break; + case RoundDoubleModeNode::rmode_ceil: + __ z_vflrd($dst$$VectorRegister, $src$$VectorRegister, 6); + break; + default: + ShouldNotReachHere(); + } + %} + ins_pipe(pipe_class_dummy); +%} + //----------POPULATION COUNT RULES-------------------------------------------- // Byte reverse diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index c60f6ef3295..1238f887b87 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -81,6 +81,9 @@ #define RegisterSaver_ExcludedFloatReg(regname) \ { RegisterSaver::excluded_reg, regname->encoding(), regname->as_VMReg() } +#define RegisterSaver_LiveVReg(regname) \ + { RegisterSaver::v_reg, regname->encoding(), regname->as_VMReg() } + static const RegisterSaver::LiveRegType RegisterSaver_LiveRegs[] = { // Live registers which get spilled to the stack. Register positions // in this array correspond directly to the stack layout. @@ -258,6 +261,26 @@ static const RegisterSaver::LiveRegType RegisterSaver_LiveVolatileRegs[] = { // RegisterSaver_ExcludedIntReg(Z_R15) // stack pointer }; +static const RegisterSaver::LiveRegType RegisterSaver_LiveVRegs[] = { + // live vector registers (optional, only these are used by C2): + RegisterSaver_LiveVReg( Z_V16 ), + RegisterSaver_LiveVReg( Z_V17 ), + RegisterSaver_LiveVReg( Z_V18 ), + RegisterSaver_LiveVReg( Z_V19 ), + RegisterSaver_LiveVReg( Z_V20 ), + RegisterSaver_LiveVReg( Z_V21 ), + RegisterSaver_LiveVReg( Z_V22 ), + RegisterSaver_LiveVReg( Z_V23 ), + RegisterSaver_LiveVReg( Z_V24 ), + RegisterSaver_LiveVReg( Z_V25 ), + RegisterSaver_LiveVReg( Z_V26 ), + RegisterSaver_LiveVReg( Z_V27 ), + RegisterSaver_LiveVReg( Z_V28 ), + RegisterSaver_LiveVReg( Z_V29 ), + RegisterSaver_LiveVReg( Z_V30 ), + RegisterSaver_LiveVReg( Z_V31 ) +}; + int RegisterSaver::live_reg_save_size(RegisterSet reg_set) { int reg_space = -1; switch (reg_set) { @@ -271,23 +294,28 @@ int RegisterSaver::live_reg_save_size(RegisterSet reg_set) { return (reg_space / sizeof(RegisterSaver::LiveRegType)) * reg_size; } +int RegisterSaver::calculate_vregstosave_num() { + return (sizeof(RegisterSaver_LiveVRegs) / sizeof(RegisterSaver::LiveRegType)); +} -int RegisterSaver::live_reg_frame_size(RegisterSet reg_set) { - return live_reg_save_size(reg_set) + frame::z_abi_160_size; +int RegisterSaver::live_reg_frame_size(RegisterSet reg_set, bool save_vectors) { + const int vregstosave_num = save_vectors ? calculate_vregstosave_num() : 0; + return live_reg_save_size(reg_set) + vregstosave_num * v_reg_size + frame::z_abi_160_size; } // return_pc: Specify the register that should be stored as the return pc in the current frame. -OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, RegisterSet reg_set, Register return_pc) { +OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, RegisterSet reg_set, Register return_pc, bool save_vectors) { // Record volatile registers as callee-save values in an OopMap so // their save locations will be propagated to the caller frame's // RegisterMap during StackFrameStream construction (needed for // deoptimization; see compiledVFrame::create_stack_value). // Calculate frame size. - const int frame_size_in_bytes = live_reg_frame_size(reg_set); + const int frame_size_in_bytes = live_reg_frame_size(reg_set, save_vectors); const int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); - const int register_save_offset = frame_size_in_bytes - live_reg_save_size(reg_set); + const int vregstosave_num = save_vectors ? calculate_vregstosave_num() : 0; + const int register_save_offset = frame_size_in_bytes - (live_reg_save_size(reg_set) + vregstosave_num * v_reg_size); // OopMap frame size is in c2 stack slots (sizeof(jint)) not bytes or words. OopMap* map = new OopMap(frame_size_in_slots, 0); @@ -382,6 +410,23 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, RegisterSet reg assert(first != noreg, "Should spill at least one int reg."); __ z_stmg(first, last, first_offset, Z_SP); + for (int i = 0; i < vregstosave_num; i++, offset += v_reg_size) { + int reg_num = RegisterSaver_LiveVRegs[i].reg_num; + + __ z_vst(as_VectorRegister(reg_num), Address(Z_SP, offset)); + + map->set_callee_saved(VMRegImpl::stack2reg(offset>>2), + RegisterSaver_LiveVRegs[i].vmreg); + map->set_callee_saved(VMRegImpl::stack2reg((offset + half_reg_size ) >> 2), + RegisterSaver_LiveVRegs[i].vmreg->next()); + map->set_callee_saved(VMRegImpl::stack2reg((offset + (half_reg_size * 2)) >> 2), + RegisterSaver_LiveVRegs[i].vmreg->next(2)); + map->set_callee_saved(VMRegImpl::stack2reg((offset + (half_reg_size * 3)) >> 2), + RegisterSaver_LiveVRegs[i].vmreg->next(3)); + } + + assert(offset == frame_size_in_bytes, "consistency check"); + // And we're done. return map; } @@ -433,14 +478,18 @@ OopMap* RegisterSaver::generate_oop_map(MacroAssembler* masm, RegisterSet reg_se } offset += reg_size; } +#ifdef ASSERT + assert(offset == frame_size_in_bytes, "consistency check"); +#endif return map; } // Pop the current frame and restore all the registers that we saved. -void RegisterSaver::restore_live_registers(MacroAssembler* masm, RegisterSet reg_set) { +void RegisterSaver::restore_live_registers(MacroAssembler* masm, RegisterSet reg_set, bool save_vectors) { int offset; - const int register_save_offset = live_reg_frame_size(reg_set) - live_reg_save_size(reg_set); + const int vregstosave_num = save_vectors ? calculate_vregstosave_num() : 0; + const int register_save_offset = live_reg_frame_size(reg_set, save_vectors) - (live_reg_save_size(reg_set) + vregstosave_num * v_reg_size); Register first = noreg; Register last = noreg; @@ -517,6 +566,12 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, RegisterSet reg assert(first != noreg, "Should spill at least one int reg."); __ z_lmg(first, last, first_offset, Z_SP); + for (int i = 0; i < vregstosave_num; i++, offset += v_reg_size) { + int reg_num = RegisterSaver_LiveVRegs[i].reg_num; + + __ z_vl(as_VectorRegister(reg_num), Address(Z_SP, offset)); + } + // Pop the frame. __ pop_frame(); @@ -527,14 +582,12 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, RegisterSet reg // Pop the current frame and restore the registers that might be holding a result. void RegisterSaver::restore_result_registers(MacroAssembler* masm) { - int i; - int offset; const int regstosave_num = sizeof(RegisterSaver_LiveRegs) / sizeof(RegisterSaver::LiveRegType); const int register_save_offset = live_reg_frame_size(all_registers) - live_reg_save_size(all_registers); // Restore all result registers (ints and floats). - offset = register_save_offset; + int offset = register_save_offset; for (int i = 0; i < regstosave_num; i++, offset += reg_size) { int reg_num = RegisterSaver_LiveRegs[i].reg_num; int reg_type = RegisterSaver_LiveRegs[i].reg_type; @@ -557,6 +610,7 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm) { ShouldNotReachHere(); } } + assert(offset == live_reg_frame_size(all_registers), "consistency check"); } // --------------------------------------------------------------------------- @@ -980,8 +1034,8 @@ static void gen_special_dispatch(MacroAssembler *masm, // Is the size of a vector size (in bytes) bigger than a size saved by default? // 8 bytes registers are saved by default on z/Architecture. bool SharedRuntime::is_wide_vector(int size) { - // Note, MaxVectorSize == 8 on this platform. - assert(size <= 8, "%d bytes vectors are not supported", size); + // Note, MaxVectorSize == 8/16 on this platform. + assert(size <= (SuperwordUseVX ? 16 : 8), "%d bytes vectors are not supported", size); return size > 8; } @@ -2865,8 +2919,9 @@ SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address cal __ z_lg(Z_R14, Address(Z_thread, JavaThread::saved_exception_pc_offset())); } + bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); // Save registers, fpu state, and flags - map = RegisterSaver::save_live_registers(masm, RegisterSaver::all_registers); + map = RegisterSaver::save_live_registers(masm, RegisterSaver::all_registers, Z_R14, save_vectors); if (!cause_return) { // Keep a copy of the return pc to detect if it gets modified. @@ -2898,7 +2953,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address cal // Pending exception case, used (sporadically) by // api/java_lang/Thread.State/index#ThreadState et al. - RegisterSaver::restore_live_registers(masm, RegisterSaver::all_registers); + RegisterSaver::restore_live_registers(masm, RegisterSaver::all_registers, save_vectors); // Jump to forward_exception_entry, with the issuing PC in Z_R14 // so it looks like the original nmethod called forward_exception_entry. @@ -2911,7 +2966,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address cal if (!cause_return) { Label no_adjust; // If our stashed return pc was modified by the runtime we avoid touching it - const int offset_of_return_pc = _z_common_abi(return_pc) + RegisterSaver::live_reg_frame_size(RegisterSaver::all_registers); + const int offset_of_return_pc = _z_common_abi(return_pc) + RegisterSaver::live_reg_frame_size(RegisterSaver::all_registers, save_vectors); __ z_cg(Z_R6, offset_of_return_pc, Z_SP); __ z_brne(no_adjust); @@ -2924,7 +2979,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address cal } // Normal exit, restore registers and exit. - RegisterSaver::restore_live_registers(masm, RegisterSaver::all_registers); + RegisterSaver::restore_live_registers(masm, RegisterSaver::all_registers, save_vectors); __ z_br(Z_R14); @@ -2932,7 +2987,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address cal masm->flush(); // Fill-out other meta info - return SafepointBlob::create(&buffer, oop_maps, RegisterSaver::live_reg_frame_size(RegisterSaver::all_registers)/wordSize); + return SafepointBlob::create(&buffer, oop_maps, RegisterSaver::live_reg_frame_size(RegisterSaver::all_registers, save_vectors)/wordSize); } diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index 4b17ff4594c..8ab5affd309 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -97,7 +97,23 @@ void VM_Version::initialize() { intx cache_line_size = Dcache_lineSize(0); #ifdef COMPILER2 - MaxVectorSize = 8; + int model_ix = get_model_index(); + + if ( model_ix >= 7 ) { + if (FLAG_IS_DEFAULT(SuperwordUseVX)) { + FLAG_SET_ERGO(SuperwordUseVX, true); + } + if (model_ix > 7 && FLAG_IS_DEFAULT(UseSFPV) && SuperwordUseVX) { + FLAG_SET_ERGO(UseSFPV, true); + } else if (model_ix == 7 && UseSFPV) { + warning("UseSFPV specified, but needs at least Z14."); + FLAG_SET_DEFAULT(UseSFPV, false); + } + } else if (SuperwordUseVX) { + warning("SuperwordUseVX specified, but needs at least Z13."); + FLAG_SET_DEFAULT(SuperwordUseVX, false); + } + MaxVectorSize = SuperwordUseVX ? 16 : 8; #endif if (has_PrefetchRaw()) { diff --git a/src/hotspot/cpu/s390/vmreg_s390.cpp b/src/hotspot/cpu/s390/vmreg_s390.cpp index 239b68513b9..5bec8313a48 100644 --- a/src/hotspot/cpu/s390/vmreg_s390.cpp +++ b/src/hotspot/cpu/s390/vmreg_s390.cpp @@ -43,6 +43,16 @@ void VMRegImpl::set_regName() { regName[i++] = freg->name(); freg = freg->successor(); } + + VectorRegister vreg = ::as_VectorRegister(0); + for (; i < ConcreteRegisterImpl::max_vr;) { + regName[i++] = vreg->name(); + regName[i++] = vreg->name(); + regName[i++] = vreg->name(); + regName[i++] = vreg->name(); + vreg = vreg->successor(); + } + for (; i < ConcreteRegisterImpl::number_of_registers; i ++) { regName[i] = "NON-GPR-XMM"; } diff --git a/src/hotspot/cpu/s390/vmreg_s390.hpp b/src/hotspot/cpu/s390/vmreg_s390.hpp index 3dd1bd9a16c..eb601f693ab 100644 --- a/src/hotspot/cpu/s390/vmreg_s390.hpp +++ b/src/hotspot/cpu/s390/vmreg_s390.hpp @@ -35,14 +35,26 @@ inline bool is_FloatRegister() { value() < ConcreteRegisterImpl::max_fpr; } +inline bool is_VectorRegister() { + return value() >= ConcreteRegisterImpl::max_fpr && + value() < ConcreteRegisterImpl::max_vr; +} + inline Register as_Register() { assert(is_Register() && is_even(value()), "even-aligned GPR name"); - return ::as_Register(value() >> 1); + return ::as_Register(value() / Register::max_slots_per_register); } inline FloatRegister as_FloatRegister() { assert(is_FloatRegister() && is_even(value()), "must be"); - return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) >> 1); + return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) / + FloatRegister::max_slots_per_register); +} + +inline VectorRegister as_VectorRegister() { + assert(is_VectorRegister(), "must be"); + return ::as_VectorRegister((value() - ConcreteRegisterImpl::max_fpr) / + VectorRegister::max_slots_per_register); } inline bool is_concrete() { diff --git a/src/hotspot/cpu/s390/vmreg_s390.inline.hpp b/src/hotspot/cpu/s390/vmreg_s390.inline.hpp index 593a0d48045..b03a66b3086 100644 --- a/src/hotspot/cpu/s390/vmreg_s390.inline.hpp +++ b/src/hotspot/cpu/s390/vmreg_s390.inline.hpp @@ -27,15 +27,21 @@ #define CPU_S390_VMREG_S390_INLINE_HPP inline VMReg Register::as_VMReg() const { - return VMRegImpl::as_VMReg(encoding() << 1); + return VMRegImpl::as_VMReg(encoding() * Register::max_slots_per_register); } inline VMReg FloatRegister::as_VMReg() const { - return VMRegImpl::as_VMReg((encoding() << 1) + ConcreteRegisterImpl::max_gpr); + return VMRegImpl::as_VMReg((encoding() * FloatRegister::max_slots_per_register) + + ConcreteRegisterImpl::max_gpr); +} + +inline VMReg VectorRegister::as_VMReg() const { + return VMRegImpl::as_VMReg((encoding() * VectorRegister::max_slots_per_register) + + ConcreteRegisterImpl::max_fpr); } inline VMReg ConditionRegister::as_VMReg() const { - return VMRegImpl::as_VMReg((encoding() << 1) + ConcreteRegisterImpl::max_fpr); + return VMRegImpl::as_VMReg(encoding() + ConcreteRegisterImpl::max_vr); } #endif // CPU_S390_VMREG_S390_INLINE_HPP diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index 804e8f1a4e6..cc6ed278b49 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -2358,6 +2358,9 @@ class DefineEmitState { if (strcmp(rep_var,"$VectorRegister") == 0) return "as_VectorRegister"; if (strcmp(rep_var,"$VectorSRegister") == 0) return "as_VectorSRegister"; #endif +#if defined(S390) + if (strcmp(rep_var,"$VectorRegister") == 0) return "as_VectorRegister"; +#endif #if defined(AARCH64) if (strcmp(rep_var,"$PRegister") == 0) return "as_PRegister"; #endif diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index 6fcbabdab90..4ac91175f78 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -134,6 +134,14 @@ class MachOper : public ResourceObj { return ::as_VectorSRegister(reg(ra_, node, idx)); } #endif +#if defined(S390) + VectorRegister as_VectorRegister(PhaseRegAlloc *ra_, const Node *node) const { + return ::as_VectorRegister(reg(ra_, node)); + } + VectorRegister as_VectorRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const { + return ::as_VectorRegister(reg(ra_, node, idx)); + } +#endif #if defined(AARCH64) PRegister as_PRegister(PhaseRegAlloc* ra_, const Node* node) const { return ::as_PRegister(reg(ra_, node)); diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 70cd46c900d..407a4a20a9b 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -77,7 +77,7 @@ const Type::TypeInfo Type::_type_info[Type::lastype] = { { Bad, T_ILLEGAL, "vectora:", false, Op_VecA, relocInfo::none }, // VectorA. { Bad, T_ILLEGAL, "vectors:", false, 0, relocInfo::none }, // VectorS { Bad, T_ILLEGAL, "vectord:", false, Op_RegL, relocInfo::none }, // VectorD - { Bad, T_ILLEGAL, "vectorx:", false, 0, relocInfo::none }, // VectorX + { Bad, T_ILLEGAL, "vectorx:", false, Op_VecX, relocInfo::none }, // VectorX { Bad, T_ILLEGAL, "vectory:", false, 0, relocInfo::none }, // VectorY { Bad, T_ILLEGAL, "vectorz:", false, 0, relocInfo::none }, // VectorZ #else // all other diff --git a/src/java.base/share/classes/java/util/Currency.java b/src/java.base/share/classes/java/util/Currency.java index b639855b3bf..789eefad5d5 100644 --- a/src/java.base/share/classes/java/util/Currency.java +++ b/src/java.base/share/classes/java/util/Currency.java @@ -486,10 +486,7 @@ public static Set getAvailableCurrencies() { } } } - - @SuppressWarnings("unchecked") - Set result = (Set) available.clone(); - return result; + return new HashSet<>(available); } /** diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java index 9dfd422f6dd..96ef2541c7b 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,12 +24,21 @@ */ package javax.swing.plaf.nimbus; -import java.awt.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; import java.awt.image.BufferedImage; -import java.util.*; -import javax.swing.*; +import javax.swing.JDesktopPane; +import javax.swing.JSlider; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.Painter; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.plaf.UIResource; import javax.swing.plaf.synth.SynthContext; import javax.swing.plaf.synth.SynthPainter; import javax.swing.plaf.synth.SynthConstants; @@ -531,7 +540,11 @@ public void paintDesktopIconBorder(SynthContext context, public void paintDesktopPaneBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { - paintBackground(context, g, x, y, w, h, null); + if (context.getComponent() instanceof JDesktopPane pane) { + if (pane.getBackground() instanceof UIResource) { + paintBackground(context, g, x, y, w, h, null); + } + } } /** diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 680806e6e31..1577bb6f7f1 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -30,3 +30,4 @@ java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all java/lang/reflect/callerCache/ReflectionCallerCacheTest.java 8332028 generic-all com/sun/jdi/InterruptHangTest.java 8043571 generic-all +jdk/jfr/jvm/TestVirtualThreadExclusion.java 8344199 generic-all diff --git a/test/jdk/javax/swing/JInternalFrame/bug6726866.java b/test/jdk/javax/swing/JInternalFrame/bug6726866.java index 88b890d7b2c..a8f267fedc2 100644 --- a/test/jdk/javax/swing/JInternalFrame/bug6726866.java +++ b/test/jdk/javax/swing/JInternalFrame/bug6726866.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6726866 8186617 + * @bug 6726866 8186617 8343123 * @summary Repainting artifacts when resizing or dragging JInternalFrames in non-opaque toplevel * @library /java/awt/regtesthelpers @@ -34,7 +34,6 @@ import java.awt.Color; import java.awt.Window; -import javax.swing.JApplet; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JInternalFrame; diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java new file mode 100644 index 00000000000..2d23f49cdd7 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.time.LocalDate; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import static java.util.stream.Collectors.toMap; +import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; +import static jdk.internal.util.OperatingSystem.LINUX; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; +import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Test; +import static jdk.jpackage.test.Functional.ThrowingSupplier.toSupplier; + +/* + * @test + * @summary Test jpackage test library's annotation processor + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.AnnotationsTest + */ +public class AnnotationsTest { + + public static void main(String... args) { + runTests(BasicTest.class, ParameterizedInstanceTest.class); + for (var os : OperatingSystem.values()) { + try { + TestBuilderConfig.setOperatingSystem(os); + TKit.log("Current operating system: " + os); + runTests(IfOSTest.class); + } finally { + TestBuilderConfig.setDefaults(); + } + } + } + + public static class BasicTest extends TestExecutionRecorder { + @Test + public void testNoArg() { + recordTestCase(); + } + + @Test + @Parameter("TRUE") + public int testNoArg(boolean v) { + recordTestCase(v); + return 0; + } + + @Test + @Parameter({}) + @Parameter("a") + @Parameter({"b", "c"}) + public void testVarArg(Path ... paths) { + recordTestCase((Object[]) paths); + } + + @Test + @Parameter({"12", "foo"}) + @Parameter({"-89", "bar", "more"}) + @Parameter({"-89", "bar", "more", "moore"}) + public void testVarArg2(int a, String b, String ... other) { + recordTestCase(a, b, other); + } + + @Test + @ParameterSupplier("dateSupplier") + @ParameterSupplier("jdk.jpackage.test.AnnotationsTest.dateSupplier") + public void testDates(LocalDate v) { + recordTestCase(v); + } + + public static Set getExpectedTestDescs() { + return Set.of( + "().testNoArg()", + "().testNoArg(true)", + "().testVarArg()", + "().testVarArg(a)", + "().testVarArg(b, c)", + "().testVarArg2(-89, bar, [more, moore](length=2))", + "().testVarArg2(-89, bar, [more](length=1))", + "().testVarArg2(12, foo, [](length=0))", + "().testDates(2018-05-05)", + "().testDates(2018-07-11)", + "().testDates(2034-05-05)", + "().testDates(2056-07-11)" + ); + } + + public static Collection dateSupplier() { + return List.of(new Object[][] { + { LocalDate.parse("2018-05-05") }, + { LocalDate.parse("2018-07-11") }, + }); + } + } + + public static class ParameterizedInstanceTest extends TestExecutionRecorder { + public ParameterizedInstanceTest(String... args) { + super((Object[]) args); + } + + public ParameterizedInstanceTest(int o) { + super(o); + } + + public ParameterizedInstanceTest(int a, Boolean[] b, String c, String ... other) { + super(a, b, c, other); + } + + @Test + public void testNoArgs() { + recordTestCase(); + } + + @Test + @ParameterSupplier("jdk.jpackage.test.AnnotationsTest.dateSupplier") + public void testDates(LocalDate v) { + recordTestCase(v); + } + + @Test + @Parameter("a") + public static void staticTest(String arg) { + staticRecorder.recordTestCase(arg); + } + + @Parameters + public static Collection input() { + return List.of(new Object[][] { + {}, + {55, new Boolean[]{false, true, false}, "foo", "bar"}, + {78}, + }); + } + + @Parameters + public static Collection input2() { + return List.of(new Object[][] { + {51, new boolean[]{true, true, true}, "foo"}, + {33}, + {55, null, null }, + {55, null, null, "1" }, + }); + } + + public static Set getExpectedTestDescs() { + return Set.of( + "().testNoArgs()", + "(33).testNoArgs()", + "(78).testNoArgs()", + "(55, [false, true, false](length=3), foo, [bar](length=1)).testNoArgs()", + "(51, [true, true, true](length=3), foo, [](length=0)).testNoArgs()", + "().testDates(2034-05-05)", + "().testDates(2056-07-11)", + "(33).testDates(2034-05-05)", + "(33).testDates(2056-07-11)", + "(51, [true, true, true](length=3), foo, [](length=0)).testDates(2034-05-05)", + "(51, [true, true, true](length=3), foo, [](length=0)).testDates(2056-07-11)", + "(55, [false, true, false](length=3), foo, [bar](length=1)).testDates(2034-05-05)", + "(55, [false, true, false](length=3), foo, [bar](length=1)).testDates(2056-07-11)", + "(78).testDates(2034-05-05)", + "(78).testDates(2056-07-11)", + "(55, null, null, [1](length=1)).testDates(2034-05-05)", + "(55, null, null, [1](length=1)).testDates(2056-07-11)", + "(55, null, null, [1](length=1)).testNoArgs()", + "(55, null, null, [](length=0)).testDates(2034-05-05)", + "(55, null, null, [](length=0)).testDates(2056-07-11)", + "(55, null, null, [](length=0)).testNoArgs()", + "().staticTest(a)" + ); + } + + private final static TestExecutionRecorder staticRecorder = new TestExecutionRecorder(ParameterizedInstanceTest.class); + } + + public static class IfOSTest extends TestExecutionRecorder { + public IfOSTest(int a, String b) { + super(a, b); + } + + @Test(ifOS = OperatingSystem.LINUX) + public void testNoArgs() { + recordTestCase(); + } + + @Test(ifNotOS = OperatingSystem.LINUX) + public void testNoArgs2() { + recordTestCase(); + } + + @Test + @Parameter(value = "foo", ifOS = OperatingSystem.LINUX) + @Parameter(value = {"foo", "bar"}, ifOS = { OperatingSystem.LINUX, OperatingSystem.MACOS }) + @Parameter(value = {}, ifNotOS = { OperatingSystem.WINDOWS }) + public void testVarArgs(String ... args) { + recordTestCase((Object[]) args); + } + + @Test + @ParameterSupplier(value = "jdk.jpackage.test.AnnotationsTest.dateSupplier", ifOS = OperatingSystem.WINDOWS) + public void testDates(LocalDate v) { + recordTestCase(v); + } + + @Parameters(ifOS = OperatingSystem.LINUX) + public static Collection input() { + return Set.of(new Object[][] { + {7, null}, + }); + } + + @Parameters(ifNotOS = {OperatingSystem.LINUX, OperatingSystem.MACOS}) + public static Collection input2() { + return Set.of(new Object[][] { + {10, "hello"}, + }); + } + + @Parameters(ifNotOS = OperatingSystem.LINUX) + public static Collection input3() { + return Set.of(new Object[][] { + {15, "bye"}, + }); + } + + public static Set getExpectedTestDescs() { + switch (TestBuilderConfig.getDefault().getOperatingSystem()) { + case LINUX -> { + return Set.of( + "(7, null).testNoArgs()", + "(7, null).testVarArgs()", + "(7, null).testVarArgs(foo)", + "(7, null).testVarArgs(foo, bar)" + ); + } + + case MACOS -> { + return Set.of( + "(15, bye).testNoArgs2()", + "(15, bye).testVarArgs()", + "(15, bye).testVarArgs(foo, bar)" + ); + } + + case WINDOWS -> { + return Set.of( + "(15, bye).testDates(2034-05-05)", + "(15, bye).testDates(2056-07-11)", + "(15, bye).testNoArgs2()", + "(10, hello).testDates(2034-05-05)", + "(10, hello).testDates(2056-07-11)", + "(10, hello).testNoArgs2()" + ); + } + + case AIX -> { + return Set.of( + ); + } + } + + throw new UnsupportedOperationException(); + } + } + + public static Collection dateSupplier() { + return List.of(new Object[][] { + { LocalDate.parse("2034-05-05") }, + { LocalDate.parse("2056-07-11") }, + }); + } + + private static void runTests(Class... tests) { + ACTUAL_TEST_DESCS.get().clear(); + + var expectedTestDescs = Stream.of(tests) + .map(AnnotationsTest::getExpectedTestDescs) + .flatMap(x -> x) + // Collect in the map to check for collisions for free + .collect(toMap(x -> x, x -> "")) + .keySet(); + + var args = Stream.of(tests).map(test -> { + return String.format("--jpt-run=%s", test.getName()); + }).toArray(String[]::new); + + try { + Main.main(args); + assertRecordedTestDescs(expectedTestDescs); + } catch (Throwable t) { + t.printStackTrace(System.err); + System.exit(1); + } + } + + private static Stream getExpectedTestDescs(Class type) { + return toSupplier(() -> { + var method = type.getMethod("getExpectedTestDescs"); + var testDescPefix = type.getName(); + return ((Set)method.invoke(null)).stream().map(desc -> { + return testDescPefix + desc; + }); + }).get(); + } + + private static void assertRecordedTestDescs(Set expectedTestDescs) { + var comm = Comm.compare(expectedTestDescs, ACTUAL_TEST_DESCS.get()); + if (!comm.unique1().isEmpty()) { + System.err.println("Missing test case signatures:"); + comm.unique1().stream().sorted().sequential().forEachOrdered(System.err::println); + System.err.println("<>"); + } + + if (!comm.unique2().isEmpty()) { + System.err.println("Unexpected test case signatures:"); + comm.unique2().stream().sorted().sequential().forEachOrdered(System.err::println); + System.err.println("<>"); + } + + if (!comm.unique2().isEmpty() || !comm.unique1().isEmpty()) { + // Don't use TKit asserts as this call is outside the test execution + throw new AssertionError("Test case signatures mismatched"); + } + } + + private static class TestExecutionRecorder { + protected TestExecutionRecorder(Object ... args) { + this.testClass = getClass(); + this.testDescBuilder = TestInstance.TestDesc.createBuilder().ctorArgs(args); + } + + TestExecutionRecorder(Class testClass) { + this.testClass = testClass; + this.testDescBuilder = TestInstance.TestDesc.createBuilder().ctorArgs(); + } + + protected void recordTestCase(Object ... args) { + testDescBuilder.methodArgs(args).method(getCurrentTestCase()); + var testCaseDescs = ACTUAL_TEST_DESCS.get(); + var testCaseDesc = testDescBuilder.get().testFullName(); + TKit.assertTrue(!testCaseDescs.contains(testCaseDesc), String.format( + "Check this test case is executed for the first time", + testCaseDesc)); + TKit.assertTrue(!executed, "Check this test case instance is not reused"); + executed = true; + testCaseDescs.add(testCaseDesc); + } + + private Method getCurrentTestCase() { + return StackWalker.getInstance(RETAIN_CLASS_REFERENCE).walk(frames -> { + return frames.map(frame -> { + var methodType = frame.getMethodType(); + var methodName = frame.getMethodName(); + var methodReturn = methodType.returnType(); + var methodParameters = methodType.parameterArray(); + return Stream.of(testClass.getDeclaredMethods()).filter(method -> { + return method.getName().equals(methodName) + && method.getReturnType().equals(methodReturn) + && Arrays.equals(method.getParameterTypes(), methodParameters) + && method.isAnnotationPresent(Test.class); + }).findFirst(); + }).dropWhile(Optional::isEmpty).map(Optional::get).findFirst(); + }).get(); + } + + private boolean executed; + private final TestInstance.TestDesc.Builder testDescBuilder; + private final Class testClass; + } + + private static final ThreadLocal> ACTUAL_TEST_DESCS = new ThreadLocal<>() { + @Override + protected Set initialValue() { + return new HashSet<>(); + } + }; +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Annotations.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Annotations.java index d29133ee3e1..ad1e77b4171 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Annotations.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Annotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import jdk.internal.util.OperatingSystem; public class Annotations { @@ -43,6 +44,14 @@ public class Annotations { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Test { + + OperatingSystem[] ifOS() default { + OperatingSystem.LINUX, + OperatingSystem.WINDOWS, + OperatingSystem.MACOS + }; + + OperatingSystem[] ifNotOS() default {}; } @Retention(RetentionPolicy.RUNTIME) @@ -51,6 +60,14 @@ public class Annotations { public @interface Parameter { String[] value(); + + OperatingSystem[] ifOS() default { + OperatingSystem.LINUX, + OperatingSystem.WINDOWS, + OperatingSystem.MACOS + }; + + OperatingSystem[] ifNotOS() default {}; } @Retention(RetentionPolicy.RUNTIME) @@ -60,8 +77,39 @@ public class Annotations { Parameter[] value(); } + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + @Repeatable(ParameterSupplierGroup.class) + public @interface ParameterSupplier { + + String value(); + + OperatingSystem[] ifOS() default { + OperatingSystem.LINUX, + OperatingSystem.WINDOWS, + OperatingSystem.MACOS + }; + + OperatingSystem[] ifNotOS() default {}; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface ParameterSupplierGroup { + + ParameterSupplier[] value(); + } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Parameters { + + OperatingSystem[] ifOS() default { + OperatingSystem.LINUX, + OperatingSystem.WINDOWS, + OperatingSystem.MACOS + }; + + OperatingSystem[] ifNotOS() default {}; } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Comm.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Comm.java new file mode 100644 index 00000000000..23798f326fe --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Comm.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.util.HashSet; +import java.util.Set; + +record Comm(Set common, Set unique1, Set unique2) { + + static Comm compare(Set a, Set b) { + Set common = new HashSet<>(a); + common.retainAll(b); + Set unique1 = new HashSet<>(a); + unique1.removeAll(common); + Set unique2 = new HashSet<>(b); + unique2.removeAll(common); + return new Comm(common, unique1, unique2); + } +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index bf5ced09bc7..a96bab49355 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.internal.IOUtils; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -399,6 +400,15 @@ static void addBundleDesktopIntegrationVerifier(PackageTest test, private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile) throws IOException { TKit.trace(String.format("Check [%s] file BEGIN", desktopFile)); + + var launcherName = Stream.of(List.of(cmd.name()), cmd.addLauncherNames()).flatMap(List::stream).filter(name -> { + return getDesktopFile(cmd, name).equals(desktopFile); + }).findAny(); + if (!cmd.hasArgument("--app-image")) { + TKit.assertTrue(launcherName.isPresent(), + "Check the desktop file corresponds to one of app launchers"); + } + List lines = Files.readAllLines(desktopFile); TKit.assertEquals("[Desktop Entry]", lines.get(0), "Check file header"); @@ -428,7 +438,7 @@ private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile) "Check value of [%s] key", key)); } - // Verify value of `Exec` property in .desktop files are escaped if required + // Verify the value of `Exec` key is escaped if required String launcherPath = data.get("Exec"); if (Pattern.compile("\\s").matcher(launcherPath).find()) { TKit.assertTrue(launcherPath.startsWith("\"") @@ -437,10 +447,25 @@ private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile) launcherPath = launcherPath.substring(1, launcherPath.length() - 1); } - Stream.of(launcherPath, data.get("Icon")) - .map(Path::of) - .map(cmd::pathToUnpackedPackageFile) - .forEach(TKit::assertFileExists); + if (launcherName.isPresent()) { + TKit.assertEquals(launcherPath, cmd.pathToPackageFile( + cmd.appLauncherPath(launcherName.get())).toString(), + String.format( + "Check the value of [Exec] key references [%s] app launcher", + launcherName.get())); + } + + for (var e : List.>, Function>>of( + Map.entry(Map.entry("Exec", Optional.of(launcherPath)), ApplicationLayout::launchersDirectory), + Map.entry(Map.entry("Icon", Optional.empty()), ApplicationLayout::destktopIntegrationDirectory))) { + var path = e.getKey().getValue().or(() -> Optional.of(data.get( + e.getKey().getKey()))).map(Path::of).get(); + TKit.assertFileExists(cmd.pathToUnpackedPackageFile(path)); + Path expectedDir = cmd.pathToPackageFile(e.getValue().apply(cmd.appLayout())); + TKit.assertTrue(path.getParent().equals(expectedDir), String.format( + "Check the value of [%s] key references a file in [%s] folder", + e.getKey().getKey(), expectedDir)); + } TKit.trace(String.format("Check [%s] file END", desktopFile)); } @@ -725,10 +750,10 @@ private static Method initGetServiceUnitFileName() { private static Map archs; - private final static Pattern XDG_CMD_ICON_SIZE_PATTERN = Pattern.compile("\\s--size\\s+(\\d+)\\b"); + private static final Pattern XDG_CMD_ICON_SIZE_PATTERN = Pattern.compile("\\s--size\\s+(\\d+)\\b"); // Values grabbed from https://linux.die.net/man/1/xdg-icon-resource - private final static Set XDG_CMD_VALID_ICON_SIZES = Set.of(16, 22, 32, 48, 64, 128); + private static final Set XDG_CMD_VALID_ICON_SIZES = Set.of(16, 22, 32, 48, 64, 128); - private final static Method getServiceUnitFileName = initGetServiceUnitFileName(); + private static final Method getServiceUnitFileName = initGetServiceUnitFileName(); } 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 37aca48ac17..5919d8361c4 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, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,17 @@ package jdk.jpackage.test; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Comparator; +import java.util.Deque; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; -import java.util.stream.Collectors; +import static java.util.stream.Collectors.toCollection; +import java.util.stream.Stream; import static jdk.jpackage.test.TestBuilder.CMDLINE_ARG_PREFIX; @@ -36,7 +42,9 @@ public static void main(String args[]) throws Throwable { boolean listTests = false; List tests = new ArrayList<>(); try (TestBuilder testBuilder = new TestBuilder(tests::add)) { - for (var arg : args) { + Deque argsAsList = new ArrayDeque<>(List.of(args)); + while (!argsAsList.isEmpty()) { + var arg = argsAsList.pop(); TestBuilder.trace(String.format("Parsing [%s]...", arg)); if ((CMDLINE_ARG_PREFIX + "list").equals(arg)) { @@ -44,6 +52,29 @@ public static void main(String args[]) throws Throwable { continue; } + if (arg.startsWith("@")) { + // Command file + // @=args will read arguments from the "args" file, one argument per line + // @args will read arguments from the "args" file, splitting lines into arguments at whitespaces + arg = arg.substring(1); + var oneArgPerLine = arg.startsWith("="); + if (oneArgPerLine) { + arg = arg.substring(1); + } + + var newArgsStream = Files.readAllLines(Path.of(arg)).stream(); + if (!oneArgPerLine) { + newArgsStream.map(line -> { + return Stream.of(line.split("\\s+")); + }).flatMap(x -> x); + } + + var newArgs = newArgsStream.collect(toCollection(ArrayDeque::new)); + newArgs.addAll(argsAsList); + argsAsList = newArgs; + continue; + } + boolean success = false; try { testBuilder.processCmdLineArg(arg); @@ -62,12 +93,11 @@ public static void main(String args[]) throws Throwable { // Order tests by their full names to have stable test sequence. List orderedTests = tests.stream() - .sorted((a, b) -> a.fullName().compareTo(b.fullName())) - .collect(Collectors.toList()); + .sorted(Comparator.comparing(TestInstance::fullName)).toList(); if (listTests) { // Just list the tests - orderedTests.stream().forEach(test -> System.out.println(String.format( + orderedTests.forEach(test -> System.out.println(String.format( "%s; workDir=[%s]", test.fullName(), test.workDir()))); return; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java index 2aaba054a9b..d5b8bd702c8 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,34 +22,33 @@ */ package jdk.jpackage.test; +import java.lang.reflect.Array; import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; -import java.util.List; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.function.Supplier; -import java.util.stream.Collectors; +import java.util.function.Predicate; +import java.util.stream.IntStream; import java.util.stream.Stream; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.TestInstance.TestDesc; class MethodCall implements ThrowingConsumer { - MethodCall(Object[] instanceCtorArgs, Method method) { - this.ctorArgs = Optional.ofNullable(instanceCtorArgs).orElse( - DEFAULT_CTOR_ARGS); - this.method = method; - this.methodArgs = new Object[0]; - } + MethodCall(Object[] instanceCtorArgs, Method method, Object ... args) { + Objects.requireNonNull(instanceCtorArgs); + Objects.requireNonNull(method); - MethodCall(Object[] instanceCtorArgs, Method method, Object arg) { - this.ctorArgs = Optional.ofNullable(instanceCtorArgs).orElse( - DEFAULT_CTOR_ARGS); + this.ctorArgs = instanceCtorArgs; this.method = method; - this.methodArgs = new Object[]{arg}; + this.methodArgs = args; } TestDesc createDescription() { @@ -76,78 +75,195 @@ Object newInstance() throws NoSuchMethodException, InstantiationException, return null; } - Constructor ctor = findRequiredConstructor(method.getDeclaringClass(), - ctorArgs); - if (ctor.isVarArgs()) { - // Assume constructor doesn't have fixed, only variable parameters. - return ctor.newInstance(new Object[]{ctorArgs}); - } + var ctor = findMatchingConstructor(method.getDeclaringClass(), ctorArgs); - return ctor.newInstance(ctorArgs); + return ctor.newInstance(mapArgs(ctor, ctorArgs)); + } + + static Object[] mapArgs(Executable executable, final Object ... args) { + return mapPrimitiveTypeArgs(executable, mapVarArgs(executable, args)); } void checkRequiredConstructor() throws NoSuchMethodException { if ((method.getModifiers() & Modifier.STATIC) == 0) { - findRequiredConstructor(method.getDeclaringClass(), ctorArgs); + findMatchingConstructor(method.getDeclaringClass(), ctorArgs); } } - private static Constructor findVarArgConstructor(Class type) { - return Stream.of(type.getConstructors()).filter( - Constructor::isVarArgs).findFirst().orElse(null); - } - - private Constructor findRequiredConstructor(Class type, Object... ctorArgs) + private static Constructor findMatchingConstructor(Class type, Object... ctorArgs) throws NoSuchMethodException { - Supplier notFoundException = () -> { - return new NoSuchMethodException(String.format( + var ctors = filterMatchingExecutablesForParameterValues(Stream.of( + type.getConstructors()), ctorArgs).toList(); + + if (ctors.size() != 1) { + // No public constructors that can handle the given arguments. + throw new NoSuchMethodException(String.format( "No public contructor in %s for %s arguments", type, Arrays.deepToString(ctorArgs))); - }; - - if (Stream.of(ctorArgs).allMatch(Objects::nonNull)) { - // No `null` in constructor args, take easy path - try { - return type.getConstructor(Stream.of(ctorArgs).map( - Object::getClass).collect(Collectors.toList()).toArray( - Class[]::new)); - } catch (NoSuchMethodException ex) { - // Failed to find ctor that can take the given arguments. - Constructor varArgCtor = findVarArgConstructor(type); - if (varArgCtor != null) { - // There is one with variable number of arguments. Use it. - return varArgCtor; - } - throw notFoundException.get(); + } + + return ctors.get(0); + } + + @Override + public void accept(Object thiz) throws Throwable { + method.invoke(thiz, methodArgs); + } + + private static Object[] mapVarArgs(Executable executable, final Object ... args) { + if (executable.isVarArgs()) { + var paramTypes = executable.getParameterTypes(); + Class varArgParamType = paramTypes[paramTypes.length - 1]; + + Object[] newArgs; + if (paramTypes.length - args.length == 1) { + // Empty var args + + // "args" can be of type String[] if the "executable" is "foo(String ... str)" + newArgs = Arrays.copyOf(args, args.length + 1, Object[].class); + newArgs[newArgs.length - 1] = Array.newInstance(varArgParamType.componentType(), 0); + } else { + var varArgs = Arrays.copyOfRange(args, paramTypes.length - 1, + args.length, varArgParamType); + + // "args" can be of type String[] if the "executable" is "foo(String ... str)" + newArgs = Arrays.copyOfRange(args, 0, paramTypes.length, Object[].class); + newArgs[newArgs.length - 1] = varArgs; } + return newArgs; } - List ctors = Stream.of(type.getConstructors()) - .filter(ctor -> ctor.getParameterCount() == ctorArgs.length) - .collect(Collectors.toList()); + return args; + } - if (ctors.isEmpty()) { - // No public constructors that can handle the given arguments. - throw notFoundException.get(); + private static Object[] mapPrimitiveTypeArgs(Executable executable, final Object ... args) { + var paramTypes = executable.getParameterTypes(); + if (paramTypes.length != args.length) { + throw new IllegalArgumentException( + "The number of arguments must be equal to the number of parameters of the executable"); } - if (ctors.size() == 1) { - return ctors.iterator().next(); + if (IntStream.range(0, args.length).allMatch(idx -> { + return Optional.ofNullable(args[idx]).map(Object::getClass).map(paramTypes[idx]::isAssignableFrom).orElse(true); + })) { + return args; + } else { + final var newArgs = Arrays.copyOf(args, args.length, Object[].class); + for (var idx = 0; idx != args.length; ++idx) { + final var paramType = paramTypes[idx]; + final var argValue = args[idx]; + newArgs[idx] = Optional.ofNullable(argValue).map(Object::getClass).map(argType -> { + if(argType.isArray() && !paramType.isAssignableFrom(argType)) { + var length = Array.getLength(argValue); + var newArray = Array.newInstance(paramType.getComponentType(), length); + for (var arrayIdx = 0; arrayIdx != length; ++arrayIdx) { + Array.set(newArray, arrayIdx, Array.get(argValue, arrayIdx)); + } + return newArray; + } else { + return argValue; + } + }).orElse(argValue); + } + + return newArgs; } + } - // Revisit this tricky case when it will start bothering. - throw notFoundException.get(); + private static Stream filterMatchingExecutablesForParameterValues( + Stream executables, Object... args) { + return filterMatchingExecutablesForParameterTypes( + executables, + Stream.of(args) + .map(arg -> arg != null ? arg.getClass() : null) + .toArray(Class[]::new)); } - @Override - public void accept(Object thiz) throws Throwable { - method.invoke(thiz, methodArgs); + private static Stream filterMatchingExecutablesForParameterTypes( + Stream executables, Class... argTypes) { + return executables.filter(executable -> { + var parameterTypes = executable.getParameterTypes(); + + final int checkArgTypeCount; + if (parameterTypes.length <= argTypes.length) { + checkArgTypeCount = parameterTypes.length; + } else if (parameterTypes.length - argTypes.length == 1 && executable.isVarArgs()) { + // Empty optional arguments. + checkArgTypeCount = argTypes.length; + } else { + // Not enough mandatory arguments. + return false; + } + + var unmatched = IntStream.range(0, checkArgTypeCount).dropWhile(idx -> { + return new ParameterTypeMatcher(parameterTypes[idx]).test(argTypes[idx]); + }).toArray(); + + if (argTypes.length == parameterTypes.length && unmatched.length == 0) { + // Number of argument types equals to the number of parameters + // of the executable and all types match. + return true; + } + + if (executable.isVarArgs()) { + var varArgType = parameterTypes[parameterTypes.length - 1].componentType(); + return IntStream.of(unmatched).allMatch(idx -> { + return new ParameterTypeMatcher(varArgType).test(argTypes[idx]); + }); + } + + return false; + }); + } + + private static final class ParameterTypeMatcher implements Predicate> { + ParameterTypeMatcher(Class parameterType) { + Objects.requireNonNull(parameterType); + this.parameterType = NORM_TYPES.getOrDefault(parameterType, parameterType); + } + + @Override + public boolean test(Class paramaterValueType) { + if (paramaterValueType == null) { + return true; + } + + paramaterValueType = NORM_TYPES.getOrDefault(paramaterValueType, paramaterValueType); + return parameterType.isAssignableFrom(paramaterValueType); + } + + private final Class parameterType; } private final Object[] methodArgs; private final Method method; private final Object[] ctorArgs; - final static Object[] DEFAULT_CTOR_ARGS = new Object[0]; + private static final Map, Class> NORM_TYPES; + + static { + Map, Class> primitives = Map.of( + boolean.class, Boolean.class, + byte.class, Byte.class, + short.class, Short.class, + int.class, Integer.class, + long.class, Long.class, + float.class, Float.class, + double.class, Double.class); + + Map, Class> primitiveArrays = Map.of( + boolean[].class, Boolean[].class, + byte[].class, Byte[].class, + short[].class, Short[].class, + int[].class, Integer[].class, + long[].class, Long[].class, + float[].class, Float[].class, + double[].class, Double[].class); + + Map, Class> combined = new HashMap<>(primitives); + combined.putAll(primitiveArrays); + + NORM_TYPES = Collections.unmodifiableMap(combined); + } } 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 28c58a4db3d..957449697a5 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -781,18 +781,18 @@ public void match(Set expected) { currentTest.notifyAssert(); var comm = Comm.compare(content, expected); - if (!comm.unique1.isEmpty() && !comm.unique2.isEmpty()) { + if (!comm.unique1().isEmpty() && !comm.unique2().isEmpty()) { error(String.format( "assertDirectoryContentEquals(%s): Some expected %s. Unexpected %s. Missing %s", - baseDir, format(comm.common), format(comm.unique1), format(comm.unique2))); - } else if (!comm.unique1.isEmpty()) { + baseDir, format(comm.common()), format(comm.unique1()), format(comm.unique2()))); + } else if (!comm.unique1().isEmpty()) { error(String.format( "assertDirectoryContentEquals(%s): Expected %s. Unexpected %s", - baseDir, format(comm.common), format(comm.unique1))); - } else if (!comm.unique2.isEmpty()) { + baseDir, format(comm.common()), format(comm.unique1()))); + } else if (!comm.unique2().isEmpty()) { error(String.format( "assertDirectoryContentEquals(%s): Some expected %s. Missing %s", - baseDir, format(comm.common), format(comm.unique2))); + baseDir, format(comm.common()), format(comm.unique2()))); } else { traceAssert(String.format( "assertDirectoryContentEquals(%s): Expected %s", @@ -808,10 +808,10 @@ public void contains(Set expected) { currentTest.notifyAssert(); var comm = Comm.compare(content, expected); - if (!comm.unique2.isEmpty()) { + if (!comm.unique2().isEmpty()) { error(String.format( "assertDirectoryContentContains(%s): Some expected %s. Missing %s", - baseDir, format(comm.common), format(comm.unique2))); + baseDir, format(comm.common()), format(comm.unique2()))); } else { traceAssert(String.format( "assertDirectoryContentContains(%s): Expected %s", @@ -838,21 +838,6 @@ private DirectoryContentVerifier(Path baseDir, Set contents) { this.content = contents; } - private static record Comm(Set common, Set unique1, Set unique2) { - static Comm compare(Set a, Set b) { - Set common = new HashSet<>(a); - common.retainAll(b); - - Set unique1 = new HashSet<>(a); - unique1.removeAll(common); - - Set unique2 = new HashSet<>(b); - unique2.removeAll(common); - - return new Comm(common, unique1, unique2); - } - } - private static String format(Set paths) { return Arrays.toString( paths.stream().sorted().map(Path::toString).toArray( diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index bb699ba3b9c..c2fc1789a25 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,32 +23,28 @@ package jdk.jpackage.test; -import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Collection; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.test.Annotations.AfterEach; import jdk.jpackage.test.Annotations.BeforeEach; -import jdk.jpackage.test.Annotations.Parameter; -import jdk.jpackage.test.Annotations.ParameterGroup; -import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Functional.ThrowingConsumer; +import static jdk.jpackage.test.Functional.ThrowingConsumer.toConsumer; import jdk.jpackage.test.Functional.ThrowingFunction; +import jdk.jpackage.test.TestMethodSupplier.InvalidAnnotationException; +import static jdk.jpackage.test.TestMethodSupplier.MethodQuery.fromQualifiedMethodName; final class TestBuilder implements AutoCloseable { @@ -58,6 +54,7 @@ public void close() throws Exception { } TestBuilder(Consumer testConsumer) { + this.testMethodSupplier = TestBuilderConfig.getDefault().createTestMethodSupplier(); argProcessors = Map.of( CMDLINE_ARG_PREFIX + "after-run", arg -> getJavaMethodsFromArg(arg).map( @@ -70,7 +67,7 @@ public void close() throws Exception { CMDLINE_ARG_PREFIX + "run", arg -> addTestGroup(getJavaMethodsFromArg(arg).map( ThrowingFunction.toFunction( - TestBuilder::toMethodCalls)).flatMap(s -> s).collect( + this::toMethodCalls)).flatMap(s -> s).collect( Collectors.toList())), CMDLINE_ARG_PREFIX + "exclude", @@ -219,23 +216,29 @@ private static Stream selectFrameMethods(Class type, Class annotationTyp .filter(m -> m.getParameterCount() == 0) .filter(m -> !m.isAnnotationPresent(Test.class)) .filter(m -> m.isAnnotationPresent(annotationType)) - .sorted((a, b) -> a.getName().compareTo(b.getName())); + .sorted(Comparator.comparing(Method::getName)); } - private static Stream cmdLineArgValueToMethodNames(String v) { + private Stream cmdLineArgValueToMethodNames(String v) { List result = new ArrayList<>(); String defaultClassName = null; for (String token : v.split(",")) { Class testSet = probeClass(token); if (testSet != null) { + if (testMethodSupplier.isTestClass(testSet)) { + toConsumer(testMethodSupplier::verifyTestClass).accept(testSet); + } + // Test set class specified. Pull in all public methods // from the class with @Test annotation removing name duplicates. // Overloads will be handled at the next phase of processing. defaultClassName = token; - Stream.of(testSet.getMethods()).filter( - m -> m.isAnnotationPresent(Test.class)).map( - Method::getName).distinct().forEach( - name -> result.add(String.join(".", token, name))); + result.addAll(Stream.of(testSet.getMethods()) + .filter(m -> m.isAnnotationPresent(Test.class)) + .filter(testMethodSupplier::isEnabled) + .map(Method::getName).distinct() + .map(name -> String.join(".", token, name)) + .toList()); continue; } @@ -246,7 +249,7 @@ private static Stream cmdLineArgValueToMethodNames(String v) { qualifiedMethodName = token; defaultClassName = token.substring(0, lastDotIdx); } else if (defaultClassName == null) { - throw new ParseException("Default class name not found in"); + throw new ParseException("Missing default class name in"); } else { qualifiedMethodName = String.join(".", defaultClassName, token); } @@ -255,155 +258,43 @@ private static Stream cmdLineArgValueToMethodNames(String v) { return result.stream(); } - private static boolean filterMethod(String expectedMethodName, Method method) { - if (!method.getName().equals(expectedMethodName)) { - return false; - } - switch (method.getParameterCount()) { - case 0: - return !isParametrized(method); - case 1: - return isParametrized(method); - } - return false; - } - - private static boolean isParametrized(Method method) { - return method.isAnnotationPresent(ParameterGroup.class) || method.isAnnotationPresent( - Parameter.class); - } - - private static List getJavaMethodFromString( - String qualifiedMethodName) { + private List getJavaMethodFromString(String qualifiedMethodName) { int lastDotIdx = qualifiedMethodName.lastIndexOf('.'); if (lastDotIdx == -1) { - throw new ParseException("Class name not found in"); - } - String className = qualifiedMethodName.substring(0, lastDotIdx); - String methodName = qualifiedMethodName.substring(lastDotIdx + 1); - Class methodClass; - try { - methodClass = Class.forName(className); - } catch (ClassNotFoundException ex) { - throw new ParseException(String.format("Class [%s] not found;", - className)); - } - // Get the list of all public methods as need to deal with overloads. - List methods = Stream.of(methodClass.getMethods()).filter( - (m) -> filterMethod(methodName, m)).collect(Collectors.toList()); - if (methods.isEmpty()) { - throw new ParseException(String.format( - "Method [%s] not found in [%s] class;", - methodName, className)); + throw new ParseException("Missing class name in"); } - trace(String.format("%s -> %s", qualifiedMethodName, methods)); - return methods; - } - - private static Stream getJavaMethodsFromArg(String argValue) { - return cmdLineArgValueToMethodNames(argValue).map( - ThrowingFunction.toFunction( - TestBuilder::getJavaMethodFromString)).flatMap( - List::stream).sequential(); - } - - private static Parameter[] getMethodParameters(Method method) { - if (method.isAnnotationPresent(ParameterGroup.class)) { - return ((ParameterGroup) method.getAnnotation(ParameterGroup.class)).value(); - } - - if (method.isAnnotationPresent(Parameter.class)) { - return new Parameter[]{(Parameter) method.getAnnotation( - Parameter.class)}; - } - - // Unexpected - return null; - } - - private static Stream toCtorArgs(Method method) throws - IllegalAccessException, InvocationTargetException { - Class type = method.getDeclaringClass(); - List paremetersProviders = Stream.of(type.getMethods()) - .filter(m -> m.getParameterCount() == 0) - .filter(m -> (m.getModifiers() & Modifier.STATIC) != 0) - .filter(m -> m.isAnnotationPresent(Parameters.class)) - .sorted() - .collect(Collectors.toList()); - if (paremetersProviders.isEmpty()) { - // Single instance using the default constructor. - return Stream.ofNullable(MethodCall.DEFAULT_CTOR_ARGS); - } - - // Pick the first method from the list. - Method paremetersProvider = paremetersProviders.iterator().next(); - if (paremetersProviders.size() > 1) { - trace(String.format( - "Found %d public static methods without arguments with %s annotation. Will use %s", - paremetersProviders.size(), Parameters.class, - paremetersProvider)); - paremetersProviders.stream().map(Method::toString).forEach( - TestBuilder::trace); + try { + return testMethodSupplier.findNullaryLikeMethods( + fromQualifiedMethodName(qualifiedMethodName)); + } catch (NoSuchMethodException ex) { + throw new ParseException(ex.getMessage() + ";", ex); } - - // Construct collection of arguments for test class instances. - return ((Collection) paremetersProvider.invoke(null)).stream(); } - private static Stream toMethodCalls(Method method) throws - IllegalAccessException, InvocationTargetException { - return toCtorArgs(method).map(v -> toMethodCalls(v, method)).flatMap( - s -> s).peek(methodCall -> { - // Make sure required constructor is accessible if the one is needed. - // Need to probe all methods as some of them might be static - // and some class members. - // Only class members require ctors. - try { - methodCall.checkRequiredConstructor(); - } catch (NoSuchMethodException ex) { - throw new ParseException(ex.getMessage() + "."); - } - }); + private Stream getJavaMethodsFromArg(String argValue) { + var methods = cmdLineArgValueToMethodNames(argValue) + .map(this::getJavaMethodFromString) + .flatMap(List::stream).toList(); + trace(String.format("%s -> %s", argValue, methods)); + return methods.stream(); } - private static Stream toMethodCalls(Object[] ctorArgs, Method method) { - if (!isParametrized(method)) { - return Stream.of(new MethodCall(ctorArgs, method)); - } - Parameter[] annotations = getMethodParameters(method); - if (annotations.length == 0) { - return Stream.of(new MethodCall(ctorArgs, method)); - } - return Stream.of(annotations).map((a) -> { - Class paramType = method.getParameterTypes()[0]; - final Object annotationValue; - if (!paramType.isArray()) { - annotationValue = fromString(a.value()[0], paramType); - } else { - Class paramComponentType = paramType.getComponentType(); - annotationValue = Array.newInstance(paramComponentType, a.value().length); - var idx = new AtomicInteger(-1); - Stream.of(a.value()).map(v -> fromString(v, paramComponentType)).sequential().forEach( - v -> Array.set(annotationValue, idx.incrementAndGet(), v)); + private Stream toMethodCalls(Method method) throws + IllegalAccessException, InvocationTargetException, InvalidAnnotationException { + return testMethodSupplier.mapToMethodCalls(method).peek(methodCall -> { + // Make sure required constructor is accessible if the one is needed. + // Need to probe all methods as some of them might be static + // and some class members. + // Only class members require ctors. + try { + methodCall.checkRequiredConstructor(); + } catch (NoSuchMethodException ex) { + throw new ParseException(ex.getMessage() + ".", ex); } - return new MethodCall(ctorArgs, method, annotationValue); }); } - private static Object fromString(String value, Class toType) { - if (toType.isEnum()) { - return Enum.valueOf(toType, value); - } - Function converter = conv.get(toType); - if (converter == null) { - throw new RuntimeException(String.format( - "Failed to find a conversion of [%s] string to %s type", - value, toType)); - } - return converter.apply(value); - } - // Wraps Method.invike() into ThrowingRunnable.run() private ThrowingConsumer wrap(Method method) { return (test) -> { @@ -427,6 +318,10 @@ private static class ParseException extends IllegalArgumentException { super(msg); } + ParseException(String msg, Exception ex) { + super(msg, ex); + } + void setContext(String badCmdLineArg) { this.badCmdLineArg = badCmdLineArg; } @@ -448,8 +343,9 @@ static void trace(String msg) { } } + private final TestMethodSupplier testMethodSupplier; private final Map> argProcessors; - private Consumer testConsumer; + private final Consumer testConsumer; private List testGroup; private List beforeActions; private List afterActions; @@ -458,14 +354,5 @@ static void trace(String msg) { private String spaceSubstitute; private boolean dryRun; - private final static Map> conv = Map.of( - boolean.class, Boolean::valueOf, - Boolean.class, Boolean::valueOf, - int.class, Integer::valueOf, - Integer.class, Integer::valueOf, - long.class, Long::valueOf, - Long.class, Long::valueOf, - String.class, String::valueOf); - - final static String CMDLINE_ARG_PREFIX = "--jpt-"; + static final String CMDLINE_ARG_PREFIX = "--jpt-"; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilderConfig.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilderConfig.java new file mode 100644 index 00000000000..baeaec32546 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilderConfig.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.test; + +import java.util.Objects; +import jdk.internal.util.OperatingSystem; + +final class TestBuilderConfig { + TestBuilderConfig() { + } + + TestMethodSupplier createTestMethodSupplier() { + return new TestMethodSupplier(os); + } + + OperatingSystem getOperatingSystem() { + return os; + } + + static TestBuilderConfig getDefault() { + return DEFAULT.get(); + } + + static void setOperatingSystem(OperatingSystem os) { + Objects.requireNonNull(os); + DEFAULT.get().os = os; + } + + static void setDefaults() { + DEFAULT.set(new TestBuilderConfig()); + } + + private OperatingSystem os = OperatingSystem.current(); + + private static final ThreadLocal DEFAULT = new ThreadLocal<>() { + @Override + protected TestBuilderConfig initialValue() { + return new TestBuilderConfig(); + } + }; +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index 105c8f707cd..f619c9e222e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,10 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -50,7 +52,7 @@ private TestDesc() { String testFullName() { StringBuilder sb = new StringBuilder(); - sb.append(clazz.getSimpleName()); + sb.append(clazz.getName()); if (instanceArgs != null) { sb.append('(').append(instanceArgs).append(')'); } @@ -78,12 +80,12 @@ Builder method(Method v) { } Builder ctorArgs(Object... v) { - ctorArgs = ofNullable(v); + ctorArgs = Arrays.asList(v); return this; } Builder methodArgs(Object... v) { - methodArgs = ofNullable(v); + methodArgs = Arrays.asList(v); return this; } @@ -107,22 +109,18 @@ private static String formatArgs(List values) { } return values.stream().map(v -> { if (v != null && v.getClass().isArray()) { - return String.format("%s(length=%d)", - Arrays.deepToString((Object[]) v), - Array.getLength(v)); + String asString; + if (v.getClass().getComponentType().isPrimitive()) { + asString = PRIMITIVE_ARRAY_FORMATTERS.get(v.getClass()).apply(v); + } else { + asString = Arrays.deepToString((Object[]) v); + } + return String.format("%s(length=%d)", asString, Array.getLength(v)); } return String.format("%s", v); }).collect(Collectors.joining(", ")); } - private static List ofNullable(Object... values) { - List result = new ArrayList(); - for (var v: values) { - result.add(v); - } - return result; - } - private List ctorArgs; private List methodArgs; private Method method; @@ -331,7 +329,7 @@ public String toString() { private final boolean dryRun; private final Path workDir; - private final static Set KEEP_WORK_DIR = Functional.identity( + private static final Set KEEP_WORK_DIR = Functional.identity( () -> { final String propertyName = "keep-work-dir"; Set keepWorkDir = TKit.tokenizeConfigProperty( @@ -355,4 +353,15 @@ public String toString() { return Collections.unmodifiableSet(result); }).get(); + private static final Map, Function> PRIMITIVE_ARRAY_FORMATTERS = Map.of( + boolean[].class, v -> Arrays.toString((boolean[])v), + byte[].class, v -> Arrays.toString((byte[])v), + char[].class, v -> Arrays.toString((char[])v), + short[].class, v -> Arrays.toString((short[])v), + int[].class, v -> Arrays.toString((int[])v), + long[].class, v -> Arrays.toString((long[])v), + float[].class, v -> Arrays.toString((float[])v), + double[].class, v -> Arrays.toString((double[])v) + ); + } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java new file mode 100644 index 00000000000..83b1c19bd95 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.test; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Executable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterGroup; +import jdk.jpackage.test.Annotations.ParameterSupplier; +import jdk.jpackage.test.Annotations.ParameterSupplierGroup; +import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Test; +import static jdk.jpackage.test.Functional.ThrowingFunction.toFunction; +import static jdk.jpackage.test.Functional.ThrowingSupplier.toSupplier; +import static jdk.jpackage.test.MethodCall.mapArgs; + +final class TestMethodSupplier { + + TestMethodSupplier(OperatingSystem os) { + Objects.requireNonNull(os); + this.os = os; + } + + record MethodQuery(String className, String methodName) { + + List lookup() throws ClassNotFoundException { + final Class methodClass = Class.forName(className); + + // Get the list of all public methods as need to deal with overloads. + return Stream.of(methodClass.getMethods()).filter(method -> { + return method.getName().equals(methodName); + }).toList(); + } + + static MethodQuery fromQualifiedMethodName(String qualifiedMethodName) { + int lastDotIdx = qualifiedMethodName.lastIndexOf('.'); + if (lastDotIdx == -1) { + throw new IllegalArgumentException("Class name not specified"); + } + + var className = qualifiedMethodName.substring(0, lastDotIdx); + var methodName = qualifiedMethodName.substring(lastDotIdx + 1); + + return new MethodQuery(className, methodName); + } + } + + List findNullaryLikeMethods(MethodQuery query) throws NoSuchMethodException { + List methods; + + try { + methods = query.lookup(); + } catch (ClassNotFoundException ex) { + throw new NoSuchMethodException( + String.format("Class [%s] not found", query.className())); + } + + if (methods.isEmpty()) { + throw new NoSuchMethodException(String.format( + "Public method [%s] not found in [%s] class", + query.methodName(), query.className())); + } + + methods = methods.stream().filter(method -> { + if (isParameterized(method) && isTest(method)) { + // Always accept test method with annotations producing arguments for its invocation. + return true; + } else { + return method.getParameterCount() == 0; + } + }).filter(this::isEnabled).toList(); + + if (methods.isEmpty()) { + throw new NoSuchMethodException(String.format( + "Suitable public method [%s] not found in [%s] class", + query.methodName(), query.className())); + } + + return methods; + } + + boolean isTestClass(Class type) { + var typeStatus = processedTypes.get(type); + if (typeStatus == null) { + typeStatus = Verifier.isTestClass(type) ? TypeStatus.TEST_CLASS : TypeStatus.NOT_TEST_CLASS; + processedTypes.put(type, typeStatus); + } + + return !TypeStatus.NOT_TEST_CLASS.equals(typeStatus); + } + + void verifyTestClass(Class type) throws InvalidAnnotationException { + var typeStatus = processedTypes.get(type); + if (typeStatus == null) { + // The "type" has not been verified yet. + try { + Verifier.verifyTestClass(type); + processedTypes.put(type, TypeStatus.VALID_TEST_CLASS); + return; + } catch (InvalidAnnotationException ex) { + processedTypes.put(type, TypeStatus.TEST_CLASS); + throw ex; + } + } + + switch (typeStatus) { + case NOT_TEST_CLASS -> Verifier.throwNotTestClassException(type); + case TEST_CLASS -> Verifier.verifyTestClass(type); + case VALID_TEST_CLASS -> {} + } + } + + boolean isEnabled(Method method) { + return Stream.of(Test.class, Parameters.class) + .filter(method::isAnnotationPresent) + .findFirst() + .map(method::getAnnotation) + .map(this::canRunOnTheOperatingSystem) + .orElse(true); + } + + Stream mapToMethodCalls(Method method) throws + IllegalAccessException, InvocationTargetException { + return toCtorArgs(method).map(v -> toMethodCalls(v, method)).flatMap(x -> x); + } + + private Stream toCtorArgs(Method method) throws + IllegalAccessException, InvocationTargetException { + + if ((method.getModifiers() & Modifier.STATIC) != 0) { + // Static method, no instance + return Stream.ofNullable(DEFAULT_CTOR_ARGS); + } + + final var type = method.getDeclaringClass(); + + final var paremeterSuppliers = filterParameterSuppliers(type) + .filter(m -> m.isAnnotationPresent(Parameters.class)) + .filter(this::isEnabled) + .sorted(Comparator.comparing(Method::getName)).toList(); + if (paremeterSuppliers.isEmpty()) { + // Single instance using the default constructor. + return Stream.ofNullable(DEFAULT_CTOR_ARGS); + } + + // Construct collection of arguments for test class instances. + return createArgs(paremeterSuppliers.toArray(Method[]::new)); + } + + private Stream toMethodCalls(Object[] ctorArgs, Method method) { + if (!isParameterized(method)) { + return Stream.of(new MethodCall(ctorArgs, method)); + } + + var fromParameter = Stream.of(getMethodParameters(method)).map(a -> { + return createArgsForAnnotation(method, a); + }).flatMap(List::stream); + + var fromParameterSupplier = Stream.of(getMethodParameterSuppliers(method)).map(a -> { + return toSupplier(() -> createArgsForAnnotation(method, a)).get(); + }).flatMap(List::stream); + + return Stream.concat(fromParameter, fromParameterSupplier).map(args -> { + return new MethodCall(ctorArgs, method, args); + }); + } + + private List createArgsForAnnotation(Executable exec, Parameter a) { + if (!canRunOnTheOperatingSystem(a)) { + return List.of(); + } + + final var annotationArgs = a.value(); + final var execParameterTypes = exec.getParameterTypes(); + + if (execParameterTypes.length > annotationArgs.length) { + if (execParameterTypes.length - annotationArgs.length == 1 && exec.isVarArgs()) { + } else { + throw new RuntimeException(String.format( + "Not enough annotation values %s for [%s]", + List.of(annotationArgs), exec)); + } + } + + final Class[] argTypes; + if (exec.isVarArgs()) { + List> argTypesBuilder = new ArrayList<>(); + var lastExecParameterTypeIdx = execParameterTypes.length - 1; + argTypesBuilder.addAll(List.of(execParameterTypes).subList(0, + lastExecParameterTypeIdx)); + argTypesBuilder.addAll(Collections.nCopies( + Integer.max(0, annotationArgs.length - lastExecParameterTypeIdx), + execParameterTypes[lastExecParameterTypeIdx].componentType())); + argTypes = argTypesBuilder.toArray(Class[]::new); + } else { + argTypes = execParameterTypes; + } + + if (argTypes.length < annotationArgs.length) { + throw new RuntimeException(String.format( + "Too many annotation values %s for [%s]", + List.of(annotationArgs), exec)); + } + + var args = mapArgs(exec, IntStream.range(0, argTypes.length).mapToObj(idx -> { + return fromString(annotationArgs[idx], argTypes[idx]); + }).toArray(Object[]::new)); + + return List.of(args); + } + + private List createArgsForAnnotation(Executable exec, + ParameterSupplier a) throws IllegalAccessException, + InvocationTargetException { + if (!canRunOnTheOperatingSystem(a)) { + return List.of(); + } + + final Class execClass = exec.getDeclaringClass(); + final var supplierFuncName = a.value(); + + final MethodQuery methodQuery; + if (!a.value().contains(".")) { + // No class name specified + methodQuery = new MethodQuery(execClass.getName(), a.value()); + } else { + methodQuery = MethodQuery.fromQualifiedMethodName(supplierFuncName); + } + + final Method supplierMethod; + try { + final var parameterSupplierCandidates = findNullaryLikeMethods(methodQuery); + final Function classForName = toFunction(Class::forName); + final var supplierMethodClass = classForName.apply(methodQuery.className()); + if (parameterSupplierCandidates.isEmpty()) { + throw new RuntimeException(String.format( + "No parameter suppliers in [%s] class", + supplierMethodClass.getName())); + } + + var allParameterSuppliers = filterParameterSuppliers(supplierMethodClass).toList(); + + supplierMethod = findNullaryLikeMethods(methodQuery) + .stream() + .filter(allParameterSuppliers::contains) + .findFirst().orElseThrow(() -> { + var msg = String.format( + "No suitable parameter supplier found for %s(%s) annotation", + a, supplierFuncName); + trace(String.format( + "%s. Parameter suppliers of %s class:", msg, + execClass.getName())); + IntStream.range(0, allParameterSuppliers.size()).mapToObj(idx -> { + return String.format(" [%d/%d] %s()", idx + 1, + allParameterSuppliers.size(), + allParameterSuppliers.get(idx).getName()); + }).forEachOrdered(TestMethodSupplier::trace); + + return new RuntimeException(msg); + }); + } catch (NoSuchMethodException ex) { + throw new RuntimeException(String.format( + "Method not found for %s(%s) annotation", a, supplierFuncName)); + } + + return createArgs(supplierMethod).map(args -> { + return mapArgs(exec, args); + }).toList(); + } + + private boolean canRunOnTheOperatingSystem(Annotation a) { + switch (a) { + case Test t -> { + return canRunOnTheOperatingSystem(os, t.ifOS(), t.ifNotOS()); + } + case Parameters t -> { + return canRunOnTheOperatingSystem(os, t.ifOS(), t.ifNotOS()); + } + case Parameter t -> { + return canRunOnTheOperatingSystem(os, t.ifOS(), t.ifNotOS()); + } + case ParameterSupplier t -> { + return canRunOnTheOperatingSystem(os, t.ifOS(), t.ifNotOS()); + } + default -> { + return true; + } + } + } + + private static boolean isParameterized(Method method) { + return Stream.of( + Parameter.class, ParameterGroup.class, + ParameterSupplier.class, ParameterSupplierGroup.class + ).anyMatch(method::isAnnotationPresent); + } + + private static boolean isTest(Method method) { + return method.isAnnotationPresent(Test.class); + } + + private static boolean canRunOnTheOperatingSystem(OperatingSystem value, + OperatingSystem[] include, OperatingSystem[] exclude) { + Set suppordOperatingSystems = new HashSet<>(); + suppordOperatingSystems.addAll(List.of(include)); + suppordOperatingSystems.removeAll(List.of(exclude)); + return suppordOperatingSystems.contains(value); + } + + private static Parameter[] getMethodParameters(Method method) { + if (method.isAnnotationPresent(ParameterGroup.class)) { + return ((ParameterGroup) method.getAnnotation(ParameterGroup.class)).value(); + } + + if (method.isAnnotationPresent(Parameter.class)) { + return new Parameter[]{(Parameter) method.getAnnotation(Parameter.class)}; + } + + return new Parameter[0]; + } + + private static ParameterSupplier[] getMethodParameterSuppliers(Method method) { + if (method.isAnnotationPresent(ParameterSupplierGroup.class)) { + return ((ParameterSupplierGroup) method.getAnnotation(ParameterSupplierGroup.class)).value(); + } + + if (method.isAnnotationPresent(ParameterSupplier.class)) { + return new ParameterSupplier[]{(ParameterSupplier) method.getAnnotation( + ParameterSupplier.class)}; + } + + return new ParameterSupplier[0]; + } + + private static Stream filterParameterSuppliers(Class type) { + return Stream.of(type.getMethods()) + .filter(m -> m.getParameterCount() == 0) + .filter(m -> (m.getModifiers() & Modifier.STATIC) != 0) + .sorted(Comparator.comparing(Method::getName)); + } + + private static Stream createArgs(Method ... parameterSuppliers) throws + IllegalAccessException, InvocationTargetException { + List args = new ArrayList<>(); + for (var parameterSupplier : parameterSuppliers) { + args.addAll((Collection) parameterSupplier.invoke(null)); + } + return args.stream(); + } + + private static Object fromString(String value, Class toType) { + if (toType.isEnum()) { + return Enum.valueOf(toType, value); + } + Function converter = FROM_STRING.get(toType); + if (converter == null) { + throw new RuntimeException(String.format( + "Failed to find a conversion of [%s] string to %s type", + value, toType.getName())); + } + return converter.apply(value); + } + + private static void trace(String msg) { + if (TKit.VERBOSE_TEST_SETUP) { + TKit.log(msg); + } + } + + static class InvalidAnnotationException extends Exception { + InvalidAnnotationException(String msg) { + super(msg); + } + } + + private static class Verifier { + static boolean isTestClass(Class type) { + for (var method : type.getDeclaredMethods()) { + if (isParameterized(method) || isTest(method)) { + return true; + } + } + return false; + } + + static void verifyTestClass(Class type) throws InvalidAnnotationException { + boolean withTestAnnotations = false; + for (var method : type.getDeclaredMethods()) { + if (!withTestAnnotations && (isParameterized(method) || isTest(method))) { + withTestAnnotations = true; + } + verifyAnnotationsCorrect(method); + } + + if (!withTestAnnotations) { + throwNotTestClassException(type); + } + } + + static void throwNotTestClassException(Class type) throws InvalidAnnotationException { + throw new InvalidAnnotationException(String.format( + "Type [%s] is not a test class", type.getName())); + } + + private static void verifyAnnotationsCorrect(Method method) throws + InvalidAnnotationException { + var parameterized = isParameterized(method); + if (parameterized && !isTest(method)) { + throw new InvalidAnnotationException(String.format( + "Missing %s annotation on [%s] method", Test.class.getName(), method)); + } + + var isPublic = Modifier.isPublic(method.getModifiers()); + + if (isTest(method) && !isPublic) { + throw new InvalidAnnotationException(String.format( + "Non-public method [%s] with %s annotation", + method, Test.class.getName())); + } + + if (method.isAnnotationPresent(Parameters.class) && !isPublic) { + throw new InvalidAnnotationException(String.format( + "Non-public method [%s] with %s annotation", + method, Test.class.getName())); + } + } + } + + private enum TypeStatus { + NOT_TEST_CLASS, + TEST_CLASS, + VALID_TEST_CLASS, + } + + private final OperatingSystem os; + private final Map, TypeStatus> processedTypes = new HashMap<>(); + + private static final Object[] DEFAULT_CTOR_ARGS = new Object[0]; + + private static final Map> FROM_STRING; + + static { + Map> primitives = Map.of( + boolean.class, Boolean::valueOf, + byte.class, Byte::valueOf, + short.class, Short::valueOf, + int.class, Integer::valueOf, + long.class, Long::valueOf, + float.class, Float::valueOf, + double.class, Double::valueOf); + + Map> boxed = Map.of( + Boolean.class, Boolean::valueOf, + Byte.class, Byte::valueOf, + Short.class, Short::valueOf, + Integer.class, Integer::valueOf, + Long.class, Long::valueOf, + Float.class, Float::valueOf, + Double.class, Double::valueOf); + + Map> other = Map.of( + String.class, String::valueOf, + Path.class, Path::of); + + Map> combined = new HashMap<>(primitives); + combined.putAll(other); + combined.putAll(boxed); + + FROM_STRING = Collections.unmodifiableMap(combined); + } +} diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index f8cb983bd16..15d96283ef4 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -29,12 +29,12 @@ import java.util.List; import java.util.Set; import java.util.function.Predicate; -import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.internal.PackageFile; -import jdk.jpackage.test.Annotations; +import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.JPackageCommand; @@ -55,47 +55,51 @@ */ public final class InOutPathTest { - @Annotations.Parameters + @Parameters public static Collection input() { List data = new ArrayList<>(); - for (var packageTypes : List.of(PackageType.IMAGE.toString(), ALL_NATIVE_PACKAGE_TYPES)) { + for (var packageTypeAlias : PackageTypeAlias.values()) { data.addAll(List.of(new Object[][]{ - {packageTypes, wrap(InOutPathTest::outputDirInInputDir, "--dest in --input")}, - {packageTypes, wrap(InOutPathTest::outputDirSameAsInputDir, "--dest same as --input")}, - {packageTypes, wrap(InOutPathTest::tempDirInInputDir, "--temp in --input")}, - {packageTypes, wrap(cmd -> { + {packageTypeAlias, wrap(InOutPathTest::outputDirInInputDir, "--dest in --input")}, + {packageTypeAlias, wrap(InOutPathTest::outputDirSameAsInputDir, "--dest same as --input")}, + {packageTypeAlias, wrap(InOutPathTest::tempDirInInputDir, "--temp in --input")}, + {packageTypeAlias, wrap(cmd -> { outputDirInInputDir(cmd); tempDirInInputDir(cmd); }, "--dest and --temp in --input")}, })); - data.addAll(additionalContentInput(packageTypes, "--app-content")); + data.addAll(additionalContentInput(packageTypeAlias, "--app-content")); } - if (!TKit.isOSX()) { - data.addAll(List.of(new Object[][]{ - {PackageType.IMAGE.toString(), wrap(cmd -> { - additionalContent(cmd, "--app-content", cmd.outputBundle()); - }, "--app-content same as output bundle")}, - })); - } else { - var contentsFolder = "Contents/MacOS"; - data.addAll(List.of(new Object[][]{ - {PackageType.IMAGE.toString(), wrap(cmd -> { - additionalContent(cmd, "--app-content", cmd.outputBundle().resolve(contentsFolder)); - }, String.format("--app-content same as the \"%s\" folder in the output bundle", contentsFolder))}, - })); - } + return data; + } - if (TKit.isOSX()) { - data.addAll(additionalContentInput(PackageType.MAC_DMG.toString(), - "--mac-dmg-content")); - } + @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")}, + }); + } - return data; + @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))}, + }); } - private static List additionalContentInput(String packageTypes, String argName) { + @Parameters(ifOS = OperatingSystem.MACOS) + public static Collection inputOSX() { + return List.of(additionalContentInput(PackageType.MAC_DMG, "--mac-dmg-content").toArray(Object[][]::new)); + } + + private static List additionalContentInput(Object packageTypes, String argName) { List data = new ArrayList<>(); data.addAll(List.of(new Object[][]{ @@ -127,13 +131,16 @@ private static List additionalContentInput(String packageTypes, String return data; } - public InOutPathTest(String packageTypes, Envelope configure) { - if (ALL_NATIVE_PACKAGE_TYPES.equals(packageTypes)) { - this.packageTypes = PackageType.NATIVE; - } else { - this.packageTypes = Stream.of(packageTypes.split(",")).map( - PackageType::valueOf).collect(toSet()); - } + public InOutPathTest(PackageTypeAlias packageTypeAlias, Envelope configure) { + this(packageTypeAlias.packageTypes, configure); + } + + public InOutPathTest(PackageType packageType, Envelope configure) { + this(Set.of(packageType), configure); + } + + public InOutPathTest(Set packageTypes, Envelope configure) { + this.packageTypes = packageTypes; this.configure = configure.value; } @@ -271,6 +278,18 @@ public String toString() { } } + private enum PackageTypeAlias { + IMAGE(Set.of(PackageType.IMAGE)), + NATIVE(PackageType.NATIVE), + ; + + PackageTypeAlias(Set packageTypes) { + this.packageTypes = packageTypes; + } + + private final Set packageTypes; + } + private final Set packageTypes; private final ThrowingConsumer configure; @@ -279,6 +298,4 @@ public String toString() { // For other platforms it doesn't matter. Keep it the same across // all platforms for simplicity. private static final Path JAR_PATH = Path.of("Resources/duke.jar"); - - private static final String ALL_NATIVE_PACKAGE_TYPES = "NATIVE"; } diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index 7047f35e87b..23539589bcc 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -22,13 +22,12 @@ */ import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; +import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.TKit; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.Functional; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.Test; /** * Test --install-dir parameter. Output of the test should be @@ -76,28 +75,18 @@ */ public class InstallDirTest { - public static void testCommon() { - final Map INSTALL_DIRS = Functional.identity(() -> { - Map reply = new HashMap<>(); - reply.put(PackageType.WIN_MSI, Path.of("TestVendor\\InstallDirTest1234")); - reply.put(PackageType.WIN_EXE, reply.get(PackageType.WIN_MSI)); - - reply.put(PackageType.LINUX_DEB, Path.of("/opt/jpackage")); - reply.put(PackageType.LINUX_RPM, reply.get(PackageType.LINUX_DEB)); - - reply.put(PackageType.MAC_PKG, Path.of("/Applications/jpackage")); - reply.put(PackageType.MAC_DMG, reply.get(PackageType.MAC_PKG)); - - return reply; - }).get(); - + @Test + @Parameter(value = "TestVendor\\InstallDirTest1234", ifOS = OperatingSystem.WINDOWS) + @Parameter(value = "/opt/jpackage", ifOS = OperatingSystem.LINUX) + @Parameter(value = "/Applications/jpackage", ifOS = OperatingSystem.MACOS) + public static void testCommon(Path installDir) { new PackageTest().configureHelloApp() .addInitializer(cmd -> { - cmd.addArguments("--install-dir", INSTALL_DIRS.get( - cmd.packageType())); + cmd.addArguments("--install-dir", installDir); }).run(); } + @Test(ifOS = OperatingSystem.LINUX) @Parameter("/") @Parameter(".") @Parameter("foo") diff --git a/test/jdk/tools/sincechecker/modules/jdk.hotspot.agent/JdkHotspotAgentCheckSince.java b/test/jdk/tools/sincechecker/modules/jdk.hotspot.agent/JdkHotspotAgentCheckSince.java index 5f8b8162cd9..974550cc7b7 100644 --- a/test/jdk/tools/sincechecker/modules/jdk.hotspot.agent/JdkHotspotAgentCheckSince.java +++ b/test/jdk/tools/sincechecker/modules/jdk.hotspot.agent/JdkHotspotAgentCheckSince.java @@ -25,6 +25,7 @@ * @test * @bug 8343781 * @summary Test for `@since` in jdk.hotspot.agent module + * @requires vm.hasSA * @library /test/lib /test/jdk/tools/sincechecker * @run main SinceChecker jdk.hotspot.agent */