From abf2dc7128fc0644e85bca32d8f3beacc876cecb Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 5 Nov 2024 09:33:50 +0000 Subject: [PATCH 01/23] 8343298: Improve stability of runtime/cds/DeterministicDump.java test Reviewed-by: shade, iklam --- src/hotspot/share/cds/archiveHeapWriter.cpp | 7 ++++++- test/hotspot/jtreg/runtime/cds/DeterministicDump.java | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index 710e693bfdb..a55325978de 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -558,9 +558,12 @@ void ArchiveHeapWriter::update_header_for_requested_obj(oop requested_obj, oop s oop fake_oop = cast_to_oop(buffered_addr); fake_oop->set_narrow_klass(nk); + if (src_obj == nullptr) { + return; + } // We need to retain the identity_hash, because it may have been used by some hashtables // in the shared heap. - if (src_obj != nullptr && !src_obj->fast_no_hash_check()) { + if (!src_obj->fast_no_hash_check()) { intptr_t src_hash = src_obj->identity_hash(); fake_oop->set_mark(markWord::prototype().copy_set_hash(src_hash)); assert(fake_oop->mark().is_unlocked(), "sanity"); @@ -568,6 +571,8 @@ void ArchiveHeapWriter::update_header_for_requested_obj(oop requested_obj, oop s DEBUG_ONLY(intptr_t archived_hash = fake_oop->identity_hash()); assert(src_hash == archived_hash, "Different hash codes: original " INTPTR_FORMAT ", archived " INTPTR_FORMAT, src_hash, archived_hash); } + // Strip age bits. + fake_oop->set_mark(fake_oop->mark().set_age(0)); } class ArchiveHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure { diff --git a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java index cc8d8c2b1dd..6b6431c0e5e 100644 --- a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java +++ b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java @@ -50,8 +50,10 @@ public static void main(String[] args) throws Exception { public static void doTest(boolean compressed) throws Exception { ArrayList baseArgs = new ArrayList<>(); - // Use the same heap size as make/Images.gmk + // Try to reduce indeterminism of GC heap sizing and evacuation. baseArgs.add("-Xmx128M"); + baseArgs.add("-Xms128M"); + baseArgs.add("-Xmn120M"); if (Platform.is64bit()) { // This option is available only on 64-bit. @@ -80,7 +82,7 @@ static String dump(ArrayList args, String... more) throws Exception { String mapName = logName + ".map"; CDSOptions opts = (new CDSOptions()) .addPrefix("-Xint") // Override any -Xmixed/-Xcomp flags from jtreg -vmoptions - .addPrefix("-Xlog:cds=debug") + .addPrefix("-Xlog:cds=debug,gc=debug") .addPrefix("-Xlog:cds+map*=trace:file=" + mapName + ":none:filesize=0") .setArchiveName(archiveName) .addSuffix(args) From 4fc6d4135e795d18a024a6035908f380b81082d1 Mon Sep 17 00:00:00 2001 From: Mikhail Ablakatov Date: Tue, 5 Nov 2024 10:20:51 +0000 Subject: [PATCH 02/23] 8341194: [REDO] Implement C2 VectorizedHashCode on AArch64 Reviewed-by: aph, adinn --- src/hotspot/cpu/aarch64/aarch64.ad | 44 + src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 68 +- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 96 ++ .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp | 7 + .../cpu/aarch64/macroAssembler_aarch64.hpp | 18 + .../cpu/aarch64/stubGenerator_aarch64.cpp | 310 +++++ .../cpu/aarch64/stubRoutines_aarch64.cpp | 7 +- .../cpu/aarch64/stubRoutines_aarch64.hpp | 26 +- .../cpu/aarch64/vm_version_aarch64.cpp | 4 + src/hotspot/share/utilities/intpow.hpp | 46 + test/hotspot/gtest/aarch64/aarch64-asmtest.py | 111 ++ test/hotspot/gtest/aarch64/asmtest.out.h | 1189 +++++++++-------- 12 files changed, 1346 insertions(+), 580 deletions(-) create mode 100644 src/hotspot/share/utilities/intpow.hpp diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index eb473f97979..0ce06dd8341 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -5028,6 +5028,24 @@ operand vRegD_V7() interface(REG_INTER); %} +operand vRegD_V12() +%{ + constraint(ALLOC_IN_RC(v12_reg)); + match(RegD); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vRegD_V13() +%{ + constraint(ALLOC_IN_RC(v13_reg)); + match(RegD); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + operand pReg() %{ constraint(ALLOC_IN_RC(pr_reg)); @@ -16770,6 +16788,32 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, ins_pipe(pipe_class_memory); %} +instruct arrays_hashcode(iRegP_R1 ary, iRegI_R2 cnt, iRegI_R0 result, immI basic_type, + vRegD_V0 vtmp0, vRegD_V1 vtmp1, vRegD_V2 vtmp2, vRegD_V3 vtmp3, + vRegD_V4 vtmp4, vRegD_V5 vtmp5, vRegD_V6 vtmp6, vRegD_V7 vtmp7, + vRegD_V12 vtmp8, vRegD_V13 vtmp9, rFlagsReg cr) +%{ + match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type))); + effect(TEMP vtmp0, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP vtmp4, TEMP vtmp5, TEMP vtmp6, + TEMP vtmp7, TEMP vtmp8, TEMP vtmp9, USE_KILL ary, USE_KILL cnt, USE basic_type, KILL cr); + + format %{ "Array HashCode array[] $ary,$cnt,$result,$basic_type -> $result // KILL all" %} + ins_encode %{ + address tpc = __ arrays_hashcode($ary$$Register, $cnt$$Register, $result$$Register, + $vtmp3$$FloatRegister, $vtmp2$$FloatRegister, + $vtmp1$$FloatRegister, $vtmp0$$FloatRegister, + $vtmp4$$FloatRegister, $vtmp5$$FloatRegister, + $vtmp6$$FloatRegister, $vtmp7$$FloatRegister, + $vtmp8$$FloatRegister, $vtmp9$$FloatRegister, + (BasicType)$basic_type$$constant); + if (tpc == nullptr) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } + %} + ins_pipe(pipe_class_memory); +%} + instruct count_positives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr) %{ match(Set result (CountPositives ary1 len)); diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 28a0cc2c7d9..a5e0e2665af 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2024, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -287,6 +287,11 @@ class Instruction_aarch64 { f(r->raw_encoding(), lsb + 4, lsb); } + //<0-15>reg: As `rf(FloatRegister)`, but only the lower 16 FloatRegisters are allowed. + void lrf(FloatRegister r, int lsb) { + f(r->raw_encoding(), lsb + 3, lsb); + } + void prf(PRegister r, int lsb) { f(r->raw_encoding(), lsb + 3, lsb); } @@ -765,6 +770,7 @@ class Assembler : public AbstractAssembler { #define f current_insn.f #define sf current_insn.sf #define rf current_insn.rf +#define lrf current_insn.lrf #define srf current_insn.srf #define zrf current_insn.zrf #define prf current_insn.prf @@ -1590,6 +1596,16 @@ class Assembler : public AbstractAssembler { #undef INSN + // Load/store a register, but with a BasicType parameter. Loaded signed integer values are + // extended to 64 bits. + void load(Register Rt, const Address &adr, BasicType bt) { + int op = (is_signed_subword_type(bt) || bt == T_INT) ? 0b10 : 0b01; + ld_st2(Rt, adr, exact_log2(type2aelembytes(bt)), op); + } + void store(Register Rt, const Address &adr, BasicType bt) { + ld_st2(Rt, adr, exact_log2(type2aelembytes(bt)), 0b00); + } + /* SIMD extensions * * We just use FloatRegister in the following. They are exactly the same @@ -2587,6 +2603,7 @@ template INSN(addpv, 0, 0b101111, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D INSN(smullv, 0, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(umullv, 1, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S + INSN(smlalv, 0, 0b100000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(umlalv, 1, 0b100000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(maxv, 0, 0b011001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(minv, 0, 0b011011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S @@ -2860,6 +2877,28 @@ template // FMULX - Vector - Scalar INSN(fmulxvs, 1, 0b1001); +#undef INSN + +#define INSN(NAME, op1, op2) \ + void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, int index) { \ + starti; \ + assert(T == T4H || T == T8H || T == T2S || T == T4S, "invalid arrangement"); \ + assert(index >= 0 && \ + ((T == T2S && index <= 1) || (T != T2S && index <= 3) || (T == T8H && index <= 7)), \ + "invalid index"); \ + assert((T != T4H && T != T8H) || Vm->encoding() < 16, "invalid source SIMD&FP register"); \ + f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01111, 28, 24); \ + if (T == T4H || T == T8H) { \ + f(0b01, 23, 22), f(index & 0b11, 21, 20), lrf(Vm, 16), f(index >> 2 & 1, 11); \ + } else { \ + f(0b10, 23, 22), f(index & 1, 21), rf(Vm, 16), f(index >> 1, 11); \ + } \ + f(op2, 15, 12), f(0, 10), rf(Vn, 5), rf(Vd, 0); \ + } + + // MUL - Vector - Scalar + INSN(mulvs, 0, 0b1000); + #undef INSN // Floating-point Reciprocal Estimate @@ -3023,6 +3062,33 @@ template umov(Xd, Vn, T, index); } + protected: + void _xaddwv(bool is_unsigned, FloatRegister Vd, FloatRegister Vn, SIMD_Arrangement Ta, + FloatRegister Vm, SIMD_Arrangement Tb) { + starti; + assert((Tb >> 1) + 1 == (Ta >> 1), "Incompatible arrangement"); + f(0, 31), f((int)Tb & 1, 30), f(is_unsigned ? 1 : 0, 29), f(0b01110, 28, 24); + f((int)(Ta >> 1) - 1, 23, 22), f(1, 21), rf(Vm, 16), f(0b000100, 15, 10), rf(Vn, 5), rf(Vd, 0); + } + + public: +#define INSN(NAME, assertion, is_unsigned) \ + void NAME(FloatRegister Vd, FloatRegister Vn, SIMD_Arrangement Ta, FloatRegister Vm, \ + SIMD_Arrangement Tb) { \ + assert((assertion), "invalid arrangement"); \ + _xaddwv(is_unsigned, Vd, Vn, Ta, Vm, Tb); \ + } + +public: + + INSN(uaddwv, Tb == T8B || Tb == T4H || Tb == T2S, /*is_unsigned*/true) + INSN(uaddwv2, Tb == T16B || Tb == T8H || Tb == T4S, /*is_unsigned*/true) + INSN(saddwv, Tb == T8B || Tb == T4H || Tb == T2S, /*is_unsigned*/false) + INSN(saddwv2, Tb == T16B || Tb == T8H || Tb == T4S, /*is_unsigned*/false) + +#undef INSN + + private: void _pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) { starti; diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index b29be7213ba..5ce76106c9e 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -33,6 +33,7 @@ #include "opto/subnode.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -46,6 +47,101 @@ typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr); +// jdk.internal.util.ArraysSupport.vectorizedHashCode +address C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register result, + FloatRegister vdata0, FloatRegister vdata1, + FloatRegister vdata2, FloatRegister vdata3, + FloatRegister vmul0, FloatRegister vmul1, + FloatRegister vmul2, FloatRegister vmul3, + FloatRegister vpow, FloatRegister vpowm, + BasicType eltype) { + ARRAYS_HASHCODE_REGISTERS; + + Register tmp1 = rscratch1, tmp2 = rscratch2; + + Label TAIL, STUB_SWITCH, STUB_SWITCH_OUT, LOOP, BR_BASE, LARGE, DONE; + + // Vectorization factor. Number of array elements loaded to one SIMD&FP registers by the stubs. We + // use 8H load arrangements for chars and shorts and 8B for booleans and bytes. It's possible to + // use 4H for chars and shorts instead, but using 8H gives better performance. + const size_t vf = eltype == T_BOOLEAN || eltype == T_BYTE ? 8 + : eltype == T_CHAR || eltype == T_SHORT ? 8 + : eltype == T_INT ? 4 + : 0; + guarantee(vf, "unsupported eltype"); + + // Unroll factor for the scalar loop below. The value is chosen based on performance analysis. + const size_t unroll_factor = 4; + + switch (eltype) { + case T_BOOLEAN: + BLOCK_COMMENT("arrays_hashcode(unsigned byte) {"); + break; + case T_CHAR: + BLOCK_COMMENT("arrays_hashcode(char) {"); + break; + case T_BYTE: + BLOCK_COMMENT("arrays_hashcode(byte) {"); + break; + case T_SHORT: + BLOCK_COMMENT("arrays_hashcode(short) {"); + break; + case T_INT: + BLOCK_COMMENT("arrays_hashcode(int) {"); + break; + default: + ShouldNotReachHere(); + } + + // large_arrays_hashcode(T_INT) performs worse than the scalar loop below when the Neon loop + // implemented by the stub executes just once. Call the stub only if at least two iterations will + // be executed. + const size_t large_threshold = eltype == T_INT ? vf * 2 : vf; + cmpw(cnt, large_threshold); + br(Assembler::HS, LARGE); + + bind(TAIL); + + // The andr performs cnt % uf where uf = unroll_factor. The subtract shifted by 3 offsets past + // uf - (cnt % uf) pairs of load + madd insns i.e. it only executes cnt % uf load + madd pairs. + // Iteration eats up the remainder, uf elements at a time. + assert(is_power_of_2(unroll_factor), "can't use this value to calculate the jump target PC"); + andr(tmp2, cnt, unroll_factor - 1); + adr(tmp1, BR_BASE); + sub(tmp1, tmp1, tmp2, ext::sxtw, 3); + movw(tmp2, 0x1f); + br(tmp1); + + bind(LOOP); + for (size_t i = 0; i < unroll_factor; ++i) { + load(tmp1, Address(post(ary, type2aelembytes(eltype))), eltype); + maddw(result, result, tmp2, tmp1); + } + bind(BR_BASE); + subsw(cnt, cnt, unroll_factor); + br(Assembler::HS, LOOP); + + b(DONE); + + bind(LARGE); + + RuntimeAddress stub = RuntimeAddress(StubRoutines::aarch64::large_arrays_hashcode(eltype)); + assert(stub.target() != nullptr, "array_hashcode stub has not been generated"); + address tpc = trampoline_call(stub); + if (tpc == nullptr) { + DEBUG_ONLY(reset_labels(TAIL, BR_BASE)); + postcond(pc() == badAddress); + return nullptr; + } + + bind(DONE); + + BLOCK_COMMENT("} // arrays_hashcode"); + + postcond(pc() != badAddress); + return pc(); +} + void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register tmpReg, Register tmp2Reg, Register tmp3Reg) { Register oop = objectReg; diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index 43e60ae5a48..d61b050407d 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -35,6 +35,13 @@ enum shift_kind kind = Assembler::LSL, unsigned shift = 0); public: + // jdk.internal.util.ArraysSupport.vectorizedHashCode + address arrays_hashcode(Register ary, Register cnt, Register result, FloatRegister vdata0, + FloatRegister vdata1, FloatRegister vdata2, FloatRegister vdata3, + FloatRegister vmul0, FloatRegister vmul1, FloatRegister vmul2, + FloatRegister vmul3, FloatRegister vpow, FloatRegister vpowm, + BasicType eltype); + // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. void fast_lock(Register object, Register box, Register tmp, Register tmp2, Register tmp3); void fast_unlock(Register object, Register box, Register tmp, Register tmp2); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 48fb3c2b071..b4452688950 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1439,6 +1439,24 @@ class MacroAssembler: public Assembler { address arrays_equals(Register a1, Register a2, Register result, Register cnt1, Register tmp1, Register tmp2, Register tmp3, int elem_size); +// Ensure that the inline code and the stub use the same registers. +#define ARRAYS_HASHCODE_REGISTERS \ + do { \ + assert(result == r0 && \ + ary == r1 && \ + cnt == r2 && \ + vdata0 == v3 && \ + vdata1 == v2 && \ + vdata2 == v1 && \ + vdata3 == v0 && \ + vmul0 == v4 && \ + vmul1 == v5 && \ + vmul2 == v6 && \ + vmul3 == v7 && \ + vpow == v12 && \ + vpowm == v13, "registers must match aarch64.ad"); \ + } while (0) + void string_equals(Register a1, Register a2, Register result, Register cnt1); void fill_words(Register base, Register cnt, Register value); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index c0f2531b1ac..ecaaf0a98e9 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -54,7 +54,9 @@ #include "runtime/stubRoutines.hpp" #include "utilities/align.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/intpow.hpp" #include "utilities/powerOfTwo.hpp" #ifdef COMPILER2 #include "opto/runtime.hpp" @@ -5320,6 +5322,307 @@ class StubGenerator: public StubCodeGenerator { return entry; } + // result = r0 - return value. Contains initial hashcode value on entry. + // ary = r1 - array address + // cnt = r2 - elements count + // Clobbers: v0-v13, rscratch1, rscratch2 + address generate_large_arrays_hashcode(BasicType eltype) { + const Register result = r0, ary = r1, cnt = r2; + const FloatRegister vdata0 = v3, vdata1 = v2, vdata2 = v1, vdata3 = v0; + const FloatRegister vmul0 = v4, vmul1 = v5, vmul2 = v6, vmul3 = v7; + const FloatRegister vpow = v12; // powers of 31: <31^3, ..., 31^0> + const FloatRegister vpowm = v13; + + ARRAYS_HASHCODE_REGISTERS; + + Label SMALL_LOOP, LARGE_LOOP_PREHEADER, LARGE_LOOP, TAIL, TAIL_SHORTCUT, BR_BASE; + + unsigned int vf; // vectorization factor + bool multiply_by_halves; + Assembler::SIMD_Arrangement load_arrangement; + switch (eltype) { + case T_BOOLEAN: + case T_BYTE: + load_arrangement = Assembler::T8B; + multiply_by_halves = true; + vf = 8; + break; + case T_CHAR: + case T_SHORT: + load_arrangement = Assembler::T8H; + multiply_by_halves = true; + vf = 8; + break; + case T_INT: + load_arrangement = Assembler::T4S; + multiply_by_halves = false; + vf = 4; + break; + default: + ShouldNotReachHere(); + } + + // Unroll factor + const unsigned uf = 4; + + // Effective vectorization factor + const unsigned evf = vf * uf; + + __ align(CodeEntryAlignment); + + const char *mark_name = ""; + switch (eltype) { + case T_BOOLEAN: + mark_name = "_large_arrays_hashcode_boolean"; + break; + case T_BYTE: + mark_name = "_large_arrays_hashcode_byte"; + break; + case T_CHAR: + mark_name = "_large_arrays_hashcode_char"; + break; + case T_SHORT: + mark_name = "_large_arrays_hashcode_short"; + break; + case T_INT: + mark_name = "_large_arrays_hashcode_int"; + break; + default: + mark_name = "_large_arrays_hashcode_incorrect_type"; + __ should_not_reach_here(); + }; + + StubCodeMark mark(this, "StubRoutines", mark_name); + + address entry = __ pc(); + __ enter(); + + // Put 0-3'th powers of 31 into a single SIMD register together. The register will be used in + // the SMALL and LARGE LOOPS' epilogues. The initialization is hoisted here and the register's + // value shouldn't change throughout both loops. + __ movw(rscratch1, intpow(31U, 3)); + __ mov(vpow, Assembler::S, 0, rscratch1); + __ movw(rscratch1, intpow(31U, 2)); + __ mov(vpow, Assembler::S, 1, rscratch1); + __ movw(rscratch1, intpow(31U, 1)); + __ mov(vpow, Assembler::S, 2, rscratch1); + __ movw(rscratch1, intpow(31U, 0)); + __ mov(vpow, Assembler::S, 3, rscratch1); + + __ mov(vmul0, Assembler::T16B, 0); + __ mov(vmul0, Assembler::S, 3, result); + + __ andr(rscratch2, cnt, (uf - 1) * vf); + __ cbz(rscratch2, LARGE_LOOP_PREHEADER); + + __ movw(rscratch1, intpow(31U, multiply_by_halves ? vf / 2 : vf)); + __ mov(vpowm, Assembler::S, 0, rscratch1); + + // SMALL LOOP + __ bind(SMALL_LOOP); + + __ ld1(vdata0, load_arrangement, Address(__ post(ary, vf * type2aelembytes(eltype)))); + __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 0); + __ subsw(rscratch2, rscratch2, vf); + + if (load_arrangement == Assembler::T8B) { + // Extend 8B to 8H to be able to use vector multiply + // instructions + assert(load_arrangement == Assembler::T8B, "expected to extend 8B to 8H"); + if (is_signed_subword_type(eltype)) { + __ sxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); + } else { + __ uxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); + } + } + + switch (load_arrangement) { + case Assembler::T4S: + __ addv(vmul0, load_arrangement, vmul0, vdata0); + break; + case Assembler::T8B: + case Assembler::T8H: + assert(is_subword_type(eltype), "subword type expected"); + if (is_signed_subword_type(eltype)) { + __ saddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); + } else { + __ uaddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); + } + break; + default: + __ should_not_reach_here(); + } + + // Process the upper half of a vector + if (load_arrangement == Assembler::T8B || load_arrangement == Assembler::T8H) { + __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 0); + if (is_signed_subword_type(eltype)) { + __ saddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); + } else { + __ uaddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); + } + } + + __ br(Assembler::HI, SMALL_LOOP); + + // SMALL LOOP'S EPILOQUE + __ lsr(rscratch2, cnt, exact_log2(evf)); + __ cbnz(rscratch2, LARGE_LOOP_PREHEADER); + + __ mulv(vmul0, Assembler::T4S, vmul0, vpow); + __ addv(vmul0, Assembler::T4S, vmul0); + __ umov(result, vmul0, Assembler::S, 0); + + // TAIL + __ bind(TAIL); + + // The andr performs cnt % vf. The subtract shifted by 3 offsets past vf - 1 - (cnt % vf) pairs + // of load + madd insns i.e. it only executes cnt % vf load + madd pairs. + assert(is_power_of_2(vf), "can't use this value to calculate the jump target PC"); + __ andr(rscratch2, cnt, vf - 1); + __ bind(TAIL_SHORTCUT); + __ adr(rscratch1, BR_BASE); + __ sub(rscratch1, rscratch1, rscratch2, ext::uxtw, 3); + __ movw(rscratch2, 0x1f); + __ br(rscratch1); + + for (size_t i = 0; i < vf - 1; ++i) { + __ load(rscratch1, Address(__ post(ary, type2aelembytes(eltype))), + eltype); + __ maddw(result, result, rscratch2, rscratch1); + } + __ bind(BR_BASE); + + __ leave(); + __ ret(lr); + + // LARGE LOOP + __ bind(LARGE_LOOP_PREHEADER); + + __ lsr(rscratch2, cnt, exact_log2(evf)); + + if (multiply_by_halves) { + // 31^4 - multiplier between lower and upper parts of a register + __ movw(rscratch1, intpow(31U, vf / 2)); + __ mov(vpowm, Assembler::S, 1, rscratch1); + // 31^28 - remainder of the iteraion multiplier, 28 = 32 - 4 + __ movw(rscratch1, intpow(31U, evf - vf / 2)); + __ mov(vpowm, Assembler::S, 0, rscratch1); + } else { + // 31^16 + __ movw(rscratch1, intpow(31U, evf)); + __ mov(vpowm, Assembler::S, 0, rscratch1); + } + + __ mov(vmul3, Assembler::T16B, 0); + __ mov(vmul2, Assembler::T16B, 0); + __ mov(vmul1, Assembler::T16B, 0); + + __ bind(LARGE_LOOP); + + __ mulvs(vmul3, Assembler::T4S, vmul3, vpowm, 0); + __ mulvs(vmul2, Assembler::T4S, vmul2, vpowm, 0); + __ mulvs(vmul1, Assembler::T4S, vmul1, vpowm, 0); + __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 0); + + __ ld1(vdata3, vdata2, vdata1, vdata0, load_arrangement, + Address(__ post(ary, evf * type2aelembytes(eltype)))); + + if (load_arrangement == Assembler::T8B) { + // Extend 8B to 8H to be able to use vector multiply + // instructions + assert(load_arrangement == Assembler::T8B, "expected to extend 8B to 8H"); + if (is_signed_subword_type(eltype)) { + __ sxtl(vdata3, Assembler::T8H, vdata3, load_arrangement); + __ sxtl(vdata2, Assembler::T8H, vdata2, load_arrangement); + __ sxtl(vdata1, Assembler::T8H, vdata1, load_arrangement); + __ sxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); + } else { + __ uxtl(vdata3, Assembler::T8H, vdata3, load_arrangement); + __ uxtl(vdata2, Assembler::T8H, vdata2, load_arrangement); + __ uxtl(vdata1, Assembler::T8H, vdata1, load_arrangement); + __ uxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); + } + } + + switch (load_arrangement) { + case Assembler::T4S: + __ addv(vmul3, load_arrangement, vmul3, vdata3); + __ addv(vmul2, load_arrangement, vmul2, vdata2); + __ addv(vmul1, load_arrangement, vmul1, vdata1); + __ addv(vmul0, load_arrangement, vmul0, vdata0); + break; + case Assembler::T8B: + case Assembler::T8H: + assert(is_subword_type(eltype), "subword type expected"); + if (is_signed_subword_type(eltype)) { + __ saddwv(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T4H); + __ saddwv(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T4H); + __ saddwv(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T4H); + __ saddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); + } else { + __ uaddwv(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T4H); + __ uaddwv(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T4H); + __ uaddwv(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T4H); + __ uaddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); + } + break; + default: + __ should_not_reach_here(); + } + + // Process the upper half of a vector + if (load_arrangement == Assembler::T8B || load_arrangement == Assembler::T8H) { + __ mulvs(vmul3, Assembler::T4S, vmul3, vpowm, 1); + __ mulvs(vmul2, Assembler::T4S, vmul2, vpowm, 1); + __ mulvs(vmul1, Assembler::T4S, vmul1, vpowm, 1); + __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 1); + if (is_signed_subword_type(eltype)) { + __ saddwv2(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T8H); + __ saddwv2(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T8H); + __ saddwv2(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T8H); + __ saddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); + } else { + __ uaddwv2(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T8H); + __ uaddwv2(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T8H); + __ uaddwv2(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T8H); + __ uaddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); + } + } + + __ subsw(rscratch2, rscratch2, 1); + __ br(Assembler::HI, LARGE_LOOP); + + __ mulv(vmul3, Assembler::T4S, vmul3, vpow); + __ addv(vmul3, Assembler::T4S, vmul3); + __ umov(result, vmul3, Assembler::S, 0); + + __ mov(rscratch2, intpow(31U, vf)); + + __ mulv(vmul2, Assembler::T4S, vmul2, vpow); + __ addv(vmul2, Assembler::T4S, vmul2); + __ umov(rscratch1, vmul2, Assembler::S, 0); + __ maddw(result, result, rscratch2, rscratch1); + + __ mulv(vmul1, Assembler::T4S, vmul1, vpow); + __ addv(vmul1, Assembler::T4S, vmul1); + __ umov(rscratch1, vmul1, Assembler::S, 0); + __ maddw(result, result, rscratch2, rscratch1); + + __ mulv(vmul0, Assembler::T4S, vmul0, vpow); + __ addv(vmul0, Assembler::T4S, vmul0); + __ umov(rscratch1, vmul0, Assembler::S, 0); + __ maddw(result, result, rscratch2, rscratch1); + + __ andr(rscratch2, cnt, vf - 1); + __ cbnz(rscratch2, TAIL_SHORTCUT); + + __ leave(); + __ ret(lr); + + return entry; + } + address generate_dsin_dcos(bool isCos) { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", isCos ? "libmDcos" : "libmDsin"); @@ -8361,6 +8664,13 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::aarch64::_large_array_equals = generate_large_array_equals(); } + // arrays_hascode stub for large arrays. + StubRoutines::aarch64::_large_arrays_hashcode_boolean = generate_large_arrays_hashcode(T_BOOLEAN); + StubRoutines::aarch64::_large_arrays_hashcode_byte = generate_large_arrays_hashcode(T_BYTE); + StubRoutines::aarch64::_large_arrays_hashcode_char = generate_large_arrays_hashcode(T_CHAR); + StubRoutines::aarch64::_large_arrays_hashcode_int = generate_large_arrays_hashcode(T_INT); + StubRoutines::aarch64::_large_arrays_hashcode_short = generate_large_arrays_hashcode(T_SHORT); + // byte_array_inflate stub for large arrays. StubRoutines::aarch64::_large_byte_array_inflate = generate_large_byte_array_inflate(); diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index 80875a3b3cd..dee615df5a5 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -48,6 +48,11 @@ address StubRoutines::aarch64::_zero_blocks = nullptr; address StubRoutines::aarch64::_count_positives = nullptr; address StubRoutines::aarch64::_count_positives_long = nullptr; address StubRoutines::aarch64::_large_array_equals = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_boolean = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_byte = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_char = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_int = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_short = nullptr; address StubRoutines::aarch64::_compare_long_string_LL = nullptr; address StubRoutines::aarch64::_compare_long_string_UU = nullptr; address StubRoutines::aarch64::_compare_long_string_LU = nullptr; diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index e6438908ce4..7d3b72a8836 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -62,6 +62,11 @@ class aarch64 { static address _zero_blocks; static address _large_array_equals; + static address _large_arrays_hashcode_boolean; + static address _large_arrays_hashcode_byte; + static address _large_arrays_hashcode_char; + static address _large_arrays_hashcode_int; + static address _large_arrays_hashcode_short; static address _compare_long_string_LL; static address _compare_long_string_LU; static address _compare_long_string_UL; @@ -145,6 +150,25 @@ class aarch64 { return _large_array_equals; } + static address large_arrays_hashcode(BasicType eltype) { + switch (eltype) { + case T_BOOLEAN: + return _large_arrays_hashcode_boolean; + case T_BYTE: + return _large_arrays_hashcode_byte; + case T_CHAR: + return _large_arrays_hashcode_char; + case T_SHORT: + return _large_arrays_hashcode_short; + case T_INT: + return _large_arrays_hashcode_int; + default: + ShouldNotReachHere(); + } + + return nullptr; + } + static address compare_long_string_LL() { return _compare_long_string_LL; } diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index f18cec16488..cf16fe3a08d 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -577,6 +577,10 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) { FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true); } + + if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { + FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true); + } #endif _spin_wait = get_spin_wait_desc(); diff --git a/src/hotspot/share/utilities/intpow.hpp b/src/hotspot/share/utilities/intpow.hpp new file mode 100644 index 00000000000..0b441a55c4c --- /dev/null +++ b/src/hotspot/share/utilities/intpow.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, Arm Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_UTILITIES_INTPOW_HPP +#define SHARE_UTILITIES_INTPOW_HPP + +#include "metaprogramming/enableIf.hpp" +#include +#include + +// Raise v to the power p mod 2**N, where N is the width of the type T. +template ::value && std::is_unsigned::value)> +static constexpr T intpow(T v, unsigned p) { + if (p == 0) { + return 1; + } + + // We use exponentiation by squaring to calculate the required power. + T a = intpow(v, p / 2); + T b = (p % 2) ? v : 1; + + return a * a * b; +} + +#endif // SHARE_UTILITIES_INTPOW_HPP diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index 7e9d557d11c..64f3e787356 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -77,11 +77,29 @@ class FloatRegister(Register): def __str__(self): return self.astr("v") + def generate(self): + self.number = random.randint(0, 31) + return self + def nextReg(self): next = FloatRegister() next.number = (self.number + 1) % 32 return next +class LowFloatRegister(Register): + + def __str__(self): + return self.astr("v") + + def generate(self): + self.number = random.randint(0, 15) + return self + + def nextReg(self): + next = FloatRegister() + next.number = (self.number + 1) % 16 + return next + class GeneralRegister(Register): def __str__(self): @@ -1271,6 +1289,75 @@ def astr(self): def aname(self): return self._name +class VectorScalarNEONInstruction(Instruction): + def __init__(self, args): + self._name, self.insname, self.arrangement = args + + def generate(self): + vectorLength = {"8B" : 8, "16B" : 16, "4H" : 4, "8H" : 8, "2S" : 2, "4S" : 4, "1D" : 1, "2D" : 2} [self.arrangement] + self.elemIndex = random.randrange(0, vectorLength) + self.elemSizeSpecifier = self.arrangement[len(self.arrangement) - 1:] + self._firstSIMDreg = LowFloatRegister().generate() + self.numRegs = 3 + return self + + def cstr(self): + buf = Instruction.cstr(self) + str(self._firstSIMDreg) + buf = '%s, __ T%s' % (buf, self.arrangement) + current = self._firstSIMDreg + for cnt in range(1, self.numRegs - 1): + buf = '%s, %s' % (buf, current.nextReg()) + current = current.nextReg() + buf = '%s, %s, %d' % (buf, current.nextReg(), self.elemIndex) + return '%s);' % (buf) + + def astr(self): + buf = '%s\t%s.%s' % (self.insname, self._firstSIMDreg, self.arrangement) + current = self._firstSIMDreg + for cnt in range(1, self.numRegs - 1): + buf = '%s, %s.%s' % (buf, current.nextReg(), self.arrangement) + current = current.nextReg() + buf = '%s, %s.%s[%d]' % (buf, current.nextReg(), self.elemSizeSpecifier, self.elemIndex) + return buf + + def aname(self): + return self._name + +class WideningNEONInstruction(Instruction): + def __init__(self, args): + self._name, self.insname, self.widerArrangement, self.narrowerArrangement = args + + def generate(self): + self._firstSIMDreg = FloatRegister().generate() + return self + + def cstr(self): + buf = Instruction.cstr(self) + str(self._firstSIMDreg) + current = self._firstSIMDreg + for cnt in range(1, self.numWiderRegs): + buf = '%s, %s' % (buf, current.nextReg()) + current = current.nextReg() + buf = '%s, __ T%s' % (buf, self.widerArrangement) + for cnt in range(0, self.numNarrowerRegs): + buf = '%s, %s' % (buf, current.nextReg()) + current = current.nextReg() + buf = '%s, __ T%s' % (buf, self.narrowerArrangement) + return '%s);' % (buf) + + def astr(self): + buf = '%s\t%s.%s' % (self.insname, self._firstSIMDreg, self.widerArrangement) + current = self._firstSIMDreg + for cnt in range(1, self.numWiderRegs): + buf = '%s, %s.%s' % (buf, current.nextReg(), self.widerArrangement) + current = current.nextReg() + for cnt in range(0, self.numNarrowerRegs): + buf = '%s, %s.%s' % (buf, current.nextReg(), self.narrowerArrangement) + current = current.nextReg() + return buf + + def aname(self): + return self._name + class SHA512SIMDOp(Instruction): def generate(self): @@ -1390,6 +1477,10 @@ class TwoRegNEONOp(CommonNEONInstruction): class ThreeRegNEONOp(TwoRegNEONOp): numRegs = 3 +class AddWideNEONOp(WideningNEONInstruction): + numWiderRegs = 2 + numNarrowerRegs = 1 + class NEONFloatCompareWithZero(TwoRegNEONOp): def __init__(self, args): self._name = 'fcm' @@ -1748,6 +1839,17 @@ def generate(kind, names): ["facgt", "facgt", "2D"], ]) +generate(VectorScalarNEONInstruction, + [["fmlavs", "fmla", "2S"], ["mulvs", "mul", "4S"], + ["fmlavs", "fmla", "2D"], + ["fmlsvs", "fmls", "2S"], ["mulvs", "mul", "4S"], + ["fmlsvs", "fmls", "2D"], + ["fmulxvs", "fmulx", "2S"], ["mulvs", "mul", "4S"], + ["fmulxvs", "fmulx", "2D"], + ["mulvs", "mul", "4H"], ["mulvs", "mul", "8H"], + ["mulvs", "mul", "2S"], ["mulvs", "mul", "4S"], + ]) + neonVectorCompareInstructionPrefix = ['cm', 'fcm'] neonIntegerVectorCompareConditions = ['GT', 'GE', 'EQ', 'HI', 'HS'] neonFloatVectorCompareConditions = ['EQ', 'GT', 'GE'] @@ -2081,6 +2183,15 @@ def generate(kind, names): generate(SVEReductionOp, [["andv", 0], ["orv", 0], ["eorv", 0], ["smaxv", 0], ["sminv", 0], ["fminv", 2], ["fmaxv", 2], ["fadda", 2], ["uaddv", 0]]) +generate(AddWideNEONOp, + [["saddwv", "saddw", "8H", "8B"], ["saddwv2", "saddw2", "8H", "16B"], + ["saddwv", "saddw", "4S", "4H"], ["saddwv2", "saddw2", "4S", "8H"], + ["saddwv", "saddw", "2D", "2S"], ["saddwv2", "saddw2", "2D", "4S"], + ["uaddwv", "uaddw", "8H", "8B"], ["uaddwv2", "uaddw2", "8H", "16B"], + ["uaddwv", "uaddw", "4S", "4H"], ["uaddwv2", "uaddw2", "4S", "8H"], + ["uaddwv", "uaddw", "2D", "2S"], ["uaddwv2", "uaddw2", "2D", "4S"], + ]) + print "\n __ bind(forth);" outfile.write("forth:\n") diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index b8260aaf932..9805a05c5c1 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -293,9 +293,9 @@ __ ldrshw(r5, Address(r3, 12)); // ldrsh w5, [x3, 12] __ ldrsw(r27, Address(r24, 17)); // ldrsw x27, [x24, 17] __ ldrd(v13, Address(r29, -35)); // ldr d13, [x29, -35] - __ ldrs(v22, Address(r9, -47)); // ldr s22, [x9, -47] + __ ldrs(v23, Address(r9, -47)); // ldr s23, [x9, -47] __ strd(v11, Address(r0, 9)); // str d11, [x0, 9] - __ strs(v20, Address(r0, -127)); // str s20, [x0, -127] + __ strs(v21, Address(r0, -127)); // str s21, [x0, -127] // pre // LoadStoreOp @@ -314,7 +314,7 @@ __ ldrd(v0, Address(__ pre(r14, -54))); // ldr d0, [x14, -54]! __ ldrs(v3, Address(__ pre(r1, 40))); // ldr s3, [x1, 40]! __ strd(v4, Address(__ pre(r14, -94))); // str d4, [x14, -94]! - __ strs(v17, Address(__ pre(r28, -54))); // str s17, [x28, -54]! + __ strs(v18, Address(__ pre(r28, -54))); // str s18, [x28, -54]! // post // LoadStoreOp @@ -331,8 +331,8 @@ __ ldrshw(r3, Address(__ post(r11, -48))); // ldrsh w3, [x11], -48 __ ldrsw(r25, Address(__ post(r23, 22))); // ldrsw x25, [x23], 22 __ ldrd(v0, Address(__ post(r10, -215))); // ldr d0, [x10], -215 - __ ldrs(v17, Address(__ post(r6, 55))); // ldr s17, [x6], 55 - __ strd(v13, Address(__ post(r21, -234))); // str d13, [x21], -234 + __ ldrs(v19, Address(__ post(r6, 55))); // ldr s19, [x6], 55 + __ strd(v14, Address(__ post(r21, -234))); // str d14, [x21], -234 __ strs(v0, Address(__ post(r22, -70))); // str s0, [x22], -70 // base_plus_reg @@ -349,9 +349,9 @@ __ ldrsh(r21, Address(r30, r30, Address::sxtw(1))); // ldrsh x21, [x30, w30, sxtw #1] __ ldrshw(r11, Address(r10, r28, Address::sxtw(1))); // ldrsh w11, [x10, w28, sxtw #1] __ ldrsw(r28, Address(r19, r10, Address::uxtw(0))); // ldrsw x28, [x19, w10, uxtw #0] - __ ldrd(v29, Address(r29, r14, Address::sxtw(0))); // ldr d29, [x29, w14, sxtw #0] + __ ldrd(v30, Address(r29, r14, Address::sxtw(0))); // ldr d30, [x29, w14, sxtw #0] __ ldrs(v8, Address(r5, r5, Address::sxtw(2))); // ldr s8, [x5, w5, sxtw #2] - __ strd(v24, Address(r8, r13, Address::sxtx(0))); // str d24, [x8, x13, sxtx #0] + __ strd(v25, Address(r8, r13, Address::sxtx(0))); // str d25, [x8, x13, sxtx #0] __ strs(v17, Address(r24, r26, Address::lsl(2))); // str s17, [x24, x26, lsl #2] // base_plus_scaled_offset @@ -370,7 +370,7 @@ __ ldrsw(r10, Address(r7, 6372)); // ldrsw x10, [x7, 6372] __ ldrd(v3, Address(r25, 12392)); // ldr d3, [x25, 12392] __ ldrs(v12, Address(r9, 7840)); // ldr s12, [x9, 7840] - __ strd(v23, Address(r1, 12728)); // str d23, [x1, 12728] + __ strd(v24, Address(r1, 12728)); // str d24, [x1, 12728] __ strs(v3, Address(r20, 6924)); // str s3, [x20, 6924] // pcrel @@ -484,63 +484,63 @@ __ umsubl(r13, r10, r7, r5); // umsubl x13, w10, w7, x5 // ThreeRegFloatOp - __ fabds(v29, v15, v3); // fabd s29, s15, s3 - __ fmuls(v11, v12, v15); // fmul s11, s12, s15 - __ fdivs(v30, v30, v17); // fdiv s30, s30, s17 - __ fadds(v19, v20, v15); // fadd s19, s20, s15 - __ fsubs(v15, v9, v21); // fsub s15, s9, s21 - __ fabdd(v2, v9, v27); // fabd d2, d9, d27 - __ fmuld(v7, v29, v30); // fmul d7, d29, d30 - __ fdivd(v17, v1, v2); // fdiv d17, d1, d2 + __ fabds(v30, v15, v3); // fabd s30, s15, s3 + __ fmuls(v12, v12, v16); // fmul s12, s12, s16 + __ fdivs(v31, v31, v18); // fdiv s31, s31, s18 + __ fadds(v19, v21, v16); // fadd s19, s21, s16 + __ fsubs(v15, v10, v21); // fsub s15, s10, s21 + __ fabdd(v2, v10, v28); // fabd d2, d10, d28 + __ fmuld(v7, v30, v31); // fmul d7, d30, d31 + __ fdivd(v18, v1, v2); // fdiv d18, d1, d2 __ faddd(v6, v10, v3); // fadd d6, d10, d3 - __ fsubd(v24, v11, v7); // fsub d24, d11, d7 + __ fsubd(v25, v11, v7); // fsub d25, d11, d7 // FourRegFloatOp - __ fmadds(v1, v11, v0, v3); // fmadd s1, s11, s0, s3 - __ fmsubs(v17, v28, v6, v22); // fmsub s17, s28, s6, s22 - __ fnmadds(v6, v0, v27, v26); // fnmadd s6, s0, s27, s26 - __ fnmadds(v2, v5, v7, v28); // fnmadd s2, s5, s7, s28 - __ fmaddd(v11, v25, v13, v11); // fmadd d11, d25, d13, d11 - __ fmsubd(v23, v19, v8, v17); // fmsub d23, d19, d8, d17 - __ fnmaddd(v21, v25, v20, v19); // fnmadd d21, d25, d20, d19 - __ fnmaddd(v17, v2, v29, v22); // fnmadd d17, d2, d29, d22 + __ fmadds(v1, v12, v0, v3); // fmadd s1, s12, s0, s3 + __ fmsubs(v19, v29, v6, v23); // fmsub s19, s29, s6, s23 + __ fnmadds(v6, v0, v28, v27); // fnmadd s6, s0, s28, s27 + __ fnmadds(v2, v5, v7, v29); // fnmadd s2, s5, s7, s29 + __ fmaddd(v12, v25, v13, v12); // fmadd d12, d25, d13, d12 + __ fmsubd(v24, v19, v8, v18); // fmsub d24, d19, d8, d18 + __ fnmaddd(v22, v26, v21, v20); // fnmadd d22, d26, d21, d20 + __ fnmaddd(v19, v2, v30, v22); // fnmadd d19, d2, d30, d22 // TwoRegFloatOp - __ fmovs(v8, v21); // fmov s8, s21 - __ fabss(v19, v20); // fabs s19, s20 - __ fnegs(v11, v17); // fneg s11, s17 - __ fsqrts(v20, v6); // fsqrt s20, s6 - __ fcvts(v15, v3); // fcvt d15, s3 - __ fcvtsh(v3, v28); // fcvt h3, s28 - __ fcvths(v3, v27); // fcvt s3, h27 - __ fmovd(v14, v14); // fmov d14, d14 - __ fabsd(v10, v12); // fabs d10, d12 - __ fnegd(v11, v17); // fneg d11, d17 - __ fsqrtd(v10, v25); // fsqrt d10, d25 + __ fmovs(v8, v22); // fmov s8, s22 + __ fabss(v19, v21); // fabs s19, s21 + __ fnegs(v12, v18); // fneg s12, s18 + __ fsqrts(v21, v6); // fsqrt s21, s6 + __ fcvts(v16, v3); // fcvt d16, s3 + __ fcvtsh(v3, v29); // fcvt h3, s29 + __ fcvths(v3, v28); // fcvt s3, h28 + __ fmovd(v15, v14); // fmov d15, d14 + __ fabsd(v10, v13); // fabs d10, d13 + __ fnegd(v12, v18); // fneg d12, d18 + __ fsqrtd(v10, v26); // fsqrt d10, d26 __ fcvtd(v7, v7); // fcvt s7, d7 // FloatConvertOp - __ fcvtzsw(r14, v28); // fcvtzs w14, s28 - __ fcvtzs(r0, v22); // fcvtzs x0, s22 + __ fcvtzsw(r14, v29); // fcvtzs w14, s29 + __ fcvtzs(r0, v23); // fcvtzs x0, s23 __ fcvtzdw(r0, v12); // fcvtzs w0, d12 - __ fcvtzd(r23, v13); // fcvtzs x23, d13 + __ fcvtzd(r23, v14); // fcvtzs x23, d14 __ scvtfws(v13, r7); // scvtf s13, w7 - __ scvtfs(v14, r7); // scvtf s14, x7 - __ scvtfwd(v8, r20); // scvtf d8, w20 - __ scvtfd(v17, r28); // scvtf d17, x28 + __ scvtfs(v15, r7); // scvtf s15, x7 + __ scvtfwd(v9, r20); // scvtf d9, w20 + __ scvtfd(v19, r28); // scvtf d19, x28 __ fcvtassw(r30, v16); // fcvtas w30, s16 __ fcvtasd(r2, v9); // fcvtas x2, d9 - __ fcvtmssw(r16, v20); // fcvtms w16, s20 + __ fcvtmssw(r16, v21); // fcvtms w16, s21 __ fcvtmsd(r29, v4); // fcvtms x29, d4 - __ fmovs(r1, v26); // fmov w1, s26 - __ fmovd(r24, v23); // fmov x24, d23 + __ fmovs(r1, v27); // fmov w1, s27 + __ fmovd(r24, v24); // fmov x24, d24 __ fmovs(v14, r21); // fmov s14, w21 - __ fmovd(v12, r5); // fmov d12, x5 + __ fmovd(v13, r5); // fmov d13, x5 // TwoRegFloatOp - __ fcmps(v12, v24); // fcmp s12, s24 - __ fcmpd(v24, v29); // fcmp d24, d29 - __ fcmps(v27, 0.0); // fcmp s27, #0.0 + __ fcmps(v12, v25); // fcmp s12, s25 + __ fcmpd(v25, v30); // fcmp d25, d30 + __ fcmps(v28, 0.0); // fcmp s28, #0.0 __ fcmpd(v21, 0.0); // fcmp d21, #0.0 // LoadStorePairOp @@ -573,250 +573,265 @@ // LdStNEONOp __ ld1(v0, __ T8B, Address(r11)); // ld1 {v0.8B}, [x11] __ ld1(v16, v17, __ T16B, Address(__ post(r26, 32))); // ld1 {v16.16B, v17.16B}, [x26], 32 - __ ld1(v21, v22, v23, __ T1D, Address(__ post(r26, r17))); // ld1 {v21.1D, v22.1D, v23.1D}, [x26], x17 - __ ld1(v26, v27, v28, v29, __ T8H, Address(__ post(r29, 64))); // ld1 {v26.8H, v27.8H, v28.8H, v29.8H}, [x29], 64 - __ ld1r(v21, __ T8B, Address(r6)); // ld1r {v21.8B}, [x6] - __ ld1r(v13, __ T4S, Address(__ post(r29, 4))); // ld1r {v13.4S}, [x29], 4 - __ ld1r(v21, __ T1D, Address(__ post(r12, r16))); // ld1r {v21.1D}, [x12], x16 + __ ld1(v22, v23, v24, __ T1D, Address(__ post(r26, r17))); // ld1 {v22.1D, v23.1D, v24.1D}, [x26], x17 + __ ld1(v27, v28, v29, v30, __ T8H, Address(__ post(r29, 64))); // ld1 {v27.8H, v28.8H, v29.8H, v30.8H}, [x29], 64 + __ ld1r(v22, __ T8B, Address(r6)); // ld1r {v22.8B}, [x6] + __ ld1r(v14, __ T4S, Address(__ post(r29, 4))); // ld1r {v14.4S}, [x29], 4 + __ ld1r(v22, __ T1D, Address(__ post(r12, r16))); // ld1r {v22.1D}, [x12], x16 __ ld2(v1, v2, __ T2D, Address(r0)); // ld2 {v1.2D, v2.2D}, [x0] - __ ld2(v9, v10, __ T4H, Address(__ post(r21, 16))); // ld2 {v9.4H, v10.4H}, [x21], 16 + __ ld2(v10, v11, __ T4H, Address(__ post(r21, 16))); // ld2 {v10.4H, v11.4H}, [x21], 16 __ ld2r(v7, v8, __ T16B, Address(r25)); // ld2r {v7.16B, v8.16B}, [x25] - __ ld2r(v8, v9, __ T2S, Address(__ post(r9, 8))); // ld2r {v8.2S, v9.2S}, [x9], 8 + __ ld2r(v9, v10, __ T2S, Address(__ post(r9, 8))); // ld2r {v9.2S, v10.2S}, [x9], 8 __ ld2r(v9, v10, __ T2D, Address(__ post(r12, r14))); // ld2r {v9.2D, v10.2D}, [x12], x14 __ ld3(v7, v8, v9, __ T4S, Address(__ post(r4, r17))); // ld3 {v7.4S, v8.4S, v9.4S}, [x4], x17 __ ld3(v23, v24, v25, __ T2S, Address(r17)); // ld3 {v23.2S, v24.2S, v25.2S}, [x17] - __ ld3r(v3, v4, v5, __ T8H, Address(r22)); // ld3r {v3.8H, v4.8H, v5.8H}, [x22] - __ ld3r(v12, v13, v14, __ T4S, Address(__ post(r2, 12))); // ld3r {v12.4S, v13.4S, v14.4S}, [x2], 12 - __ ld3r(v15, v16, v17, __ T1D, Address(__ post(r10, r12))); // ld3r {v15.1D, v16.1D, v17.1D}, [x10], x12 + __ ld3r(v4, v5, v6, __ T8H, Address(r22)); // ld3r {v4.8H, v5.8H, v6.8H}, [x22] + __ ld3r(v13, v14, v15, __ T4S, Address(__ post(r2, 12))); // ld3r {v13.4S, v14.4S, v15.4S}, [x2], 12 + __ ld3r(v16, v17, v18, __ T1D, Address(__ post(r10, r12))); // ld3r {v16.1D, v17.1D, v18.1D}, [x10], x12 __ ld4(v4, v5, v6, v7, __ T8H, Address(__ post(r2, 64))); // ld4 {v4.8H, v5.8H, v6.8H, v7.8H}, [x2], 64 __ ld4(v6, v7, v8, v9, __ T8B, Address(__ post(r20, r11))); // ld4 {v6.8B, v7.8B, v8.8B, v9.8B}, [x20], x11 - __ ld4r(v11, v12, v13, v14, __ T8B, Address(r12)); // ld4r {v11.8B, v12.8B, v13.8B, v14.8B}, [x12] - __ ld4r(v15, v16, v17, v18, __ T4H, Address(__ post(r17, 8))); // ld4r {v15.4H, v16.4H, v17.4H, v18.4H}, [x17], 8 + __ ld4r(v12, v13, v14, v15, __ T8B, Address(r12)); // ld4r {v12.8B, v13.8B, v14.8B, v15.8B}, [x12] + __ ld4r(v16, v17, v18, v19, __ T4H, Address(__ post(r17, 8))); // ld4r {v16.4H, v17.4H, v18.4H, v19.4H}, [x17], 8 __ ld4r(v14, v15, v16, v17, __ T2S, Address(__ post(r25, r16))); // ld4r {v14.2S, v15.2S, v16.2S, v17.2S}, [x25], x16 // NEONReduceInstruction __ addv(v20, __ T8B, v21); // addv b20, v21.8B __ addv(v1, __ T16B, v2); // addv b1, v2.16B - __ addv(v22, __ T4H, v23); // addv h22, v23.4H + __ addv(v23, __ T4H, v24); // addv h23, v24.4H __ addv(v30, __ T8H, v31); // addv h30, v31.8H __ addv(v14, __ T4S, v15); // addv s14, v15.4S __ smaxv(v2, __ T8B, v3); // smaxv b2, v3.8B __ smaxv(v6, __ T16B, v7); // smaxv b6, v7.16B __ smaxv(v3, __ T4H, v4); // smaxv h3, v4.4H - __ smaxv(v7, __ T8H, v8); // smaxv h7, v8.8H - __ smaxv(v24, __ T4S, v25); // smaxv s24, v25.4S + __ smaxv(v8, __ T8H, v9); // smaxv h8, v9.8H + __ smaxv(v25, __ T4S, v26); // smaxv s25, v26.4S __ fmaxv(v0, __ T4S, v1); // fmaxv s0, v1.4S __ sminv(v27, __ T8B, v28); // sminv b27, v28.8B - __ uminv(v29, __ T8B, v30); // uminv b29, v30.8B + __ uminv(v30, __ T8B, v31); // uminv b30, v31.8B __ sminv(v5, __ T16B, v6); // sminv b5, v6.16B __ uminv(v5, __ T16B, v6); // uminv b5, v6.16B - __ sminv(v29, __ T4H, v30); // sminv h29, v30.4H + __ sminv(v30, __ T4H, v31); // sminv h30, v31.4H __ uminv(v11, __ T4H, v12); // uminv h11, v12.4H __ sminv(v25, __ T8H, v26); // sminv h25, v26.8H __ uminv(v0, __ T8H, v1); // uminv h0, v1.8H - __ sminv(v30, __ T4S, v31); // sminv s30, v31.4S + __ sminv(v31, __ T4S, v0); // sminv s31, v0.4S __ uminv(v0, __ T4S, v1); // uminv s0, v1.4S - __ fminv(v17, __ T4S, v18); // fminv s17, v18.4S - __ fmaxp(v28, v29, __ S); // fmaxp s28, v29.2S - __ fmaxp(v25, v26, __ D); // fmaxp d25, v26.2D + __ fminv(v19, __ T4S, v20); // fminv s19, v20.4S + __ fmaxp(v29, v30, __ S); // fmaxp s29, v30.2S + __ fmaxp(v26, v27, __ D); // fmaxp d26, v27.2D __ fminp(v9, v10, __ S); // fminp s9, v10.2S - __ fminp(v25, v26, __ D); // fminp d25, v26.2D + __ fminp(v26, v27, __ D); // fminp d26, v27.2D // NEONFloatCompareWithZero __ fcm(Assembler::GT, v12, __ T2S, v13); // fcmgt v12.2S, v13.2S, #0.0 __ fcm(Assembler::GT, v15, __ T4S, v16); // fcmgt v15.4S, v16.4S, #0.0 __ fcm(Assembler::GT, v11, __ T2D, v12); // fcmgt v11.2D, v12.2D, #0.0 - __ fcm(Assembler::GE, v10, __ T2S, v11); // fcmge v10.2S, v11.2S, #0.0 - __ fcm(Assembler::GE, v17, __ T4S, v18); // fcmge v17.4S, v18.4S, #0.0 - __ fcm(Assembler::GE, v24, __ T2D, v25); // fcmge v24.2D, v25.2D, #0.0 - __ fcm(Assembler::EQ, v21, __ T2S, v22); // fcmeq v21.2S, v22.2S, #0.0 - __ fcm(Assembler::EQ, v23, __ T4S, v24); // fcmeq v23.4S, v24.4S, #0.0 + __ fcm(Assembler::GE, v11, __ T2S, v12); // fcmge v11.2S, v12.2S, #0.0 + __ fcm(Assembler::GE, v18, __ T4S, v19); // fcmge v18.4S, v19.4S, #0.0 + __ fcm(Assembler::GE, v25, __ T2D, v26); // fcmge v25.2D, v26.2D, #0.0 + __ fcm(Assembler::EQ, v22, __ T2S, v23); // fcmeq v22.2S, v23.2S, #0.0 + __ fcm(Assembler::EQ, v24, __ T4S, v25); // fcmeq v24.4S, v25.4S, #0.0 __ fcm(Assembler::EQ, v0, __ T2D, v1); // fcmeq v0.2D, v1.2D, #0.0 - __ fcm(Assembler::LT, v16, __ T2S, v17); // fcmlt v16.2S, v17.2S, #0.0 - __ fcm(Assembler::LT, v10, __ T4S, v11); // fcmlt v10.4S, v11.4S, #0.0 + __ fcm(Assembler::LT, v17, __ T2S, v18); // fcmlt v17.2S, v18.2S, #0.0 + __ fcm(Assembler::LT, v11, __ T4S, v12); // fcmlt v11.4S, v12.4S, #0.0 __ fcm(Assembler::LT, v6, __ T2D, v7); // fcmlt v6.2D, v7.2D, #0.0 - __ fcm(Assembler::LE, v28, __ T2S, v29); // fcmle v28.2S, v29.2S, #0.0 + __ fcm(Assembler::LE, v29, __ T2S, v30); // fcmle v29.2S, v30.2S, #0.0 __ fcm(Assembler::LE, v6, __ T4S, v7); // fcmle v6.4S, v7.4S, #0.0 __ fcm(Assembler::LE, v5, __ T2D, v6); // fcmle v5.2D, v6.2D, #0.0 // TwoRegNEONOp __ absr(v5, __ T8B, v6); // abs v5.8B, v6.8B - __ absr(v20, __ T16B, v21); // abs v20.16B, v21.16B - __ absr(v17, __ T4H, v18); // abs v17.4H, v18.4H - __ absr(v15, __ T8H, v16); // abs v15.8H, v16.8H - __ absr(v17, __ T2S, v18); // abs v17.2S, v18.2S - __ absr(v29, __ T4S, v30); // abs v29.4S, v30.4S - __ absr(v26, __ T2D, v27); // abs v26.2D, v27.2D + __ absr(v21, __ T16B, v22); // abs v21.16B, v22.16B + __ absr(v19, __ T4H, v20); // abs v19.4H, v20.4H + __ absr(v16, __ T8H, v17); // abs v16.8H, v17.8H + __ absr(v18, __ T2S, v19); // abs v18.2S, v19.2S + __ absr(v30, __ T4S, v31); // abs v30.4S, v31.4S + __ absr(v27, __ T2D, v28); // abs v27.2D, v28.2D __ fabs(v28, __ T2S, v29); // fabs v28.2S, v29.2S __ fabs(v1, __ T4S, v2); // fabs v1.4S, v2.4S - __ fabs(v27, __ T2D, v28); // fabs v27.2D, v28.2D - __ fneg(v0, __ T2S, v1); // fneg v0.2S, v1.2S + __ fabs(v28, __ T2D, v29); // fabs v28.2D, v29.2D + __ fneg(v1, __ T2S, v2); // fneg v1.2S, v2.2S __ fneg(v20, __ T4S, v21); // fneg v20.4S, v21.4S - __ fneg(v28, __ T2D, v29); // fneg v28.2D, v29.2D - __ fsqrt(v15, __ T2S, v16); // fsqrt v15.2S, v16.2S - __ fsqrt(v12, __ T4S, v13); // fsqrt v12.4S, v13.4S + __ fneg(v29, __ T2D, v30); // fneg v29.2D, v30.2D + __ fsqrt(v16, __ T2S, v17); // fsqrt v16.2S, v17.2S + __ fsqrt(v13, __ T4S, v14); // fsqrt v13.4S, v14.4S __ fsqrt(v10, __ T2D, v11); // fsqrt v10.2D, v11.2D - __ notr(v28, __ T8B, v29); // not v28.8B, v29.8B - __ notr(v28, __ T16B, v29); // not v28.16B, v29.16B + __ notr(v29, __ T8B, v30); // not v29.8B, v30.8B + __ notr(v29, __ T16B, v30); // not v29.16B, v30.16B // ThreeRegNEONOp __ andr(v19, __ T8B, v20, v21); // and v19.8B, v20.8B, v21.8B __ andr(v22, __ T16B, v23, v24); // and v22.16B, v23.16B, v24.16B __ orr(v10, __ T8B, v11, v12); // orr v10.8B, v11.8B, v12.8B __ orr(v4, __ T16B, v5, v6); // orr v4.16B, v5.16B, v6.16B - __ eor(v30, __ T8B, v31, v0); // eor v30.8B, v31.8B, v0.8B - __ eor(v20, __ T16B, v21, v22); // eor v20.16B, v21.16B, v22.16B + __ eor(v31, __ T8B, v0, v1); // eor v31.8B, v0.8B, v1.8B + __ eor(v21, __ T16B, v22, v23); // eor v21.16B, v22.16B, v23.16B __ addv(v8, __ T8B, v9, v10); // add v8.8B, v9.8B, v10.8B - __ addv(v30, __ T16B, v31, v0); // add v30.16B, v31.16B, v0.16B - __ addv(v17, __ T4H, v18, v19); // add v17.4H, v18.4H, v19.4H + __ addv(v31, __ T16B, v0, v1); // add v31.16B, v0.16B, v1.16B + __ addv(v19, __ T4H, v20, v21); // add v19.4H, v20.4H, v21.4H __ addv(v10, __ T8H, v11, v12); // add v10.8H, v11.8H, v12.8H - __ addv(v27, __ T2S, v28, v29); // add v27.2S, v28.2S, v29.2S + __ addv(v28, __ T2S, v29, v30); // add v28.2S, v29.2S, v30.2S __ addv(v2, __ T4S, v3, v4); // add v2.4S, v3.4S, v4.4S - __ addv(v24, __ T2D, v25, v26); // add v24.2D, v25.2D, v26.2D - __ fadd(v4, __ T2S, v5, v6); // fadd v4.2S, v5.2S, v6.2S + __ addv(v25, __ T2D, v26, v27); // add v25.2D, v26.2D, v27.2D + __ fadd(v5, __ T2S, v6, v7); // fadd v5.2S, v6.2S, v7.2S __ fadd(v3, __ T4S, v4, v5); // fadd v3.4S, v4.4S, v5.4S __ fadd(v8, __ T2D, v9, v10); // fadd v8.2D, v9.2D, v10.2D __ subv(v22, __ T8B, v23, v24); // sub v22.8B, v23.8B, v24.8B - __ subv(v17, __ T16B, v18, v19); // sub v17.16B, v18.16B, v19.16B + __ subv(v19, __ T16B, v20, v21); // sub v19.16B, v20.16B, v21.16B __ subv(v13, __ T4H, v14, v15); // sub v13.4H, v14.4H, v15.4H - __ subv(v4, __ T8H, v5, v6); // sub v4.8H, v5.8H, v6.8H - __ subv(v28, __ T2S, v29, v30); // sub v28.2S, v29.2S, v30.2S - __ subv(v23, __ T4S, v24, v25); // sub v23.4S, v24.4S, v25.4S + __ subv(v5, __ T8H, v6, v7); // sub v5.8H, v6.8H, v7.8H + __ subv(v29, __ T2S, v30, v31); // sub v29.2S, v30.2S, v31.2S + __ subv(v24, __ T4S, v25, v26); // sub v24.4S, v25.4S, v26.4S __ subv(v21, __ T2D, v22, v23); // sub v21.2D, v22.2D, v23.2D - __ fsub(v25, __ T2S, v26, v27); // fsub v25.2S, v26.2S, v27.2S + __ fsub(v26, __ T2S, v27, v28); // fsub v26.2S, v27.2S, v28.2S __ fsub(v24, __ T4S, v25, v26); // fsub v24.4S, v25.4S, v26.4S __ fsub(v3, __ T2D, v4, v5); // fsub v3.2D, v4.2D, v5.2D - __ mulv(v23, __ T8B, v24, v25); // mul v23.8B, v24.8B, v25.8B + __ mulv(v24, __ T8B, v25, v26); // mul v24.8B, v25.8B, v26.8B __ mulv(v26, __ T16B, v27, v28); // mul v26.16B, v27.16B, v28.16B __ mulv(v23, __ T4H, v24, v25); // mul v23.4H, v24.4H, v25.4H - __ mulv(v14, __ T8H, v15, v16); // mul v14.8H, v15.8H, v16.8H + __ mulv(v15, __ T8H, v16, v17); // mul v15.8H, v16.8H, v17.8H __ mulv(v21, __ T2S, v22, v23); // mul v21.2S, v22.2S, v23.2S __ mulv(v3, __ T4S, v4, v5); // mul v3.4S, v4.4S, v5.4S - __ fabd(v23, __ T2S, v24, v25); // fabd v23.2S, v24.2S, v25.2S + __ fabd(v24, __ T2S, v25, v26); // fabd v24.2S, v25.2S, v26.2S __ fabd(v8, __ T4S, v9, v10); // fabd v8.4S, v9.4S, v10.4S - __ fabd(v24, __ T2D, v25, v26); // fabd v24.2D, v25.2D, v26.2D - __ faddp(v19, __ T2S, v20, v21); // faddp v19.2S, v20.2S, v21.2S - __ faddp(v15, __ T4S, v16, v17); // faddp v15.4S, v16.4S, v17.4S - __ faddp(v16, __ T2D, v17, v18); // faddp v16.2D, v17.2D, v18.2D + __ fabd(v25, __ T2D, v26, v27); // fabd v25.2D, v26.2D, v27.2D + __ faddp(v20, __ T2S, v21, v22); // faddp v20.2S, v21.2S, v22.2S + __ faddp(v16, __ T4S, v17, v18); // faddp v16.4S, v17.4S, v18.4S + __ faddp(v17, __ T2D, v18, v19); // faddp v17.2D, v18.2D, v19.2D __ fmul(v2, __ T2S, v3, v4); // fmul v2.2S, v3.2S, v4.2S __ fmul(v1, __ T4S, v2, v3); // fmul v1.4S, v2.4S, v3.4S __ fmul(v0, __ T2D, v1, v2); // fmul v0.2D, v1.2D, v2.2D __ mlav(v24, __ T4H, v25, v26); // mla v24.4H, v25.4H, v26.4H __ mlav(v4, __ T8H, v5, v6); // mla v4.8H, v5.8H, v6.8H __ mlav(v3, __ T2S, v4, v5); // mla v3.2S, v4.2S, v5.2S - __ mlav(v11, __ T4S, v12, v13); // mla v11.4S, v12.4S, v13.4S - __ fmla(v30, __ T2S, v31, v0); // fmla v30.2S, v31.2S, v0.2S - __ fmla(v27, __ T4S, v28, v29); // fmla v27.4S, v28.4S, v29.4S - __ fmla(v9, __ T2D, v10, v11); // fmla v9.2D, v10.2D, v11.2D - __ mlsv(v25, __ T4H, v26, v27); // mls v25.4H, v26.4H, v27.4H + __ mlav(v12, __ T4S, v13, v14); // mla v12.4S, v13.4S, v14.4S + __ fmla(v31, __ T2S, v0, v1); // fmla v31.2S, v0.2S, v1.2S + __ fmla(v28, __ T4S, v29, v30); // fmla v28.4S, v29.4S, v30.4S + __ fmla(v10, __ T2D, v11, v12); // fmla v10.2D, v11.2D, v12.2D + __ mlsv(v26, __ T4H, v27, v28); // mls v26.4H, v27.4H, v28.4H __ mlsv(v2, __ T8H, v3, v4); // mls v2.8H, v3.8H, v4.8H __ mlsv(v12, __ T2S, v13, v14); // mls v12.2S, v13.2S, v14.2S - __ mlsv(v17, __ T4S, v18, v19); // mls v17.4S, v18.4S, v19.4S - __ fmls(v30, __ T2S, v31, v0); // fmls v30.2S, v31.2S, v0.2S + __ mlsv(v18, __ T4S, v19, v20); // mls v18.4S, v19.4S, v20.4S + __ fmls(v31, __ T2S, v0, v1); // fmls v31.2S, v0.2S, v1.2S __ fmls(v1, __ T4S, v2, v3); // fmls v1.4S, v2.4S, v3.4S - __ fmls(v12, __ T2D, v13, v14); // fmls v12.2D, v13.2D, v14.2D - __ fdiv(v28, __ T2S, v29, v30); // fdiv v28.2S, v29.2S, v30.2S + __ fmls(v13, __ T2D, v14, v15); // fmls v13.2D, v14.2D, v15.2D + __ fdiv(v29, __ T2S, v30, v31); // fdiv v29.2S, v30.2S, v31.2S __ fdiv(v0, __ T4S, v1, v2); // fdiv v0.4S, v1.4S, v2.4S - __ fdiv(v17, __ T2D, v18, v19); // fdiv v17.2D, v18.2D, v19.2D + __ fdiv(v19, __ T2D, v20, v21); // fdiv v19.2D, v20.2D, v21.2D __ maxv(v12, __ T8B, v13, v14); // smax v12.8B, v13.8B, v14.8B __ maxv(v17, __ T16B, v18, v19); // smax v17.16B, v18.16B, v19.16B - __ maxv(v21, __ T4H, v22, v23); // smax v21.4H, v22.4H, v23.4H - __ maxv(v12, __ T8H, v13, v14); // smax v12.8H, v13.8H, v14.8H - __ maxv(v27, __ T2S, v28, v29); // smax v27.2S, v28.2S, v29.2S - __ maxv(v29, __ T4S, v30, v31); // smax v29.4S, v30.4S, v31.4S - __ smaxp(v30, __ T8B, v31, v0); // smaxp v30.8B, v31.8B, v0.8B + __ maxv(v22, __ T4H, v23, v24); // smax v22.4H, v23.4H, v24.4H + __ maxv(v13, __ T8H, v14, v15); // smax v13.8H, v14.8H, v15.8H + __ maxv(v28, __ T2S, v29, v30); // smax v28.2S, v29.2S, v30.2S + __ maxv(v30, __ T4S, v31, v0); // smax v30.4S, v31.4S, v0.4S + __ smaxp(v31, __ T8B, v0, v1); // smaxp v31.8B, v0.8B, v1.8B __ smaxp(v1, __ T16B, v2, v3); // smaxp v1.16B, v2.16B, v3.16B - __ smaxp(v25, __ T4H, v26, v27); // smaxp v25.4H, v26.4H, v27.4H - __ smaxp(v27, __ T8H, v28, v29); // smaxp v27.8H, v28.8H, v29.8H + __ smaxp(v26, __ T4H, v27, v28); // smaxp v26.4H, v27.4H, v28.4H + __ smaxp(v28, __ T8H, v29, v30); // smaxp v28.8H, v29.8H, v30.8H __ smaxp(v4, __ T2S, v5, v6); // smaxp v4.2S, v5.2S, v6.2S - __ smaxp(v29, __ T4S, v30, v31); // smaxp v29.4S, v30.4S, v31.4S - __ fmax(v3, __ T2S, v4, v5); // fmax v3.2S, v4.2S, v5.2S + __ smaxp(v30, __ T4S, v31, v0); // smaxp v30.4S, v31.4S, v0.4S + __ fmax(v4, __ T2S, v5, v6); // fmax v4.2S, v5.2S, v6.2S __ fmax(v6, __ T4S, v7, v8); // fmax v6.4S, v7.4S, v8.4S - __ fmax(v29, __ T2D, v30, v31); // fmax v29.2D, v30.2D, v31.2D - __ minv(v25, __ T8B, v26, v27); // smin v25.8B, v26.8B, v27.8B - __ minv(v17, __ T16B, v18, v19); // smin v17.16B, v18.16B, v19.16B - __ minv(v8, __ T4H, v9, v10); // smin v8.4H, v9.4H, v10.4H - __ minv(v7, __ T8H, v8, v9); // smin v7.8H, v8.8H, v9.8H + __ fmax(v30, __ T2D, v31, v0); // fmax v30.2D, v31.2D, v0.2D + __ minv(v26, __ T8B, v27, v28); // smin v26.8B, v27.8B, v28.8B + __ minv(v18, __ T16B, v19, v20); // smin v18.16B, v19.16B, v20.16B + __ minv(v9, __ T4H, v10, v11); // smin v9.4H, v10.4H, v11.4H + __ minv(v8, __ T8H, v9, v10); // smin v8.8H, v9.8H, v10.8H __ minv(v12, __ T2S, v13, v14); // smin v12.2S, v13.2S, v14.2S __ minv(v0, __ T4S, v1, v2); // smin v0.4S, v1.4S, v2.4S - __ sminp(v19, __ T8B, v20, v21); // sminp v19.8B, v20.8B, v21.8B + __ sminp(v20, __ T8B, v21, v22); // sminp v20.8B, v21.8B, v22.8B __ sminp(v1, __ T16B, v2, v3); // sminp v1.16B, v2.16B, v3.16B - __ sminp(v23, __ T4H, v24, v25); // sminp v23.4H, v24.4H, v25.4H + __ sminp(v24, __ T4H, v25, v26); // sminp v24.4H, v25.4H, v26.4H __ sminp(v2, __ T8H, v3, v4); // sminp v2.8H, v3.8H, v4.8H __ sminp(v0, __ T2S, v1, v2); // sminp v0.2S, v1.2S, v2.2S - __ sminp(v8, __ T4S, v9, v10); // sminp v8.4S, v9.4S, v10.4S - __ fmin(v23, __ T2S, v24, v25); // fmin v23.2S, v24.2S, v25.2S - __ fmin(v25, __ T4S, v26, v27); // fmin v25.4S, v26.4S, v27.4S - __ fmin(v15, __ T2D, v16, v17); // fmin v15.2D, v16.2D, v17.2D - __ facgt(v29, __ T2S, v30, v31); // facgt v29.2S, v30.2S, v31.2S + __ sminp(v9, __ T4S, v10, v11); // sminp v9.4S, v10.4S, v11.4S + __ fmin(v24, __ T2S, v25, v26); // fmin v24.2S, v25.2S, v26.2S + __ fmin(v26, __ T4S, v27, v28); // fmin v26.4S, v27.4S, v28.4S + __ fmin(v16, __ T2D, v17, v18); // fmin v16.2D, v17.2D, v18.2D + __ facgt(v30, __ T2S, v31, v0); // facgt v30.2S, v31.2S, v0.2S __ facgt(v3, __ T4S, v4, v5); // facgt v3.4S, v4.4S, v5.4S __ facgt(v10, __ T2D, v11, v12); // facgt v10.2D, v11.2D, v12.2D +// VectorScalarNEONInstruction + __ fmlavs(v5, __ T2S, v6, v7, 1); // fmla v5.2S, v6.2S, v7.S[1] + __ mulvs(v9, __ T4S, v10, v11, 0); // mul v9.4S, v10.4S, v11.S[0] + __ fmlavs(v5, __ T2D, v6, v7, 0); // fmla v5.2D, v6.2D, v7.D[0] + __ fmlsvs(v5, __ T2S, v6, v7, 0); // fmls v5.2S, v6.2S, v7.S[0] + __ mulvs(v8, __ T4S, v9, v10, 1); // mul v8.4S, v9.4S, v10.S[1] + __ fmlsvs(v5, __ T2D, v6, v7, 0); // fmls v5.2D, v6.2D, v7.D[0] + __ fmulxvs(v6, __ T2S, v7, v8, 0); // fmulx v6.2S, v7.2S, v8.S[0] + __ mulvs(v6, __ T4S, v7, v8, 1); // mul v6.4S, v7.4S, v8.S[1] + __ fmulxvs(v3, __ T2D, v4, v5, 0); // fmulx v3.2D, v4.2D, v5.D[0] + __ mulvs(v13, __ T4H, v14, v15, 2); // mul v13.4H, v14.4H, v15.H[2] + __ mulvs(v2, __ T8H, v3, v4, 4); // mul v2.8H, v3.8H, v4.H[4] + __ mulvs(v2, __ T2S, v3, v4, 0); // mul v2.2S, v3.2S, v4.S[0] + __ mulvs(v9, __ T4S, v10, v11, 1); // mul v9.4S, v10.4S, v11.S[1] + // NEONVectorCompare - __ cm(Assembler::GT, v22, __ T8B, v23, v24); // cmgt v22.8B, v23.8B, v24.8B - __ cm(Assembler::GT, v10, __ T16B, v11, v12); // cmgt v10.16B, v11.16B, v12.16B - __ cm(Assembler::GT, v4, __ T4H, v5, v6); // cmgt v4.4H, v5.4H, v6.4H - __ cm(Assembler::GT, v17, __ T8H, v18, v19); // cmgt v17.8H, v18.8H, v19.8H - __ cm(Assembler::GT, v1, __ T2S, v2, v3); // cmgt v1.2S, v2.2S, v3.2S - __ cm(Assembler::GT, v11, __ T4S, v12, v13); // cmgt v11.4S, v12.4S, v13.4S - __ cm(Assembler::GT, v7, __ T2D, v8, v9); // cmgt v7.2D, v8.2D, v9.2D - __ cm(Assembler::GE, v10, __ T8B, v11, v12); // cmge v10.8B, v11.8B, v12.8B - __ cm(Assembler::GE, v15, __ T16B, v16, v17); // cmge v15.16B, v16.16B, v17.16B - __ cm(Assembler::GE, v16, __ T4H, v17, v18); // cmge v16.4H, v17.4H, v18.4H - __ cm(Assembler::GE, v2, __ T8H, v3, v4); // cmge v2.8H, v3.8H, v4.8H - __ cm(Assembler::GE, v9, __ T2S, v10, v11); // cmge v9.2S, v10.2S, v11.2S - __ cm(Assembler::GE, v11, __ T4S, v12, v13); // cmge v11.4S, v12.4S, v13.4S - __ cm(Assembler::GE, v12, __ T2D, v13, v14); // cmge v12.2D, v13.2D, v14.2D - __ cm(Assembler::EQ, v14, __ T8B, v15, v16); // cmeq v14.8B, v15.8B, v16.8B - __ cm(Assembler::EQ, v13, __ T16B, v14, v15); // cmeq v13.16B, v14.16B, v15.16B - __ cm(Assembler::EQ, v2, __ T4H, v3, v4); // cmeq v2.4H, v3.4H, v4.4H - __ cm(Assembler::EQ, v6, __ T8H, v7, v8); // cmeq v6.8H, v7.8H, v8.8H - __ cm(Assembler::EQ, v19, __ T2S, v20, v21); // cmeq v19.2S, v20.2S, v21.2S - __ cm(Assembler::EQ, v25, __ T4S, v26, v27); // cmeq v25.4S, v26.4S, v27.4S - __ cm(Assembler::EQ, v15, __ T2D, v16, v17); // cmeq v15.2D, v16.2D, v17.2D - __ cm(Assembler::HI, v4, __ T8B, v5, v6); // cmhi v4.8B, v5.8B, v6.8B - __ cm(Assembler::HI, v2, __ T16B, v3, v4); // cmhi v2.16B, v3.16B, v4.16B - __ cm(Assembler::HI, v4, __ T4H, v5, v6); // cmhi v4.4H, v5.4H, v6.4H - __ cm(Assembler::HI, v11, __ T8H, v12, v13); // cmhi v11.8H, v12.8H, v13.8H - __ cm(Assembler::HI, v17, __ T2S, v18, v19); // cmhi v17.2S, v18.2S, v19.2S - __ cm(Assembler::HI, v20, __ T4S, v21, v22); // cmhi v20.4S, v21.4S, v22.4S - __ cm(Assembler::HI, v16, __ T2D, v17, v18); // cmhi v16.2D, v17.2D, v18.2D - __ cm(Assembler::HS, v17, __ T8B, v18, v19); // cmhs v17.8B, v18.8B, v19.8B - __ cm(Assembler::HS, v10, __ T16B, v11, v12); // cmhs v10.16B, v11.16B, v12.16B - __ cm(Assembler::HS, v20, __ T4H, v21, v22); // cmhs v20.4H, v21.4H, v22.4H - __ cm(Assembler::HS, v22, __ T8H, v23, v24); // cmhs v22.8H, v23.8H, v24.8H - __ cm(Assembler::HS, v12, __ T2S, v13, v14); // cmhs v12.2S, v13.2S, v14.2S - __ cm(Assembler::HS, v25, __ T4S, v26, v27); // cmhs v25.4S, v26.4S, v27.4S - __ cm(Assembler::HS, v23, __ T2D, v24, v25); // cmhs v23.2D, v24.2D, v25.2D - __ fcm(Assembler::EQ, v28, __ T2S, v29, v30); // fcmeq v28.2S, v29.2S, v30.2S - __ fcm(Assembler::EQ, v14, __ T4S, v15, v16); // fcmeq v14.4S, v15.4S, v16.4S - __ fcm(Assembler::EQ, v10, __ T2D, v11, v12); // fcmeq v10.2D, v11.2D, v12.2D - __ fcm(Assembler::GT, v24, __ T2S, v25, v26); // fcmgt v24.2S, v25.2S, v26.2S - __ fcm(Assembler::GT, v1, __ T4S, v2, v3); // fcmgt v1.4S, v2.4S, v3.4S - __ fcm(Assembler::GT, v11, __ T2D, v12, v13); // fcmgt v11.2D, v12.2D, v13.2D - __ fcm(Assembler::GE, v30, __ T2S, v31, v0); // fcmge v30.2S, v31.2S, v0.2S - __ fcm(Assembler::GE, v10, __ T4S, v11, v12); // fcmge v10.4S, v11.4S, v12.4S - __ fcm(Assembler::GE, v15, __ T2D, v16, v17); // fcmge v15.2D, v16.2D, v17.2D + __ cm(Assembler::GT, v21, __ T8B, v22, v23); // cmgt v21.8B, v22.8B, v23.8B + __ cm(Assembler::GT, v16, __ T16B, v17, v18); // cmgt v16.16B, v17.16B, v18.16B + __ cm(Assembler::GT, v18, __ T4H, v19, v20); // cmgt v18.4H, v19.4H, v20.4H + __ cm(Assembler::GT, v11, __ T8H, v12, v13); // cmgt v11.8H, v12.8H, v13.8H + __ cm(Assembler::GT, v21, __ T2S, v22, v23); // cmgt v21.2S, v22.2S, v23.2S + __ cm(Assembler::GT, v23, __ T4S, v24, v25); // cmgt v23.4S, v24.4S, v25.4S + __ cm(Assembler::GT, v12, __ T2D, v13, v14); // cmgt v12.2D, v13.2D, v14.2D + __ cm(Assembler::GE, v26, __ T8B, v27, v28); // cmge v26.8B, v27.8B, v28.8B + __ cm(Assembler::GE, v23, __ T16B, v24, v25); // cmge v23.16B, v24.16B, v25.16B + __ cm(Assembler::GE, v28, __ T4H, v29, v30); // cmge v28.4H, v29.4H, v30.4H + __ cm(Assembler::GE, v14, __ T8H, v15, v16); // cmge v14.8H, v15.8H, v16.8H + __ cm(Assembler::GE, v11, __ T2S, v12, v13); // cmge v11.2S, v12.2S, v13.2S + __ cm(Assembler::GE, v24, __ T4S, v25, v26); // cmge v24.4S, v25.4S, v26.4S + __ cm(Assembler::GE, v1, __ T2D, v2, v3); // cmge v1.2D, v2.2D, v3.2D + __ cm(Assembler::EQ, v12, __ T8B, v13, v14); // cmeq v12.8B, v13.8B, v14.8B + __ cm(Assembler::EQ, v31, __ T16B, v0, v1); // cmeq v31.16B, v0.16B, v1.16B + __ cm(Assembler::EQ, v10, __ T4H, v11, v12); // cmeq v10.4H, v11.4H, v12.4H + __ cm(Assembler::EQ, v16, __ T8H, v17, v18); // cmeq v16.8H, v17.8H, v18.8H + __ cm(Assembler::EQ, v7, __ T2S, v8, v9); // cmeq v7.2S, v8.2S, v9.2S + __ cm(Assembler::EQ, v2, __ T4S, v3, v4); // cmeq v2.4S, v3.4S, v4.4S + __ cm(Assembler::EQ, v3, __ T2D, v4, v5); // cmeq v3.2D, v4.2D, v5.2D + __ cm(Assembler::HI, v13, __ T8B, v14, v15); // cmhi v13.8B, v14.8B, v15.8B + __ cm(Assembler::HI, v19, __ T16B, v20, v21); // cmhi v19.16B, v20.16B, v21.16B + __ cm(Assembler::HI, v17, __ T4H, v18, v19); // cmhi v17.4H, v18.4H, v19.4H + __ cm(Assembler::HI, v16, __ T8H, v17, v18); // cmhi v16.8H, v17.8H, v18.8H + __ cm(Assembler::HI, v3, __ T2S, v4, v5); // cmhi v3.2S, v4.2S, v5.2S + __ cm(Assembler::HI, v1, __ T4S, v2, v3); // cmhi v1.4S, v2.4S, v3.4S + __ cm(Assembler::HI, v11, __ T2D, v12, v13); // cmhi v11.2D, v12.2D, v13.2D + __ cm(Assembler::HS, v30, __ T8B, v31, v0); // cmhs v30.8B, v31.8B, v0.8B + __ cm(Assembler::HS, v5, __ T16B, v6, v7); // cmhs v5.16B, v6.16B, v7.16B + __ cm(Assembler::HS, v8, __ T4H, v9, v10); // cmhs v8.4H, v9.4H, v10.4H + __ cm(Assembler::HS, v15, __ T8H, v16, v17); // cmhs v15.8H, v16.8H, v17.8H + __ cm(Assembler::HS, v29, __ T2S, v30, v31); // cmhs v29.2S, v30.2S, v31.2S + __ cm(Assembler::HS, v30, __ T4S, v31, v0); // cmhs v30.4S, v31.4S, v0.4S + __ cm(Assembler::HS, v0, __ T2D, v1, v2); // cmhs v0.2D, v1.2D, v2.2D + __ fcm(Assembler::EQ, v20, __ T2S, v21, v22); // fcmeq v20.2S, v21.2S, v22.2S + __ fcm(Assembler::EQ, v7, __ T4S, v8, v9); // fcmeq v7.4S, v8.4S, v9.4S + __ fcm(Assembler::EQ, v20, __ T2D, v21, v22); // fcmeq v20.2D, v21.2D, v22.2D + __ fcm(Assembler::GT, v23, __ T2S, v24, v25); // fcmgt v23.2S, v24.2S, v25.2S + __ fcm(Assembler::GT, v28, __ T4S, v29, v30); // fcmgt v28.4S, v29.4S, v30.4S + __ fcm(Assembler::GT, v21, __ T2D, v22, v23); // fcmgt v21.2D, v22.2D, v23.2D + __ fcm(Assembler::GE, v27, __ T2S, v28, v29); // fcmge v27.2S, v28.2S, v29.2S + __ fcm(Assembler::GE, v25, __ T4S, v26, v27); // fcmge v25.4S, v26.4S, v27.4S + __ fcm(Assembler::GE, v5, __ T2D, v6, v7); // fcmge v5.2D, v6.2D, v7.2D // SVEComparisonWithZero - __ sve_fcm(Assembler::EQ, p3, __ S, p3, z2, 0.0); // fcmeq p3.s, p3/z, z2.s, #0.0 - __ sve_fcm(Assembler::GT, p9, __ D, p0, z16, 0.0); // fcmgt p9.d, p0/z, z16.d, #0.0 - __ sve_fcm(Assembler::GE, p0, __ D, p1, z11, 0.0); // fcmge p0.d, p1/z, z11.d, #0.0 - __ sve_fcm(Assembler::LT, p4, __ D, p7, z14, 0.0); // fcmlt p4.d, p7/z, z14.d, #0.0 - __ sve_fcm(Assembler::LE, p0, __ S, p5, z20, 0.0); // fcmle p0.s, p5/z, z20.s, #0.0 - __ sve_fcm(Assembler::NE, p11, __ D, p6, z27, 0.0); // fcmne p11.d, p6/z, z27.d, #0.0 + __ sve_fcm(Assembler::EQ, p0, __ D, p7, z23, 0.0); // fcmeq p0.d, p7/z, z23.d, #0.0 + __ sve_fcm(Assembler::GT, p2, __ S, p7, z12, 0.0); // fcmgt p2.s, p7/z, z12.s, #0.0 + __ sve_fcm(Assembler::GE, p7, __ D, p7, z29, 0.0); // fcmge p7.d, p7/z, z29.d, #0.0 + __ sve_fcm(Assembler::LT, p9, __ S, p3, z31, 0.0); // fcmlt p9.s, p3/z, z31.s, #0.0 + __ sve_fcm(Assembler::LE, p9, __ D, p6, z31, 0.0); // fcmle p9.d, p6/z, z31.d, #0.0 + __ sve_fcm(Assembler::NE, p10, __ S, p2, z16, 0.0); // fcmne p10.s, p2/z, z16.s, #0.0 // SVEComparisonWithImm - __ sve_cmp(Assembler::EQ, p12, __ B, p5, z4, 0); // cmpeq p12.b, p5/z, z4.b, #0 - __ sve_cmp(Assembler::GT, p15, __ H, p2, z5, 12); // cmpgt p15.h, p2/z, z5.h, #12 - __ sve_cmp(Assembler::GE, p7, __ S, p7, z28, 3); // cmpge p7.s, p7/z, z28.s, #3 - __ sve_cmp(Assembler::LT, p15, __ H, p4, z5, 15); // cmplt p15.h, p4/z, z5.h, #15 - __ sve_cmp(Assembler::LE, p9, __ S, p4, z26, -4); // cmple p9.s, p4/z, z26.s, #-4 - __ sve_cmp(Assembler::NE, p5, __ B, p7, z9, 1); // cmpne p5.b, p7/z, z9.b, #1 - __ sve_cmp(Assembler::HS, p13, __ D, p1, z27, 43); // cmphs p13.d, p1/z, z27.d, #43 - __ sve_cmp(Assembler::HI, p10, __ B, p6, z9, 70); // cmphi p10.b, p6/z, z9.b, #70 - __ sve_cmp(Assembler::LS, p8, __ B, p7, z22, 61); // cmpls p8.b, p7/z, z22.b, #61 - __ sve_cmp(Assembler::LO, p11, __ S, p5, z17, 11); // cmplo p11.s, p5/z, z17.s, #11 + __ sve_cmp(Assembler::EQ, p4, __ D, p4, z6, 11); // cmpeq p4.d, p4/z, z6.d, #11 + __ sve_cmp(Assembler::GT, p14, __ B, p2, z30, 4); // cmpgt p14.b, p2/z, z30.b, #4 + __ sve_cmp(Assembler::GE, p5, __ D, p4, z4, 1); // cmpge p5.d, p4/z, z4.d, #1 + __ sve_cmp(Assembler::LT, p11, __ D, p3, z3, 6); // cmplt p11.d, p3/z, z3.d, #6 + __ sve_cmp(Assembler::LE, p9, __ S, p0, z19, -1); // cmple p9.s, p0/z, z19.s, #-1 + __ sve_cmp(Assembler::NE, p3, __ S, p2, z12, -3); // cmpne p3.s, p2/z, z12.s, #-3 + __ sve_cmp(Assembler::HS, p11, __ D, p4, z1, 20); // cmphs p11.d, p4/z, z1.d, #20 + __ sve_cmp(Assembler::HI, p8, __ S, p5, z2, 53); // cmphi p8.s, p5/z, z2.s, #53 + __ sve_cmp(Assembler::LS, p5, __ D, p6, z21, 49); // cmpls p5.d, p6/z, z21.d, #49 + __ sve_cmp(Assembler::LO, p13, __ B, p7, z3, 97); // cmplo p13.b, p7/z, z3.b, #97 // SpecialCases __ ccmn(zr, zr, 3u, Assembler::LE); // ccmn xzr, xzr, #3, LE @@ -1071,215 +1086,229 @@ __ fmovd(v0, -1.0625); // fmov d0, #-1.0625 // LSEOp - __ swp(Assembler::xword, r15, r6, r12); // swp x15, x6, [x12] - __ ldadd(Assembler::xword, r16, r11, r13); // ldadd x16, x11, [x13] - __ ldbic(Assembler::xword, r23, r1, r30); // ldclr x23, x1, [x30] - __ ldeor(Assembler::xword, r19, r5, r17); // ldeor x19, x5, [x17] - __ ldorr(Assembler::xword, r2, r16, r22); // ldset x2, x16, [x22] - __ ldsmin(Assembler::xword, r13, r10, r21); // ldsmin x13, x10, [x21] - __ ldsmax(Assembler::xword, r29, r27, r12); // ldsmax x29, x27, [x12] - __ ldumin(Assembler::xword, r27, r3, r1); // ldumin x27, x3, [x1] - __ ldumax(Assembler::xword, zr, r24, r19); // ldumax xzr, x24, [x19] + __ swp(Assembler::xword, r19, r17, r9); // swp x19, x17, [x9] + __ ldadd(Assembler::xword, r28, r27, r15); // ldadd x28, x27, [x15] + __ ldbic(Assembler::xword, r7, r21, r23); // ldclr x7, x21, [x23] + __ ldeor(Assembler::xword, zr, r25, r2); // ldeor xzr, x25, [x2] + __ ldorr(Assembler::xword, zr, r27, r15); // ldset xzr, x27, [x15] + __ ldsmin(Assembler::xword, r10, r23, r19); // ldsmin x10, x23, [x19] + __ ldsmax(Assembler::xword, r3, r16, r0); // ldsmax x3, x16, [x0] + __ ldumin(Assembler::xword, r25, r26, r23); // ldumin x25, x26, [x23] + __ ldumax(Assembler::xword, r2, r16, r12); // ldumax x2, x16, [x12] // LSEOp - __ swpa(Assembler::xword, r17, r9, r28); // swpa x17, x9, [x28] - __ ldadda(Assembler::xword, r27, r15, r7); // ldadda x27, x15, [x7] - __ ldbica(Assembler::xword, r21, r23, sp); // ldclra x21, x23, [sp] - __ ldeora(Assembler::xword, r25, r2, sp); // ldeora x25, x2, [sp] - __ ldorra(Assembler::xword, r27, r16, r10); // ldseta x27, x16, [x10] - __ ldsmina(Assembler::xword, r23, r19, r3); // ldsmina x23, x19, [x3] - __ ldsmaxa(Assembler::xword, r16, r0, r25); // ldsmaxa x16, x0, [x25] - __ ldumina(Assembler::xword, r26, r23, r2); // ldumina x26, x23, [x2] - __ ldumaxa(Assembler::xword, r16, r12, r4); // ldumaxa x16, x12, [x4] + __ swpa(Assembler::xword, r4, r28, r30); // swpa x4, x28, [x30] + __ ldadda(Assembler::xword, r29, r16, r27); // ldadda x29, x16, [x27] + __ ldbica(Assembler::xword, r6, r9, r29); // ldclra x6, x9, [x29] + __ ldeora(Assembler::xword, r16, r7, r4); // ldeora x16, x7, [x4] + __ ldorra(Assembler::xword, r7, r15, r9); // ldseta x7, x15, [x9] + __ ldsmina(Assembler::xword, r23, r8, r2); // ldsmina x23, x8, [x2] + __ ldsmaxa(Assembler::xword, r28, r21, sp); // ldsmaxa x28, x21, [sp] + __ ldumina(Assembler::xword, r5, r27, r0); // ldumina x5, x27, [x0] + __ ldumaxa(Assembler::xword, r17, r15, r4); // ldumaxa x17, x15, [x4] // LSEOp - __ swpal(Assembler::xword, r28, r30, r29); // swpal x28, x30, [x29] - __ ldaddal(Assembler::xword, r16, r27, r6); // ldaddal x16, x27, [x6] - __ ldbical(Assembler::xword, r9, r29, r15); // ldclral x9, x29, [x15] - __ ldeoral(Assembler::xword, r7, r4, r7); // ldeoral x7, x4, [x7] - __ ldorral(Assembler::xword, r15, r9, r23); // ldsetal x15, x9, [x23] - __ ldsminal(Assembler::xword, r8, r2, r28); // ldsminal x8, x2, [x28] - __ ldsmaxal(Assembler::xword, r21, zr, r5); // ldsmaxal x21, xzr, [x5] - __ lduminal(Assembler::xword, r27, r0, r17); // lduminal x27, x0, [x17] - __ ldumaxal(Assembler::xword, r15, r4, r26); // ldumaxal x15, x4, [x26] + __ swpal(Assembler::xword, r26, r8, r28); // swpal x26, x8, [x28] + __ ldaddal(Assembler::xword, r22, r27, r27); // ldaddal x22, x27, [x27] + __ ldbical(Assembler::xword, r25, r23, r0); // ldclral x25, x23, [x0] + __ ldeoral(Assembler::xword, r4, r6, r15); // ldeoral x4, x6, [x15] + __ ldorral(Assembler::xword, r0, r4, r15); // ldsetal x0, x4, [x15] + __ ldsminal(Assembler::xword, r1, r10, r7); // ldsminal x1, x10, [x7] + __ ldsmaxal(Assembler::xword, r5, r10, r28); // ldsmaxal x5, x10, [x28] + __ lduminal(Assembler::xword, r7, r20, r23); // lduminal x7, x20, [x23] + __ ldumaxal(Assembler::xword, r21, r6, r11); // ldumaxal x21, x6, [x11] // LSEOp - __ swpl(Assembler::xword, r8, r28, r22); // swpl x8, x28, [x22] - __ ldaddl(Assembler::xword, r27, r27, r25); // ldaddl x27, x27, [x25] - __ ldbicl(Assembler::xword, r23, r0, r4); // ldclrl x23, x0, [x4] - __ ldeorl(Assembler::xword, r6, r16, r0); // ldeorl x6, x16, [x0] - __ ldorrl(Assembler::xword, r4, r15, r1); // ldsetl x4, x15, [x1] - __ ldsminl(Assembler::xword, r10, r7, r5); // ldsminl x10, x7, [x5] - __ ldsmaxl(Assembler::xword, r10, r28, r7); // ldsmaxl x10, x28, [x7] - __ lduminl(Assembler::xword, r20, r23, r21); // lduminl x20, x23, [x21] - __ ldumaxl(Assembler::xword, r6, r11, r8); // ldumaxl x6, x11, [x8] + __ swpl(Assembler::xword, r8, r17, sp); // swpl x8, x17, [sp] + __ ldaddl(Assembler::xword, r6, r17, r2); // ldaddl x6, x17, [x2] + __ ldbicl(Assembler::xword, r12, r30, r29); // ldclrl x12, x30, [x29] + __ ldeorl(Assembler::xword, r3, r27, r22); // ldeorl x3, x27, [x22] + __ ldorrl(Assembler::xword, r29, r14, r13); // ldsetl x29, x14, [x13] + __ ldsminl(Assembler::xword, r28, r17, r24); // ldsminl x28, x17, [x24] + __ ldsmaxl(Assembler::xword, r5, r2, r14); // ldsmaxl x5, x2, [x14] + __ lduminl(Assembler::xword, r10, r16, r11); // lduminl x10, x16, [x11] + __ ldumaxl(Assembler::xword, r27, r23, r12); // ldumaxl x27, x23, [x12] // LSEOp - __ swp(Assembler::word, r17, zr, r6); // swp w17, wzr, [x6] - __ ldadd(Assembler::word, r17, r2, r12); // ldadd w17, w2, [x12] - __ ldbic(Assembler::word, r30, r29, r3); // ldclr w30, w29, [x3] - __ ldeor(Assembler::word, r27, r22, r29); // ldeor w27, w22, [x29] - __ ldorr(Assembler::word, r14, r13, r28); // ldset w14, w13, [x28] - __ ldsmin(Assembler::word, r17, r24, r5); // ldsmin w17, w24, [x5] - __ ldsmax(Assembler::word, r2, r14, r10); // ldsmax w2, w14, [x10] - __ ldumin(Assembler::word, r16, r11, r27); // ldumin w16, w11, [x27] - __ ldumax(Assembler::word, r23, r12, r4); // ldumax w23, w12, [x4] + __ swp(Assembler::word, r4, r22, r17); // swp w4, w22, [x17] + __ ldadd(Assembler::word, r4, r1, r19); // ldadd w4, w1, [x19] + __ ldbic(Assembler::word, r16, r16, r13); // ldclr w16, w16, [x13] + __ ldeor(Assembler::word, r14, r12, r2); // ldeor w14, w12, [x2] + __ ldorr(Assembler::word, r17, r3, r21); // ldset w17, w3, [x21] + __ ldsmin(Assembler::word, r23, r5, r6); // ldsmin w23, w5, [x6] + __ ldsmax(Assembler::word, r7, r19, r13); // ldsmax w7, w19, [x13] + __ ldumin(Assembler::word, r28, r17, r16); // ldumin w28, w17, [x16] + __ ldumax(Assembler::word, r6, r2, r29); // ldumax w6, w2, [x29] // LSEOp - __ swpa(Assembler::word, r22, r17, r4); // swpa w22, w17, [x4] - __ ldadda(Assembler::word, r1, r19, r16); // ldadda w1, w19, [x16] - __ ldbica(Assembler::word, r16, r13, r14); // ldclra w16, w13, [x14] - __ ldeora(Assembler::word, r12, r2, r17); // ldeora w12, w2, [x17] - __ ldorra(Assembler::word, r3, r21, r23); // ldseta w3, w21, [x23] - __ ldsmina(Assembler::word, r5, r6, r7); // ldsmina w5, w6, [x7] - __ ldsmaxa(Assembler::word, r19, r13, r28); // ldsmaxa w19, w13, [x28] - __ ldumina(Assembler::word, r17, r16, r6); // ldumina w17, w16, [x6] - __ ldumaxa(Assembler::word, r2, r29, r3); // ldumaxa w2, w29, [x3] + __ swpa(Assembler::word, r3, r4, r6); // swpa w3, w4, [x6] + __ ldadda(Assembler::word, r16, r20, r13); // ldadda w16, w20, [x13] + __ ldbica(Assembler::word, r12, r20, r8); // ldclra w12, w20, [x8] + __ ldeora(Assembler::word, r25, r20, r19); // ldeora w25, w20, [x19] + __ ldorra(Assembler::word, r0, r11, r24); // ldseta w0, w11, [x24] + __ ldsmina(Assembler::word, r6, r20, sp); // ldsmina w6, w20, [sp] + __ ldsmaxa(Assembler::word, r14, r16, r6); // ldsmaxa w14, w16, [x6] + __ ldumina(Assembler::word, r0, r7, r15); // ldumina w0, w7, [x15] + __ ldumaxa(Assembler::word, r19, r26, r9); // ldumaxa w19, w26, [x9] // LSEOp - __ swpal(Assembler::word, r4, r6, r15); // swpal w4, w6, [x15] - __ ldaddal(Assembler::word, r20, r13, r12); // ldaddal w20, w13, [x12] - __ ldbical(Assembler::word, r20, r8, r25); // ldclral w20, w8, [x25] - __ ldeoral(Assembler::word, r20, r19, r0); // ldeoral w20, w19, [x0] - __ ldorral(Assembler::word, r11, r24, r6); // ldsetal w11, w24, [x6] - __ ldsminal(Assembler::word, r20, zr, r14); // ldsminal w20, wzr, [x14] - __ ldsmaxal(Assembler::word, r16, r6, r0); // ldsmaxal w16, w6, [x0] - __ lduminal(Assembler::word, r7, r15, r19); // lduminal w7, w15, [x19] - __ ldumaxal(Assembler::word, r26, r9, r10); // ldumaxal w26, w9, [x10] + __ swpal(Assembler::word, r10, r23, r21); // swpal w10, w23, [x21] + __ ldaddal(Assembler::word, r22, r28, r2); // ldaddal w22, w28, [x2] + __ ldbical(Assembler::word, r3, r15, r19); // ldclral w3, w15, [x19] + __ ldeoral(Assembler::word, r20, r7, r4); // ldeoral w20, w7, [x4] + __ ldorral(Assembler::word, r29, r7, r0); // ldsetal w29, w7, [x0] + __ ldsminal(Assembler::word, r9, r16, r20); // ldsminal w9, w16, [x20] + __ ldsmaxal(Assembler::word, r23, r4, r16); // ldsmaxal w23, w4, [x16] + __ lduminal(Assembler::word, r10, r23, r11); // lduminal w10, w23, [x11] + __ ldumaxal(Assembler::word, r25, r6, sp); // ldumaxal w25, w6, [sp] // LSEOp - __ swpl(Assembler::word, r23, r21, r22); // swpl w23, w21, [x22] - __ ldaddl(Assembler::word, r28, r2, r3); // ldaddl w28, w2, [x3] - __ ldbicl(Assembler::word, r15, r19, r20); // ldclrl w15, w19, [x20] - __ ldeorl(Assembler::word, r7, r4, r29); // ldeorl w7, w4, [x29] - __ ldorrl(Assembler::word, r7, r0, r9); // ldsetl w7, w0, [x9] - __ ldsminl(Assembler::word, r16, r20, r23); // ldsminl w16, w20, [x23] - __ ldsmaxl(Assembler::word, r4, r16, r10); // ldsmaxl w4, w16, [x10] - __ lduminl(Assembler::word, r23, r11, r25); // lduminl w23, w11, [x25] - __ ldumaxl(Assembler::word, r6, zr, r16); // ldumaxl w6, wzr, [x16] + __ swpl(Assembler::word, r16, r13, r23); // swpl w16, w13, [x23] + __ ldaddl(Assembler::word, r12, r1, r14); // ldaddl w12, w1, [x14] + __ ldbicl(Assembler::word, r9, r21, r16); // ldclrl w9, w21, [x16] + __ ldeorl(Assembler::word, r26, r15, r4); // ldeorl w26, w15, [x4] + __ ldorrl(Assembler::word, r4, r16, r8); // ldsetl w4, w16, [x8] + __ ldsminl(Assembler::word, r6, r30, r4); // ldsminl w6, w30, [x4] + __ ldsmaxl(Assembler::word, r29, r17, r29); // ldsmaxl w29, w17, [x29] + __ lduminl(Assembler::word, r26, r9, r15); // lduminl w26, w9, [x15] + __ ldumaxl(Assembler::word, r2, r11, r29); // ldumaxl w2, w11, [x29] // SHA3SIMDOp - __ bcax(v13, __ T16B, v22, v11, v1); // bcax v13.16B, v22.16B, v11.16B, v1.16B - __ eor3(v13, __ T16B, v8, v20, v16); // eor3 v13.16B, v8.16B, v20.16B, v16.16B - __ rax1(v25, __ T2D, v15, v4); // rax1 v25.2D, v15.2D, v4.2D - __ xar(v4, __ T2D, v17, v8, 13); // xar v4.2D, v17.2D, v8.2D, #13 + __ bcax(v3, __ T16B, v7, v1, v27); // bcax v3.16B, v7.16B, v1.16B, v27.16B + __ eor3(v21, __ T16B, v18, v14, v8); // eor3 v21.16B, v18.16B, v14.16B, v8.16B + __ rax1(v18, __ T2D, v22, v25); // rax1 v18.2D, v22.2D, v25.2D + __ xar(v5, __ T2D, v20, v21, 37); // xar v5.2D, v20.2D, v21.2D, #37 // SHA512SIMDOp - __ sha512h(v29, __ T2D, v4, v28); // sha512h q29, q4, v28.2D - __ sha512h2(v16, __ T2D, v29, v26); // sha512h2 q16, q29, v26.2D - __ sha512su0(v9, __ T2D, v14); // sha512su0 v9.2D, v14.2D - __ sha512su1(v2, __ T2D, v11, v28); // sha512su1 v2.2D, v11.2D, v28.2D + __ sha512h(v23, __ T2D, v16, v30); // sha512h q23, q16, v30.2D + __ sha512h2(v20, __ T2D, v20, v0); // sha512h2 q20, q20, v0.2D + __ sha512su0(v4, __ T2D, v19); // sha512su0 v4.2D, v19.2D + __ sha512su1(v24, __ T2D, v4, v20); // sha512su1 v24.2D, v4.2D, v20.2D // SVEBinaryImmOp - __ sve_add(z3, __ B, 10u); // add z3.b, z3.b, #0xa - __ sve_sub(z26, __ S, 150u); // sub z26.s, z26.s, #0x96 - __ sve_and(z14, __ H, 57343u); // and z14.h, z14.h, #0xdfff - __ sve_eor(z24, __ B, 191u); // eor z24.b, z24.b, #0xbf - __ sve_orr(z17, __ S, 4294966791u); // orr z17.s, z17.s, #0xfffffe07 + __ sve_add(z4, __ D, 210u); // add z4.d, z4.d, #0xd2 + __ sve_sub(z19, __ B, 71u); // sub z19.b, z19.b, #0x47 + __ sve_and(z8, __ H, 49663u); // and z8.h, z8.h, #0xc1ff + __ sve_eor(z31, __ S, 4294967231u); // eor z31.s, z31.s, #0xffffffbf + __ sve_orr(z1, __ H, 16368u); // orr z1.h, z1.h, #0x3ff0 // SVEBinaryImmOp - __ sve_add(z20, __ S, 3u); // add z20.s, z20.s, #0x3 - __ sve_sub(z4, __ S, 196u); // sub z4.s, z4.s, #0xc4 - __ sve_and(z4, __ S, 4286578691u); // and z4.s, z4.s, #0xff800003 - __ sve_eor(z25, __ S, 33553408u); // eor z25.s, z25.s, #0x1fffc00 - __ sve_orr(z8, __ H, 49663u); // orr z8.h, z8.h, #0xc1ff + __ sve_add(z0, __ H, 61u); // add z0.h, z0.h, #0x3d + __ sve_sub(z24, __ S, 36u); // sub z24.s, z24.s, #0x24 + __ sve_and(z27, __ B, 243u); // and z27.b, z27.b, #0xf3 + __ sve_eor(z24, __ H, 65534u); // eor z24.h, z24.h, #0xfffe + __ sve_orr(z22, __ S, 4294967293u); // orr z22.s, z22.s, #0xfffffffd // SVEBinaryImmOp - __ sve_add(z30, __ S, 36u); // add z30.s, z30.s, #0x24 - __ sve_sub(z30, __ B, 85u); // sub z30.b, z30.b, #0x55 - __ sve_and(z19, __ H, 4032u); // and z19.h, z19.h, #0xfc0 - __ sve_eor(z7, __ D, 274877904896u); // eor z7.d, z7.d, #0x3ffffff800 - __ sve_orr(z27, __ B, 243u); // orr z27.b, z27.b, #0xf3 + __ sve_add(z29, __ H, 113u); // add z29.h, z29.h, #0x71 + __ sve_sub(z20, __ B, 165u); // sub z20.b, z20.b, #0xa5 + __ sve_and(z28, __ H, 32256u); // and z28.h, z28.h, #0x7e00 + __ sve_eor(z12, __ S, 4287102855u); // eor z12.s, z12.s, #0xff87ff87 + __ sve_orr(z9, __ S, 3825205247u); // orr z9.s, z9.s, #0xe3ffffff // SVEBinaryImmOp - __ sve_add(z23, __ H, 132u); // add z23.h, z23.h, #0x84 - __ sve_sub(z30, __ S, 183u); // sub z30.s, z30.s, #0xb7 - __ sve_and(z20, __ D, 4503599627354112u); // and z20.d, z20.d, #0xfffffffffc000 - __ sve_eor(z13, __ S, 4042322160u); // eor z13.s, z13.s, #0xf0f0f0f0 - __ sve_orr(z28, __ H, 32256u); // orr z28.h, z28.h, #0x7e00 + __ sve_add(z18, __ S, 41u); // add z18.s, z18.s, #0x29 + __ sve_sub(z0, __ B, 98u); // sub z0.b, z0.b, #0x62 + __ sve_and(z8, __ H, 32768u); // and z8.h, z8.h, #0x8000 + __ sve_eor(z4, __ H, 508u); // eor z4.h, z4.h, #0x1fc + __ sve_orr(z0, __ H, 64512u); // orr z0.h, z0.h, #0xfc00 // SVEBinaryImmOp - __ sve_add(z11, __ S, 13u); // add z11.s, z11.s, #0xd - __ sve_sub(z24, __ H, 159u); // sub z24.h, z24.h, #0x9f - __ sve_and(z13, __ S, 2151677951u); // and z13.s, z13.s, #0x803fffff - __ sve_eor(z4, __ B, 124u); // eor z4.b, z4.b, #0x7c - __ sve_orr(z7, __ H, 32768u); // orr z7.h, z7.h, #0x8000 + __ sve_add(z3, __ B, 79u); // add z3.b, z3.b, #0x4f + __ sve_sub(z19, __ D, 84u); // sub z19.d, z19.d, #0x54 + __ sve_and(z24, __ B, 62u); // and z24.b, z24.b, #0x3e + __ sve_eor(z24, __ D, 18428729675200069887u); // eor z24.d, z24.d, #0xffc00000000000ff + __ sve_orr(z11, __ D, 17296056810822168583u); // orr z11.d, z11.d, #0xf007f007f007f007 // SVEBinaryImmOp - __ sve_add(z4, __ H, 243u); // add z4.h, z4.h, #0xf3 - __ sve_sub(z5, __ B, 86u); // sub z5.b, z5.b, #0x56 - __ sve_and(z21, __ D, 8064u); // and z21.d, z21.d, #0x1f80 - __ sve_eor(z9, __ S, 130023424u); // eor z9.s, z9.s, #0x7c00000 - __ sve_orr(z24, __ B, 62u); // orr z24.b, z24.b, #0x3e + __ sve_add(z31, __ S, 115u); // add z31.s, z31.s, #0x73 + __ sve_sub(z3, __ D, 134u); // sub z3.d, z3.d, #0x86 + __ sve_and(z22, __ S, 4042322160u); // and z22.s, z22.s, #0xf0f0f0f0 + __ sve_eor(z3, __ B, 225u); // eor z3.b, z3.b, #0xe1 + __ sve_orr(z9, __ S, 4164941887u); // orr z9.s, z9.s, #0xf83ff83f // SVEVectorOp - __ sve_add(z23, __ S, z28, z13); // add z23.s, z28.s, z13.s - __ sve_sub(z10, __ S, z26, z12); // sub z10.s, z26.s, z12.s - __ sve_fadd(z30, __ S, z17, z14); // fadd z30.s, z17.s, z14.s - __ sve_fmul(z29, __ D, z16, z21); // fmul z29.d, z16.d, z21.d - __ sve_fsub(z7, __ S, z19, z2); // fsub z7.s, z19.s, z2.s - __ sve_abs(z26, __ S, p4, z9); // abs z26.s, p4/m, z9.s - __ sve_add(z17, __ B, p5, z0); // add z17.b, p5/m, z17.b, z0.b - __ sve_and(z2, __ B, p6, z14); // and z2.b, p6/m, z2.b, z14.b - __ sve_asr(z11, __ S, p5, z14); // asr z11.s, p5/m, z11.s, z14.s - __ sve_bic(z29, __ B, p3, z3); // bic z29.b, p3/m, z29.b, z3.b - __ sve_clz(z22, __ D, p2, z3); // clz z22.d, p2/m, z3.d - __ sve_cnt(z27, __ S, p0, z19); // cnt z27.s, p0/m, z19.s - __ sve_eor(z7, __ H, p6, z21); // eor z7.h, p6/m, z7.h, z21.h - __ sve_lsl(z5, __ B, p2, z25); // lsl z5.b, p2/m, z5.b, z25.b - __ sve_lsr(z21, __ B, p4, z17); // lsr z21.b, p4/m, z21.b, z17.b - __ sve_mul(z3, __ H, p2, z19); // mul z3.h, p2/m, z3.h, z19.h - __ sve_neg(z7, __ S, p3, z14); // neg z7.s, p3/m, z14.s - __ sve_not(z17, __ D, p2, z13); // not z17.d, p2/m, z13.d - __ sve_orr(z17, __ H, p7, z17); // orr z17.h, p7/m, z17.h, z17.h - __ sve_rbit(z15, __ S, p3, z26); // rbit z15.s, p3/m, z26.s - __ sve_revb(z27, __ H, p5, z7); // revb z27.h, p5/m, z7.h - __ sve_smax(z5, __ H, p7, z27); // smax z5.h, p7/m, z5.h, z27.h - __ sve_smin(z0, __ S, p3, z24); // smin z0.s, p3/m, z0.s, z24.s - __ sve_sub(z20, __ S, p0, z3); // sub z20.s, p0/m, z20.s, z3.s - __ sve_fabs(z25, __ D, p1, z25); // fabs z25.d, p1/m, z25.d - __ sve_fadd(z17, __ S, p4, z1); // fadd z17.s, p4/m, z17.s, z1.s - __ sve_fdiv(z14, __ S, p7, z13); // fdiv z14.s, p7/m, z14.s, z13.s - __ sve_fmax(z17, __ D, p0, z30); // fmax z17.d, p0/m, z17.d, z30.d - __ sve_fmin(z22, __ S, p5, z29); // fmin z22.s, p5/m, z22.s, z29.s - __ sve_fmul(z8, __ S, p0, z0); // fmul z8.s, p0/m, z8.s, z0.s - __ sve_fneg(z23, __ D, p5, z0); // fneg z23.d, p5/m, z0.d - __ sve_frintm(z25, __ S, p6, z23); // frintm z25.s, p6/m, z23.s - __ sve_frintn(z21, __ S, p5, z1); // frintn z21.s, p5/m, z1.s - __ sve_frintp(z10, __ D, p5, z11); // frintp z10.d, p5/m, z11.d - __ sve_fsqrt(z23, __ D, p6, z8); // fsqrt z23.d, p6/m, z8.d - __ sve_fsub(z17, __ D, p5, z19); // fsub z17.d, p5/m, z17.d, z19.d - __ sve_fmad(z4, __ D, p5, z13, z30); // fmad z4.d, p5/m, z13.d, z30.d - __ sve_fmla(z30, __ D, p7, z25, z17); // fmla z30.d, p7/m, z25.d, z17.d - __ sve_fmls(z14, __ D, p2, z12, z28); // fmls z14.d, p2/m, z12.d, z28.d - __ sve_fmsb(z5, __ S, p0, z13, z13); // fmsb z5.s, p0/m, z13.s, z13.s - __ sve_fnmad(z7, __ S, p2, z11, z19); // fnmad z7.s, p2/m, z11.s, z19.s - __ sve_fnmsb(z25, __ D, p3, z2, z3); // fnmsb z25.d, p3/m, z2.d, z3.d - __ sve_fnmla(z0, __ D, p5, z5, z20); // fnmla z0.d, p5/m, z5.d, z20.d - __ sve_fnmls(z28, __ S, p3, z13, z8); // fnmls z28.s, p3/m, z13.s, z8.s - __ sve_mla(z29, __ B, p0, z14, z27); // mla z29.b, p0/m, z14.b, z27.b - __ sve_mls(z3, __ H, p6, z8, z24); // mls z3.h, p6/m, z8.h, z24.h - __ sve_and(z1, z25, z10); // and z1.d, z25.d, z10.d - __ sve_eor(z1, z20, z25); // eor z1.d, z20.d, z25.d - __ sve_orr(z28, z19, z16); // orr z28.d, z19.d, z16.d - __ sve_bic(z27, z13, z1); // bic z27.d, z13.d, z1.d - __ sve_uzp1(z11, __ B, z9, z1); // uzp1 z11.b, z9.b, z1.b - __ sve_uzp2(z1, __ H, z27, z26); // uzp2 z1.h, z27.h, z26.h - __ sve_fabd(z2, __ D, p1, z29); // fabd z2.d, p1/m, z2.d, z29.d - __ sve_bext(z24, __ D, z2, z2); // bext z24.d, z2.d, z2.d - __ sve_bdep(z3, __ H, z25, z28); // bdep z3.h, z25.h, z28.h - __ sve_eor3(z3, z22, z13); // eor3 z3.d, z3.d, z22.d, z13.d + __ sve_add(z0, __ D, z4, z2); // add z0.d, z4.d, z2.d + __ sve_sub(z14, __ S, z6, z11); // sub z14.s, z6.s, z11.s + __ sve_fadd(z14, __ S, z17, z30); // fadd z14.s, z17.s, z30.s + __ sve_fmul(z3, __ S, z3, z23); // fmul z3.s, z3.s, z23.s + __ sve_fsub(z3, __ S, z24, z28); // fsub z3.s, z24.s, z28.s + __ sve_abs(z19, __ D, p5, z7); // abs z19.d, p5/m, z7.d + __ sve_add(z21, __ H, p3, z5); // add z21.h, p3/m, z21.h, z5.h + __ sve_and(z26, __ S, p1, z22); // and z26.s, p1/m, z26.s, z22.s + __ sve_asr(z17, __ H, p0, z3); // asr z17.h, p0/m, z17.h, z3.h + __ sve_bic(z20, __ H, p3, z8); // bic z20.h, p3/m, z20.h, z8.h + __ sve_clz(z14, __ H, p4, z17); // clz z14.h, p4/m, z17.h + __ sve_cnt(z13, __ D, p6, z18); // cnt z13.d, p6/m, z18.d + __ sve_eor(z19, __ H, p2, z16); // eor z19.h, p2/m, z19.h, z16.h + __ sve_lsl(z27, __ S, p5, z28); // lsl z27.s, p5/m, z27.s, z28.s + __ sve_lsr(z8, __ D, p2, z5); // lsr z8.d, p2/m, z8.d, z5.d + __ sve_mul(z28, __ H, p2, z0); // mul z28.h, p2/m, z28.h, z0.h + __ sve_neg(z25, __ B, p5, z21); // neg z25.b, p5/m, z21.b + __ sve_not(z3, __ B, p5, z26); // not z3.b, p5/m, z26.b + __ sve_orr(z26, __ S, p7, z19); // orr z26.s, p7/m, z26.s, z19.s + __ sve_rbit(z1, __ D, p3, z14); // rbit z1.d, p3/m, z14.d + __ sve_revb(z14, __ H, p0, z18); // revb z14.h, p0/m, z18.h + __ sve_smax(z31, __ S, p5, z23); // smax z31.s, p5/m, z31.s, z23.s + __ sve_smin(z30, __ B, p3, z8); // smin z30.b, p3/m, z30.b, z8.b + __ sve_sub(z0, __ S, p3, z23); // sub z0.s, p3/m, z0.s, z23.s + __ sve_fabs(z0, __ D, p4, z26); // fabs z0.d, p4/m, z26.d + __ sve_fadd(z24, __ D, p3, z22); // fadd z24.d, p3/m, z24.d, z22.d + __ sve_fdiv(z2, __ D, p0, z11); // fdiv z2.d, p0/m, z2.d, z11.d + __ sve_fmax(z12, __ D, p5, z24); // fmax z12.d, p5/m, z12.d, z24.d + __ sve_fmin(z9, __ D, p7, z17); // fmin z9.d, p7/m, z9.d, z17.d + __ sve_fmul(z20, __ D, p5, z4); // fmul z20.d, p5/m, z20.d, z4.d + __ sve_fneg(z13, __ D, p7, z22); // fneg z13.d, p7/m, z22.d + __ sve_frintm(z31, __ D, p6, z18); // frintm z31.d, p6/m, z18.d + __ sve_frintn(z15, __ D, p2, z13); // frintn z15.d, p2/m, z13.d + __ sve_frintp(z20, __ S, p1, z1); // frintp z20.s, p1/m, z1.s + __ sve_fsqrt(z14, __ S, p0, z7); // fsqrt z14.s, p0/m, z7.s + __ sve_fsub(z12, __ D, p4, z4); // fsub z12.d, p4/m, z12.d, z4.d + __ sve_fmad(z15, __ S, p0, z3, z30); // fmad z15.s, p0/m, z3.s, z30.s + __ sve_fmla(z20, __ D, p1, z20, z31); // fmla z20.d, p1/m, z20.d, z31.d + __ sve_fmls(z13, __ D, p3, z9, z14); // fmls z13.d, p3/m, z9.d, z14.d + __ sve_fmsb(z1, __ S, p3, z28, z3); // fmsb z1.s, p3/m, z28.s, z3.s + __ sve_fnmad(z26, __ S, p2, z25, z9); // fnmad z26.s, p2/m, z25.s, z9.s + __ sve_fnmsb(z26, __ D, p2, z14, z1); // fnmsb z26.d, p2/m, z14.d, z1.d + __ sve_fnmla(z26, __ D, p1, z29, z20); // fnmla z26.d, p1/m, z29.d, z20.d + __ sve_fnmls(z6, __ D, p7, z13, z1); // fnmls z6.d, p7/m, z13.d, z1.d + __ sve_mla(z11, __ B, p2, z1, z1); // mla z11.b, p2/m, z1.b, z1.b + __ sve_mls(z27, __ B, p6, z15, z2); // mls z27.b, p6/m, z15.b, z2.b + __ sve_and(z30, z17, z25); // and z30.d, z17.d, z25.d + __ sve_eor(z2, z24, z3); // eor z2.d, z24.d, z3.d + __ sve_orr(z29, z13, z3); // orr z29.d, z13.d, z3.d + __ sve_bic(z14, z16, z28); // bic z14.d, z16.d, z28.d + __ sve_uzp1(z4, __ S, z11, z27); // uzp1 z4.s, z11.s, z27.s + __ sve_uzp2(z2, __ D, z16, z1); // uzp2 z2.d, z16.d, z1.d + __ sve_fabd(z7, __ D, p5, z31); // fabd z7.d, p5/m, z7.d, z31.d + __ sve_bext(z16, __ S, z10, z22); // bext z16.s, z10.s, z22.s + __ sve_bdep(z29, __ B, z7, z22); // bdep z29.b, z7.b, z22.b + __ sve_eor3(z12, z24, z11); // eor3 z12.d, z12.d, z24.d, z11.d // SVEReductionOp - __ sve_andv(v27, __ H, p4, z4); // andv h27, p4, z4.h - __ sve_orv(v26, __ S, p4, z2); // orv s26, p4, z2.s - __ sve_eorv(v1, __ S, p7, z7); // eorv s1, p7, z7.s - __ sve_smaxv(v30, __ H, p7, z16); // smaxv h30, p7, z16.h - __ sve_sminv(v21, __ B, p4, z28); // sminv b21, p4, z28.b - __ sve_fminv(v21, __ D, p1, z12); // fminv d21, p1, z12.d - __ sve_fmaxv(v11, __ S, p2, z10); // fmaxv s11, p2, z10.s - __ sve_fadda(v0, __ D, p1, z22); // fadda d0, p1, d0, z22.d - __ sve_uaddv(v20, __ H, p1, z3); // uaddv d20, p1, z3.h + __ sve_andv(v11, __ B, p2, z0); // andv b11, p2, z0.b + __ sve_orv(v23, __ B, p5, z20); // orv b23, p5, z20.b + __ sve_eorv(v3, __ B, p3, z15); // eorv b3, p3, z15.b + __ sve_smaxv(v30, __ B, p6, z27); // smaxv b30, p6, z27.b + __ sve_sminv(v21, __ D, p6, z10); // sminv d21, p6, z10.d + __ sve_fminv(v3, __ S, p6, z4); // fminv s3, p6, z4.s + __ sve_fmaxv(v6, __ S, p0, z21); // fmaxv s6, p0, z21.s + __ sve_fadda(v25, __ D, p6, z30); // fadda d25, p6, d25, z30.d + __ sve_uaddv(v31, __ H, p4, z1); // uaddv d31, p4, z1.h + +// AddWideNEONOp + __ saddwv(v12, v13, __ T8H, v14, __ T8B); // saddw v12.8H, v13.8H, v14.8B + __ saddwv2(v30, v31, __ T8H, v0, __ T16B); // saddw2 v30.8H, v31.8H, v0.16B + __ saddwv(v13, v14, __ T4S, v15, __ T4H); // saddw v13.4S, v14.4S, v15.4H + __ saddwv2(v8, v9, __ T4S, v10, __ T8H); // saddw2 v8.4S, v9.4S, v10.8H + __ saddwv(v25, v26, __ T2D, v27, __ T2S); // saddw v25.2D, v26.2D, v27.2S + __ saddwv2(v29, v30, __ T2D, v31, __ T4S); // saddw2 v29.2D, v30.2D, v31.4S + __ uaddwv(v1, v2, __ T8H, v3, __ T8B); // uaddw v1.8H, v2.8H, v3.8B + __ uaddwv2(v31, v0, __ T8H, v1, __ T16B); // uaddw2 v31.8H, v0.8H, v1.16B + __ uaddwv(v23, v24, __ T4S, v25, __ T4H); // uaddw v23.4S, v24.4S, v25.4H + __ uaddwv2(v31, v0, __ T4S, v1, __ T8H); // uaddw2 v31.4S, v0.4S, v1.8H + __ uaddwv(v20, v21, __ T2D, v22, __ T2S); // uaddw v20.2D, v21.2D, v22.2S + __ uaddwv2(v0, v1, __ T2D, v2, __ T4S); // uaddw2 v0.2D, v1.2D, v2.4S __ bind(forth); @@ -1298,30 +1327,30 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x14000428, 0x94000000, - 0x97ffffd4, 0x94000425, 0x3400000a, 0x34fffa2a, - 0x3400844a, 0x35000008, 0x35fff9c8, 0x350083e8, - 0xb400000b, 0xb4fff96b, 0xb400838b, 0xb500001d, - 0xb5fff91d, 0xb500833d, 0x10000013, 0x10fff8b3, - 0x100082d3, 0x90000013, 0x36300016, 0x3637f836, - 0x36308256, 0x3758000c, 0x375ff7cc, 0x375881ec, + 0x14000000, 0x17ffffd7, 0x14000441, 0x94000000, + 0x97ffffd4, 0x9400043e, 0x3400000a, 0x34fffa2a, + 0x3400876a, 0x35000008, 0x35fff9c8, 0x35008708, + 0xb400000b, 0xb4fff96b, 0xb40086ab, 0xb500001d, + 0xb5fff91d, 0xb500865d, 0x10000013, 0x10fff8b3, + 0x100085f3, 0x90000013, 0x36300016, 0x3637f836, + 0x36308576, 0x3758000c, 0x375ff7cc, 0x3758850c, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x54007fc0, 0x54000001, 0x54fff541, 0x54007f61, - 0x54000002, 0x54fff4e2, 0x54007f02, 0x54000002, - 0x54fff482, 0x54007ea2, 0x54000003, 0x54fff423, - 0x54007e43, 0x54000003, 0x54fff3c3, 0x54007de3, - 0x54000004, 0x54fff364, 0x54007d84, 0x54000005, - 0x54fff305, 0x54007d25, 0x54000006, 0x54fff2a6, - 0x54007cc6, 0x54000007, 0x54fff247, 0x54007c67, - 0x54000008, 0x54fff1e8, 0x54007c08, 0x54000009, - 0x54fff189, 0x54007ba9, 0x5400000a, 0x54fff12a, - 0x54007b4a, 0x5400000b, 0x54fff0cb, 0x54007aeb, - 0x5400000c, 0x54fff06c, 0x54007a8c, 0x5400000d, - 0x54fff00d, 0x54007a2d, 0x5400000e, 0x54ffefae, - 0x540079ce, 0x5400000f, 0x54ffef4f, 0x5400796f, + 0x540082e0, 0x54000001, 0x54fff541, 0x54008281, + 0x54000002, 0x54fff4e2, 0x54008222, 0x54000002, + 0x54fff482, 0x540081c2, 0x54000003, 0x54fff423, + 0x54008163, 0x54000003, 0x54fff3c3, 0x54008103, + 0x54000004, 0x54fff364, 0x540080a4, 0x54000005, + 0x54fff305, 0x54008045, 0x54000006, 0x54fff2a6, + 0x54007fe6, 0x54000007, 0x54fff247, 0x54007f87, + 0x54000008, 0x54fff1e8, 0x54007f28, 0x54000009, + 0x54fff189, 0x54007ec9, 0x5400000a, 0x54fff12a, + 0x54007e6a, 0x5400000b, 0x54fff0cb, 0x54007e0b, + 0x5400000c, 0x54fff06c, 0x54007dac, 0x5400000d, + 0x54fff00d, 0x54007d4d, 0x5400000e, 0x54ffefae, + 0x54007cee, 0x5400000f, 0x54ffef4f, 0x54007c8f, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, @@ -1346,23 +1375,23 @@ 0xb81b1022, 0x381ea354, 0x79002fd7, 0xf85cf39a, 0xb8580309, 0x385e218c, 0x784051e1, 0x389e11d8, 0x789fa1f8, 0x79c01865, 0xb881131b, 0xfc5dd3ad, - 0xbc5d1136, 0xfc00900b, 0xbc181014, 0xf818ec7d, + 0xbc5d1137, 0xfc00900b, 0xbc181015, 0xf818ec7d, 0xb81b8c91, 0x381efc40, 0x78007c3d, 0xf857beb0, 0xb8413dd4, 0x385fddd6, 0x78409e2f, 0x389eddea, 0x789e7d94, 0x78de3d55, 0xb8805c13, 0xfc5cadc0, - 0xbc428c23, 0xfc1a2dc4, 0xbc1caf91, 0xf81475f6, + 0xbc428c23, 0xfc1a2dc4, 0xbc1caf92, 0xf81475f6, 0xb81f95d1, 0x381e757e, 0x78014561, 0xf8402436, 0xb85896e2, 0x385f4763, 0x785db4f0, 0x3880374f, 0x789e25e7, 0x78dd0563, 0xb88166f9, 0xfc529540, - 0xbc4374d1, 0xfc1166ad, 0xbc1ba6c0, 0xf820ea7b, + 0xbc4374d3, 0xfc1166ae, 0xbc1ba6c0, 0xf820ea7b, 0xb82d68c8, 0x38367a04, 0x782f4b59, 0xf878c8a4, 0xb8674a24, 0x386b78f1, 0x78776bc0, 0x38a15aca, - 0x78bedbd5, 0x78fcd94b, 0xb8aa4a7c, 0xfc6ecbbd, - 0xbc65d8a8, 0xfc2de918, 0xbc3a7b11, 0xf91f1193, + 0x78bedbd5, 0x78fcd94b, 0xb8aa4a7c, 0xfc6ecbbe, + 0xbc65d8a8, 0xfc2de919, 0xbc3a7b11, 0xf91f1193, 0xb91ed5f7, 0x391ec9bd, 0x79182ceb, 0xf95d4b0a, 0xb9581010, 0x395fc034, 0x795fb221, 0x399d8731, 0x799efb3b, 0x79dd1a2e, 0xb998e4ea, 0xfd583723, - 0xbd5ea12c, 0xfd18dc37, 0xbd1b0e83, 0x58ffdaa2, + 0xbd5ea12c, 0xfd18dc38, 0xbd1b0e83, 0x58ffdaa2, 0x1800001d, 0xf885d1c0, 0xd8ffda40, 0xf8a77820, 0xf9980220, 0x1a030301, 0x3a140311, 0x5a0d000b, 0x7a07015c, 0x9a1001e4, 0xba140182, 0xda0d01bd, @@ -1383,187 +1412,193 @@ 0x9ad521f7, 0x9adb263c, 0x9ac0286a, 0x9ac92f27, 0x9bdd7de6, 0x9b427d4f, 0x1b0b2cf1, 0x1b1ddcf7, 0x9b0b2f6e, 0x9b0cbf04, 0x9b2b728e, 0x9b2cdd6d, - 0x9bae275e, 0x9ba7954d, 0x7ea3d5fd, 0x1e2f098b, - 0x1e311bde, 0x1e2f2a93, 0x1e35392f, 0x7efbd522, - 0x1e7e0ba7, 0x1e621831, 0x1e632946, 0x1e673978, - 0x1f000d61, 0x1f06db91, 0x1f3b6806, 0x1f2770a2, - 0x1f4d2f2b, 0x1f48c677, 0x1f744f35, 0x1f7d5851, - 0x1e2042a8, 0x1e20c293, 0x1e21422b, 0x1e21c0d4, - 0x1e22c06f, 0x1e23c383, 0x1ee24363, 0x1e6041ce, - 0x1e60c18a, 0x1e61422b, 0x1e61c32a, 0x1e6240e7, - 0x1e38038e, 0x9e3802c0, 0x1e780180, 0x9e7801b7, - 0x1e2200ed, 0x9e2200ee, 0x1e620288, 0x9e620391, - 0x1e24021e, 0x9e640122, 0x1e300290, 0x9e70009d, - 0x1e260341, 0x9e6602f8, 0x1e2702ae, 0x9e6700ac, - 0x1e382180, 0x1e7d2300, 0x1e202368, 0x1e6022a8, + 0x9bae275e, 0x9ba7954d, 0x7ea3d5fe, 0x1e30098c, + 0x1e321bff, 0x1e302ab3, 0x1e35394f, 0x7efcd542, + 0x1e7f0bc7, 0x1e621832, 0x1e632946, 0x1e673979, + 0x1f000d81, 0x1f06dfb3, 0x1f3c6c06, 0x1f2774a2, + 0x1f4d332c, 0x1f48ca78, 0x1f755356, 0x1f7e5853, + 0x1e2042c8, 0x1e20c2b3, 0x1e21424c, 0x1e21c0d5, + 0x1e22c070, 0x1e23c3a3, 0x1ee24383, 0x1e6041cf, + 0x1e60c1aa, 0x1e61424c, 0x1e61c34a, 0x1e6240e7, + 0x1e3803ae, 0x9e3802e0, 0x1e780180, 0x9e7801d7, + 0x1e2200ed, 0x9e2200ef, 0x1e620289, 0x9e620393, + 0x1e24021e, 0x9e640122, 0x1e3002b0, 0x9e70009d, + 0x1e260361, 0x9e660318, 0x1e2702ae, 0x9e6700ad, + 0x1e392180, 0x1e7e2320, 0x1e202388, 0x1e6022a8, 0x293a1796, 0x29426e73, 0x697c68fc, 0xa93d0486, 0xa97b5eba, 0x29b47934, 0x29c2534d, 0x69f62dbd, 0xa9bd54bb, 0xa9c503c6, 0x28a63e13, 0x28e25d2c, 0x68c469e0, 0xa8b34748, 0xa8f51c59, 0x28264433, 0x285036c0, 0xa8005f7d, 0xa872290b, 0x0c407160, - 0x4cdfa350, 0x0cd16f55, 0x4cdf27ba, 0x0d40c0d5, - 0x4ddfcbad, 0x0dd0cd95, 0x4c408c01, 0x0cdf86a9, - 0x4d60c327, 0x0dffc928, 0x4deecd89, 0x4cd14887, - 0x0c404a37, 0x4d40e6c3, 0x4ddfe84c, 0x0dcced4f, - 0x4cdf0444, 0x0ccb0286, 0x0d60e18b, 0x0dffe62f, - 0x0df0eb2e, 0x0e31bab4, 0x4e31b841, 0x0e71baf6, + 0x4cdfa350, 0x0cd16f56, 0x4cdf27bb, 0x0d40c0d6, + 0x4ddfcbae, 0x0dd0cd96, 0x4c408c01, 0x0cdf86aa, + 0x4d60c327, 0x0dffc929, 0x4deecd89, 0x4cd14887, + 0x0c404a37, 0x4d40e6c4, 0x4ddfe84d, 0x0dcced50, + 0x4cdf0444, 0x0ccb0286, 0x0d60e18c, 0x0dffe630, + 0x0df0eb2e, 0x0e31bab4, 0x4e31b841, 0x0e71bb17, 0x4e71bbfe, 0x4eb1b9ee, 0x0e30a862, 0x4e30a8e6, - 0x0e70a883, 0x4e70a907, 0x4eb0ab38, 0x6e30f820, - 0x0e31ab9b, 0x2e31abdd, 0x4e31a8c5, 0x6e31a8c5, - 0x0e71abdd, 0x2e71a98b, 0x4e71ab59, 0x6e71a820, - 0x4eb1abfe, 0x6eb1a820, 0x6eb0fa51, 0x7e30fbbc, - 0x7e70fb59, 0x7eb0f949, 0x7ef0fb59, 0x0ea0c9ac, - 0x4ea0ca0f, 0x4ee0c98b, 0x2ea0c96a, 0x6ea0ca51, - 0x6ee0cb38, 0x0ea0dad5, 0x4ea0db17, 0x4ee0d820, - 0x0ea0ea30, 0x4ea0e96a, 0x4ee0e8e6, 0x2ea0dbbc, - 0x6ea0d8e6, 0x6ee0d8c5, 0x0e20b8c5, 0x4e20bab4, - 0x0e60ba51, 0x4e60ba0f, 0x0ea0ba51, 0x4ea0bbdd, - 0x4ee0bb7a, 0x0ea0fbbc, 0x4ea0f841, 0x4ee0fb9b, - 0x2ea0f820, 0x6ea0fab4, 0x6ee0fbbc, 0x2ea1fa0f, - 0x6ea1f9ac, 0x6ee1f96a, 0x2e205bbc, 0x6e205bbc, + 0x0e70a883, 0x4e70a928, 0x4eb0ab59, 0x6e30f820, + 0x0e31ab9b, 0x2e31abfe, 0x4e31a8c5, 0x6e31a8c5, + 0x0e71abfe, 0x2e71a98b, 0x4e71ab59, 0x6e71a820, + 0x4eb1a81f, 0x6eb1a820, 0x6eb0fa93, 0x7e30fbdd, + 0x7e70fb7a, 0x7eb0f949, 0x7ef0fb7a, 0x0ea0c9ac, + 0x4ea0ca0f, 0x4ee0c98b, 0x2ea0c98b, 0x6ea0ca72, + 0x6ee0cb59, 0x0ea0daf6, 0x4ea0db38, 0x4ee0d820, + 0x0ea0ea51, 0x4ea0e98b, 0x4ee0e8e6, 0x2ea0dbdd, + 0x6ea0d8e6, 0x6ee0d8c5, 0x0e20b8c5, 0x4e20bad5, + 0x0e60ba93, 0x4e60ba30, 0x0ea0ba72, 0x4ea0bbfe, + 0x4ee0bb9b, 0x0ea0fbbc, 0x4ea0f841, 0x4ee0fbbc, + 0x2ea0f841, 0x6ea0fab4, 0x6ee0fbdd, 0x2ea1fa30, + 0x6ea1f9cd, 0x6ee1f96a, 0x2e205bdd, 0x6e205bdd, 0x0e351e93, 0x4e381ef6, 0x0eac1d6a, 0x4ea61ca4, - 0x2e201ffe, 0x6e361eb4, 0x0e2a8528, 0x4e2087fe, - 0x0e738651, 0x4e6c856a, 0x0ebd879b, 0x4ea48462, - 0x4efa8738, 0x0e26d4a4, 0x4e25d483, 0x4e6ad528, - 0x2e3886f6, 0x6e338651, 0x2e6f85cd, 0x6e6684a4, - 0x2ebe87bc, 0x6eb98717, 0x6ef786d5, 0x0ebbd759, - 0x4ebad738, 0x4ee5d483, 0x0e399f17, 0x4e3c9f7a, - 0x0e799f17, 0x4e709dee, 0x0eb79ed5, 0x4ea59c83, - 0x2eb9d717, 0x6eaad528, 0x6efad738, 0x2e35d693, - 0x6e31d60f, 0x6e72d630, 0x2e24dc62, 0x6e23dc41, + 0x2e211c1f, 0x6e371ed5, 0x0e2a8528, 0x4e21841f, + 0x0e758693, 0x4e6c856a, 0x0ebe87bc, 0x4ea48462, + 0x4efb8759, 0x0e27d4c5, 0x4e25d483, 0x4e6ad528, + 0x2e3886f6, 0x6e358693, 0x2e6f85cd, 0x6e6784c5, + 0x2ebf87dd, 0x6eba8738, 0x6ef786d5, 0x0ebcd77a, + 0x4ebad738, 0x4ee5d483, 0x0e3a9f38, 0x4e3c9f7a, + 0x0e799f17, 0x4e719e0f, 0x0eb79ed5, 0x4ea59c83, + 0x2ebad738, 0x6eaad528, 0x6efbd759, 0x2e36d6b4, + 0x6e32d630, 0x6e73d651, 0x2e24dc62, 0x6e23dc41, 0x6e62dc20, 0x0e7a9738, 0x4e6694a4, 0x0ea59483, - 0x4ead958b, 0x0e20cffe, 0x4e3dcf9b, 0x4e6bcd49, - 0x2e7b9759, 0x6e649462, 0x2eae95ac, 0x6eb39651, - 0x0ea0cffe, 0x4ea3cc41, 0x4eeecdac, 0x2e3effbc, - 0x6e22fc20, 0x6e73fe51, 0x0e2e65ac, 0x4e336651, - 0x0e7766d5, 0x4e6e65ac, 0x0ebd679b, 0x4ebf67dd, - 0x0e20a7fe, 0x4e23a441, 0x0e7ba759, 0x4e7da79b, - 0x0ea6a4a4, 0x4ebfa7dd, 0x0e25f483, 0x4e28f4e6, - 0x4e7ff7dd, 0x0e3b6f59, 0x4e336e51, 0x0e6a6d28, - 0x4e696d07, 0x0eae6dac, 0x4ea26c20, 0x0e35ae93, - 0x4e23ac41, 0x0e79af17, 0x4e64ac62, 0x0ea2ac20, - 0x4eaaad28, 0x0eb9f717, 0x4ebbf759, 0x4ef1f60f, - 0x2ebfefdd, 0x6ea5ec83, 0x6eeced6a, 0x0e3836f6, - 0x4e2c356a, 0x0e6634a4, 0x4e733651, 0x0ea33441, - 0x4ead358b, 0x4ee93507, 0x0e2c3d6a, 0x4e313e0f, - 0x0e723e30, 0x4e643c62, 0x0eab3d49, 0x4ead3d8b, - 0x4eee3dac, 0x2e308dee, 0x6e2f8dcd, 0x2e648c62, - 0x6e688ce6, 0x2eb58e93, 0x6ebb8f59, 0x6ef18e0f, - 0x2e2634a4, 0x6e243462, 0x2e6634a4, 0x6e6d358b, - 0x2eb33651, 0x6eb636b4, 0x6ef23630, 0x2e333e51, - 0x6e2c3d6a, 0x2e763eb4, 0x6e783ef6, 0x2eae3dac, - 0x6ebb3f59, 0x6ef93f17, 0x0e3ee7bc, 0x4e30e5ee, - 0x4e6ce56a, 0x2ebae738, 0x6ea3e441, 0x6eede58b, - 0x2e20e7fe, 0x6e2ce56a, 0x6e71e60f, 0x65922c43, - 0x65d02219, 0x65d02560, 0x65d13dc4, 0x65913690, - 0x65d33b6b, 0x2500948c, 0x254c08bf, 0x25831f87, - 0x254f30af, 0x259c3359, 0x25019d35, 0x24eac76d, - 0x2431993a, 0x242f7ed8, 0x24a2f62b, 0xba5fd3e3, - 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, 0x93df03ff, - 0xc820ffff, 0x8822fc7f, 0xc8247cbf, 0x88267fff, - 0x4e010fe0, 0x5e040420, 0x4e081fe1, 0x4e0c1fe1, - 0x4e0a1fe1, 0x4e071fe1, 0x4e042c20, 0x4e062c20, - 0x4e052c20, 0x4e083c20, 0x0e0c3c20, 0x0e0a3c20, - 0x0e073c20, 0x9eae0020, 0x0f03f409, 0x6f03f40e, - 0x4cc0ac3f, 0x0ea1b820, 0x4e21c862, 0x4e61b8a4, - 0x05a08020, 0x05104fe0, 0x05505001, 0x05906fe2, - 0x05d03005, 0x05101fea, 0x05901feb, 0x04b0e3e0, - 0x0470e7e1, 0x042f9c20, 0x043f9c35, 0x047f9c20, - 0x04ff9c20, 0x04299420, 0x04319160, 0x0461943e, - 0x04a19020, 0x04038100, 0x040381a0, 0x040387e1, - 0x04438be2, 0x04c38fe3, 0x040181e0, 0x04018100, - 0x04018621, 0x04418b22, 0x04418822, 0x04818c23, - 0x040081e0, 0x04008120, 0x04008761, 0x04008621, - 0x04408822, 0x04808c23, 0x042053ff, 0x047f5401, - 0x25208028, 0x2538cfe0, 0x2578d001, 0x25b8efe2, - 0x25f8f007, 0x2538dfea, 0x25b8dfeb, 0xa400a3e0, - 0xa420a7e0, 0xa4484be0, 0xa467afe0, 0xa4a8a7ea, - 0xa547a814, 0xa4084ffe, 0xa55c53e0, 0xa5e1540b, - 0xe400fbf6, 0xe408ffff, 0xe420e7e0, 0xe4484be0, - 0xe460efe0, 0xe547e400, 0xe4014be0, 0xe4a84fe0, - 0xe5f15000, 0x858043e0, 0x85a043ff, 0xe59f5d08, - 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, 0x04e0e3ec, - 0x25104042, 0x25104871, 0x25904861, 0x25904c92, - 0x05344020, 0x05744041, 0x05b44062, 0x05f44083, - 0x252c8840, 0x253c1420, 0x25681572, 0x25a21ce3, - 0x25ea1e34, 0x253c0421, 0x25680572, 0x25a20ce3, - 0x25ea0e34, 0x0522c020, 0x05e6c0a4, 0x2401a001, - 0x2443a051, 0x24858881, 0x24c78cd1, 0x24850891, - 0x24c70cc1, 0x250f9001, 0x25508051, 0x25802491, - 0x25df28c1, 0x25850c81, 0x251e10d1, 0x65816001, - 0x65c36051, 0x65854891, 0x65c74cc1, 0x05733820, - 0x05b238a4, 0x05f138e6, 0x0570396a, 0x65d0a001, - 0x65d6a443, 0x65d4a826, 0x6594ac26, 0x6554ac26, - 0x6556ac26, 0x6552ac26, 0x65cbac85, 0x65caac01, - 0x6589ac85, 0x6588ac01, 0x65c9ac85, 0x65c8ac01, - 0x65dea833, 0x659ca509, 0x65d8a801, 0x65dcac01, - 0x655cb241, 0x0520a1e0, 0x0521a601, 0x052281e0, - 0x05238601, 0x04a14026, 0x042244a6, 0x046344a6, - 0x04a444a6, 0x04e544a7, 0x0568aca7, 0x05b23230, - 0x853040af, 0xc5b040af, 0xe57080af, 0xe5b080af, - 0x25034440, 0x254054c4, 0x25034640, 0x25415a05, - 0x25834440, 0x25c54489, 0x250b5d3a, 0x2550dc20, - 0x2518e3e1, 0x2518e021, 0x2518e0a1, 0x2518e121, - 0x2518e1a1, 0x2558e3e2, 0x2558e042, 0x2558e0c2, - 0x2558e142, 0x2598e3e3, 0x2598e063, 0x2598e0e3, - 0x2598e163, 0x25d8e3e4, 0x25d8e084, 0x25d8e104, - 0x25d8e184, 0x2518e407, 0x05214800, 0x05614800, - 0x05a14800, 0x05e14800, 0x05214c00, 0x05614c00, - 0x05a14c00, 0x05e14c00, 0x05304001, 0x05314001, - 0x05a18610, 0x05e18610, 0x05271e11, 0x6545e891, - 0x6585e891, 0x65c5e891, 0x6545c891, 0x6585c891, - 0x65c5c891, 0x45b0c210, 0x45f1c231, 0x1e601000, - 0x1e603000, 0x1e621000, 0x1e623000, 0x1e641000, - 0x1e643000, 0x1e661000, 0x1e663000, 0x1e681000, - 0x1e683000, 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, - 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, 0x1e701000, - 0x1e703000, 0x1e721000, 0x1e723000, 0x1e741000, - 0x1e743000, 0x1e761000, 0x1e763000, 0x1e781000, - 0x1e783000, 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, - 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, 0xf82f8186, - 0xf83001ab, 0xf83713c1, 0xf8332225, 0xf82232d0, - 0xf82d52aa, 0xf83d419b, 0xf83b7023, 0xf83f6278, - 0xf8b18389, 0xf8bb00ef, 0xf8b513f7, 0xf8b923e2, - 0xf8bb3150, 0xf8b75073, 0xf8b04320, 0xf8ba7057, - 0xf8b0608c, 0xf8fc83be, 0xf8f000db, 0xf8e911fd, - 0xf8e720e4, 0xf8ef32e9, 0xf8e85382, 0xf8f540bf, - 0xf8fb7220, 0xf8ef6344, 0xf86882dc, 0xf87b033b, - 0xf8771080, 0xf8662010, 0xf864302f, 0xf86a50a7, - 0xf86a40fc, 0xf87472b7, 0xf866610b, 0xb83180df, - 0xb8310182, 0xb83e107d, 0xb83b23b6, 0xb82e338d, - 0xb83150b8, 0xb822414e, 0xb830736b, 0xb837608c, - 0xb8b68091, 0xb8a10213, 0xb8b011cd, 0xb8ac2222, - 0xb8a332f5, 0xb8a550e6, 0xb8b3438d, 0xb8b170d0, - 0xb8a2607d, 0xb8e481e6, 0xb8f4018d, 0xb8f41328, - 0xb8f42013, 0xb8eb30d8, 0xb8f451df, 0xb8f04006, - 0xb8e7726f, 0xb8fa6149, 0xb87782d5, 0xb87c0062, - 0xb86f1293, 0xb86723a4, 0xb8673120, 0xb87052f4, - 0xb8644150, 0xb877732b, 0xb866621f, 0xce2b06cd, - 0xce14410d, 0xce648df9, 0xce883624, 0xce7c809d, - 0xce7a87b0, 0xcec081c9, 0xce7c8962, 0x2520c143, - 0x25a1d2da, 0x058015ce, 0x05400ed8, 0x0500bb31, - 0x25a0c074, 0x25a1d884, 0x05804944, 0x0540b1d9, - 0x05001548, 0x25a0c49e, 0x2521cabe, 0x058054b3, - 0x0543ab47, 0x050026bb, 0x2560d097, 0x25a1d6fe, - 0x058394b4, 0x0540266d, 0x05003cbc, 0x25a0c1ab, - 0x2561d3f8, 0x05800acd, 0x05403684, 0x05000c07, - 0x2560de64, 0x2521cac5, 0x0583c8b5, 0x05405089, - 0x05003e98, 0x04ad0397, 0x04ac074a, 0x658e023e, - 0x65d50a1d, 0x65820667, 0x0496b13a, 0x04001411, - 0x041a19c2, 0x049095cb, 0x041b0c7d, 0x04d9a876, - 0x049aa27b, 0x04591aa7, 0x04138b25, 0x04119235, - 0x04500a63, 0x0497adc7, 0x04dea9b1, 0x04581e31, - 0x05a78f4f, 0x056494fb, 0x04481f65, 0x048a0f00, - 0x04810074, 0x04dca739, 0x65809031, 0x658d9dae, - 0x65c683d1, 0x658797b6, 0x65828008, 0x04ddb417, - 0x6582baf9, 0x6580b435, 0x65c1b56a, 0x65cdb917, - 0x65c19671, 0x65fe95a4, 0x65f11f3e, 0x65fc298e, - 0x65ada1a5, 0x65b3c967, 0x65e3ec59, 0x65f454a0, - 0x65a86dbc, 0x041b41dd, 0x04587903, 0x042a3321, - 0x04b93281, 0x0470327c, 0x04e131bb, 0x0521692b, - 0x057a6f61, 0x65c887a2, 0x45c2b058, 0x455cb723, - 0x043639a3, 0x045a309b, 0x0498305a, 0x04993ce1, - 0x04483e1e, 0x040a3395, 0x65c72595, 0x6586294b, - 0x65d826c0, 0x04412474, + 0x4eae95ac, 0x0e21cc1f, 0x4e3ecfbc, 0x4e6ccd6a, + 0x2e7c977a, 0x6e649462, 0x2eae95ac, 0x6eb49672, + 0x0ea1cc1f, 0x4ea3cc41, 0x4eefcdcd, 0x2e3fffdd, + 0x6e22fc20, 0x6e75fe93, 0x0e2e65ac, 0x4e336651, + 0x0e7866f6, 0x4e6f65cd, 0x0ebe67bc, 0x4ea067fe, + 0x0e21a41f, 0x4e23a441, 0x0e7ca77a, 0x4e7ea7bc, + 0x0ea6a4a4, 0x4ea0a7fe, 0x0e26f4a4, 0x4e28f4e6, + 0x4e60f7fe, 0x0e3c6f7a, 0x4e346e72, 0x0e6b6d49, + 0x4e6a6d28, 0x0eae6dac, 0x4ea26c20, 0x0e36aeb4, + 0x4e23ac41, 0x0e7aaf38, 0x4e64ac62, 0x0ea2ac20, + 0x4eabad49, 0x0ebaf738, 0x4ebcf77a, 0x4ef2f630, + 0x2ea0effe, 0x6ea5ec83, 0x6eeced6a, 0x0fa710c5, + 0x4f8b8149, 0x4fc710c5, 0x0f8750c5, 0x4faa8128, + 0x4fc750c5, 0x2f8890e6, 0x4fa880e6, 0x6fc59083, + 0x0f6f81cd, 0x4f448862, 0x0f848062, 0x4fab8149, + 0x0e3736d5, 0x4e323630, 0x0e743672, 0x4e6d358b, + 0x0eb736d5, 0x4eb93717, 0x4eee35ac, 0x0e3c3f7a, + 0x4e393f17, 0x0e7e3fbc, 0x4e703dee, 0x0ead3d8b, + 0x4eba3f38, 0x4ee33c41, 0x2e2e8dac, 0x6e218c1f, + 0x2e6c8d6a, 0x6e728e30, 0x2ea98d07, 0x6ea48c62, + 0x6ee58c83, 0x2e2f35cd, 0x6e353693, 0x2e733651, + 0x6e723630, 0x2ea53483, 0x6ea33441, 0x6eed358b, + 0x2e203ffe, 0x6e273cc5, 0x2e6a3d28, 0x6e713e0f, + 0x2ebf3fdd, 0x6ea03ffe, 0x6ee23c20, 0x0e36e6b4, + 0x4e29e507, 0x4e76e6b4, 0x2eb9e717, 0x6ebee7bc, + 0x6ef7e6d5, 0x2e3de79b, 0x6e3be759, 0x6e67e4c5, + 0x65d23ee0, 0x65903d92, 0x65d03fa7, 0x65912fe9, + 0x65d13bf9, 0x65932a0a, 0x25cb90c4, 0x25040bde, + 0x25c11085, 0x25c62c6b, 0x259f2279, 0x259d8993, + 0x24e5102b, 0x24ad5458, 0x24ec7ab5, 0x24387c6d, + 0xba5fd3e3, 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, + 0x93df03ff, 0xc820ffff, 0x8822fc7f, 0xc8247cbf, + 0x88267fff, 0x4e010fe0, 0x5e040420, 0x4e081fe1, + 0x4e0c1fe1, 0x4e0a1fe1, 0x4e071fe1, 0x4e042c20, + 0x4e062c20, 0x4e052c20, 0x4e083c20, 0x0e0c3c20, + 0x0e0a3c20, 0x0e073c20, 0x9eae0020, 0x0f03f409, + 0x6f03f40e, 0x4cc0ac3f, 0x0ea1b820, 0x4e21c862, + 0x4e61b8a4, 0x05a08020, 0x05104fe0, 0x05505001, + 0x05906fe2, 0x05d03005, 0x05101fea, 0x05901feb, + 0x04b0e3e0, 0x0470e7e1, 0x042f9c20, 0x043f9c35, + 0x047f9c20, 0x04ff9c20, 0x04299420, 0x04319160, + 0x0461943e, 0x04a19020, 0x04038100, 0x040381a0, + 0x040387e1, 0x04438be2, 0x04c38fe3, 0x040181e0, + 0x04018100, 0x04018621, 0x04418b22, 0x04418822, + 0x04818c23, 0x040081e0, 0x04008120, 0x04008761, + 0x04008621, 0x04408822, 0x04808c23, 0x042053ff, + 0x047f5401, 0x25208028, 0x2538cfe0, 0x2578d001, + 0x25b8efe2, 0x25f8f007, 0x2538dfea, 0x25b8dfeb, + 0xa400a3e0, 0xa420a7e0, 0xa4484be0, 0xa467afe0, + 0xa4a8a7ea, 0xa547a814, 0xa4084ffe, 0xa55c53e0, + 0xa5e1540b, 0xe400fbf6, 0xe408ffff, 0xe420e7e0, + 0xe4484be0, 0xe460efe0, 0xe547e400, 0xe4014be0, + 0xe4a84fe0, 0xe5f15000, 0x858043e0, 0x85a043ff, + 0xe59f5d08, 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, + 0x04e0e3ec, 0x25104042, 0x25104871, 0x25904861, + 0x25904c92, 0x05344020, 0x05744041, 0x05b44062, + 0x05f44083, 0x252c8840, 0x253c1420, 0x25681572, + 0x25a21ce3, 0x25ea1e34, 0x253c0421, 0x25680572, + 0x25a20ce3, 0x25ea0e34, 0x0522c020, 0x05e6c0a4, + 0x2401a001, 0x2443a051, 0x24858881, 0x24c78cd1, + 0x24850891, 0x24c70cc1, 0x250f9001, 0x25508051, + 0x25802491, 0x25df28c1, 0x25850c81, 0x251e10d1, + 0x65816001, 0x65c36051, 0x65854891, 0x65c74cc1, + 0x05733820, 0x05b238a4, 0x05f138e6, 0x0570396a, + 0x65d0a001, 0x65d6a443, 0x65d4a826, 0x6594ac26, + 0x6554ac26, 0x6556ac26, 0x6552ac26, 0x65cbac85, + 0x65caac01, 0x6589ac85, 0x6588ac01, 0x65c9ac85, + 0x65c8ac01, 0x65dea833, 0x659ca509, 0x65d8a801, + 0x65dcac01, 0x655cb241, 0x0520a1e0, 0x0521a601, + 0x052281e0, 0x05238601, 0x04a14026, 0x042244a6, + 0x046344a6, 0x04a444a6, 0x04e544a7, 0x0568aca7, + 0x05b23230, 0x853040af, 0xc5b040af, 0xe57080af, + 0xe5b080af, 0x25034440, 0x254054c4, 0x25034640, + 0x25415a05, 0x25834440, 0x25c54489, 0x250b5d3a, + 0x2550dc20, 0x2518e3e1, 0x2518e021, 0x2518e0a1, + 0x2518e121, 0x2518e1a1, 0x2558e3e2, 0x2558e042, + 0x2558e0c2, 0x2558e142, 0x2598e3e3, 0x2598e063, + 0x2598e0e3, 0x2598e163, 0x25d8e3e4, 0x25d8e084, + 0x25d8e104, 0x25d8e184, 0x2518e407, 0x05214800, + 0x05614800, 0x05a14800, 0x05e14800, 0x05214c00, + 0x05614c00, 0x05a14c00, 0x05e14c00, 0x05304001, + 0x05314001, 0x05a18610, 0x05e18610, 0x05271e11, + 0x6545e891, 0x6585e891, 0x65c5e891, 0x6545c891, + 0x6585c891, 0x65c5c891, 0x45b0c210, 0x45f1c231, + 0x1e601000, 0x1e603000, 0x1e621000, 0x1e623000, + 0x1e641000, 0x1e643000, 0x1e661000, 0x1e663000, + 0x1e681000, 0x1e683000, 0x1e6a1000, 0x1e6a3000, + 0x1e6c1000, 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, + 0x1e701000, 0x1e703000, 0x1e721000, 0x1e723000, + 0x1e741000, 0x1e743000, 0x1e761000, 0x1e763000, + 0x1e781000, 0x1e783000, 0x1e7a1000, 0x1e7a3000, + 0x1e7c1000, 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, + 0xf8338131, 0xf83c01fb, 0xf82712f5, 0xf83f2059, + 0xf83f31fb, 0xf82a5277, 0xf8234010, 0xf83972fa, + 0xf8226190, 0xf8a483dc, 0xf8bd0370, 0xf8a613a9, + 0xf8b02087, 0xf8a7312f, 0xf8b75048, 0xf8bc43f5, + 0xf8a5701b, 0xf8b1608f, 0xf8fa8388, 0xf8f6037b, + 0xf8f91017, 0xf8e421e6, 0xf8e031e4, 0xf8e150ea, + 0xf8e5438a, 0xf8e772f4, 0xf8f56166, 0xf86883f1, + 0xf8660051, 0xf86c13be, 0xf86322db, 0xf87d31ae, + 0xf87c5311, 0xf86541c2, 0xf86a7170, 0xf87b6197, + 0xb8248236, 0xb8240261, 0xb83011b0, 0xb82e204c, + 0xb83132a3, 0xb83750c5, 0xb82741b3, 0xb83c7211, + 0xb82663a2, 0xb8a380c4, 0xb8b001b4, 0xb8ac1114, + 0xb8b92274, 0xb8a0330b, 0xb8a653f4, 0xb8ae40d0, + 0xb8a071e7, 0xb8b3613a, 0xb8ea82b7, 0xb8f6005c, + 0xb8e3126f, 0xb8f42087, 0xb8fd3007, 0xb8e95290, + 0xb8f74204, 0xb8ea7177, 0xb8f963e6, 0xb87082ed, + 0xb86c01c1, 0xb8691215, 0xb87a208f, 0xb8643110, + 0xb866509e, 0xb87d43b1, 0xb87a71e9, 0xb86263ab, + 0xce216ce3, 0xce0e2255, 0xce798ed2, 0xce959685, + 0xce7e8217, 0xce608694, 0xcec08264, 0xce748898, + 0x25e0da44, 0x2521c8f3, 0x05801548, 0x0540cbdf, + 0x05006521, 0x2560c7a0, 0x25a1c498, 0x058026bb, + 0x05407dd8, 0x0500f3d6, 0x2560ce3d, 0x2521d4b4, + 0x05803cbc, 0x05404d6c, 0x05001b89, 0x25a0c532, + 0x2521cc40, 0x05800c08, 0x054074c4, 0x050034a0, + 0x2520c9e3, 0x25e1ca93, 0x05803e98, 0x05425238, + 0x050024cb, 0x25a0ce7f, 0x25e1d0c3, 0x05802676, + 0x05401e63, 0x05002d49, 0x04e20080, 0x04ab04ce, + 0x659e022e, 0x65970863, 0x659c0703, 0x04d6b4f3, + 0x04400cb5, 0x049a06da, 0x04508071, 0x045b0d14, + 0x0459b22e, 0x04daba4d, 0x04590a13, 0x0493979b, + 0x04d188a8, 0x0450081c, 0x0417b6b9, 0x041eb743, + 0x04981e7a, 0x05e78dc1, 0x0564824e, 0x048816ff, + 0x040a0d1e, 0x04810ee0, 0x04dcb340, 0x65c08ed8, + 0x65cd8162, 0x65c6970c, 0x65c79e29, 0x65c29494, + 0x04ddbecd, 0x65c2ba5f, 0x65c0a9af, 0x6581a434, + 0x658da0ee, 0x65c1908c, 0x65be806f, 0x65ff0694, + 0x65ee2d2d, 0x65a3af81, 0x65a9cb3a, 0x65e1e9da, + 0x65f447ba, 0x65e17da6, 0x0401482b, 0x040279fb, + 0x0439323e, 0x04a33302, 0x046331bd, 0x04fc320e, + 0x05bb6964, 0x05e16e02, 0x65c897e7, 0x4596b150, + 0x4516b4fd, 0x0438396c, 0x041a280b, 0x04183697, + 0x04192de3, 0x04083b7e, 0x04ca3955, 0x65873883, + 0x658622a6, 0x65d83bd9, 0x0441303f, 0x0e2e11ac, + 0x4e2013fe, 0x0e6f11cd, 0x4e6a1128, 0x0ebb1359, + 0x4ebf13dd, 0x2e231041, 0x6e21101f, 0x2e791317, + 0x6e61101f, 0x2eb612b4, 0x6ea21020, }; // END Generated code -- do not edit From f3671beefb3ff07441a905e25619f0d1a0a2fe15 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 5 Nov 2024 11:46:40 +0000 Subject: [PATCH 03/23] 8335392: C2 MergeStores: enhanced pointer parsing Co-authored-by: Christian Hagedorn Reviewed-by: kvn, chagedorn --- .../share/compiler/compilerDirectives.cpp | 16 +- .../share/compiler/compilerDirectives.hpp | 8 + src/hotspot/share/compiler/compilerOracle.cpp | 7 + src/hotspot/share/compiler/compilerOracle.hpp | 1 + .../share/compiler/directivesParser.cpp | 10 + src/hotspot/share/opto/c2_globals.hpp | 3 - src/hotspot/share/opto/memnode.cpp | 335 +++------- src/hotspot/share/opto/mempointer.cpp | 383 +++++++++++ src/hotspot/share/opto/mempointer.hpp | 618 ++++++++++++++++++ src/hotspot/share/opto/noOverflowInt.hpp | 114 ++++ .../share/opto/traceMergeStoresTag.hpp | 138 ++++ .../gtest/opto/test_no_overflow_int.cpp | 175 +++++ .../jtreg/compiler/c2/TestMergeStores.java | 255 +++++++- .../c2/TestMergeStoresMemorySegment.java | 426 ++++++++++++ .../c2/TestMergeStoresUnsafeArrayPointer.java | 192 ++++++ .../bench/vm/compiler/MergeStores.java | 64 +- 16 files changed, 2475 insertions(+), 270 deletions(-) create mode 100644 src/hotspot/share/opto/mempointer.cpp create mode 100644 src/hotspot/share/opto/mempointer.hpp create mode 100644 src/hotspot/share/opto/noOverflowInt.hpp create mode 100644 src/hotspot/share/opto/traceMergeStoresTag.hpp create mode 100644 test/hotspot/gtest/opto/test_no_overflow_int.cpp create mode 100644 test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index 74259c8e5d4..46750cacc35 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -33,6 +33,7 @@ #include "memory/resourceArea.hpp" #include "opto/phasetype.hpp" #include "opto/traceAutoVectorizationTag.hpp" +#include "opto/traceMergeStoresTag.hpp" #include "runtime/globals_extension.hpp" CompilerDirectives::CompilerDirectives() : _next(nullptr), _match(nullptr), _ref_count(0) { @@ -302,7 +303,8 @@ DirectiveSet::DirectiveSet(CompilerDirectives* d) : _inlinematchers(nullptr), _directive(d), _ideal_phase_name_set(PHASE_NUM_TYPES, mtCompiler), - _trace_auto_vectorization_tags(TRACE_AUTO_VECTORIZATION_TAG_NUM, mtCompiler) + _trace_auto_vectorization_tags(TRACE_AUTO_VECTORIZATION_TAG_NUM, mtCompiler), + _trace_merge_stores_tags(TraceMergeStores::TAG_NUM, mtCompiler) { #define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue; compilerdirectives_common_flags(init_defaults_definition) @@ -432,7 +434,6 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle compilerdirectives_c1_flags(init_default_cc) #undef init_default_cc - // Parse PrintIdealPhaseName and create a lookup set #ifndef PRODUCT #ifdef COMPILER2 if (!_modified[TraceAutoVectorizationIndex]) { @@ -445,6 +446,17 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle } } } + if (!_modified[TraceMergeStoresIndex]) { + // Parse ccstr and create mask + ccstrlist option; + if (CompilerOracle::has_option_value(method, CompileCommandEnum::TraceMergeStores, option)) { + TraceMergeStores::TagValidator validator(option, false); + if (validator.is_valid()) { + set.cloned()->set_trace_merge_stores_tags(validator.tags()); + } + } + } + // Parse PrintIdealPhaseName and create a lookup set if (!_modified[PrintIdealPhaseIndex]) { // Parse ccstr and create set ccstrlist option; diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index bf15fe9c713..e960fdb1e53 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -90,6 +90,7 @@ NOT_PRODUCT(cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLeve cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) #define compilerdirectives_c2_string_flags(cflags) \ NOT_PRODUCT(cflags(TraceAutoVectorization, ccstrlist, "", TraceAutoVectorization)) \ +NOT_PRODUCT(cflags(TraceMergeStores, ccstrlist, "", TraceMergeStores)) \ NOT_PRODUCT(cflags(PrintIdealPhase, ccstrlist, "", PrintIdealPhase)) #else #define compilerdirectives_c2_other_flags(cflags) @@ -131,6 +132,7 @@ class DirectiveSet : public CHeapObj { TriBoolArray<(size_t)vmIntrinsics::number_of_intrinsics(), int> _intrinsic_control_words; CHeapBitMap _ideal_phase_name_set; CHeapBitMap _trace_auto_vectorization_tags; + CHeapBitMap _trace_merge_stores_tags; public: DirectiveSet(CompilerDirectives* directive); @@ -211,6 +213,12 @@ void set_##name(void* value) { \ const CHeapBitMap& trace_auto_vectorization_tags() { return _trace_auto_vectorization_tags; }; + void set_trace_merge_stores_tags(const CHeapBitMap& tags) { + _trace_merge_stores_tags.set_from(tags); + }; + const CHeapBitMap& trace_merge_stores_tags() { + return _trace_merge_stores_tags; + }; void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } } void print_uintx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" UINTX_FORMAT " ", n, v); } } diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp index d0479f3fdbb..107350794a0 100644 --- a/src/hotspot/share/compiler/compilerOracle.cpp +++ b/src/hotspot/share/compiler/compilerOracle.cpp @@ -36,6 +36,7 @@ #include "oops/symbol.hpp" #include "opto/phasetype.hpp" #include "opto/traceAutoVectorizationTag.hpp" +#include "opto/traceMergeStoresTag.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" @@ -802,6 +803,12 @@ static void scan_value(enum OptionType type, char* line, int& total_bytes_read, else if (option == CompileCommandEnum::TraceAutoVectorization) { TraceAutoVectorizationTagValidator validator(value, true); + if (!validator.is_valid()) { + jio_snprintf(errorbuf, buf_size, "Unrecognized tag name in %s: %s", option2name(option), validator.what()); + } + } else if (option == CompileCommandEnum::TraceMergeStores) { + TraceMergeStores::TagValidator validator(value, true); + if (!validator.is_valid()) { jio_snprintf(errorbuf, buf_size, "Unrecognized tag name in %s: %s", option2name(option), validator.what()); } diff --git a/src/hotspot/share/compiler/compilerOracle.hpp b/src/hotspot/share/compiler/compilerOracle.hpp index 5864ca5dc0d..0e55ca416e0 100644 --- a/src/hotspot/share/compiler/compilerOracle.hpp +++ b/src/hotspot/share/compiler/compilerOracle.hpp @@ -86,6 +86,7 @@ NOT_PRODUCT(option(PrintIdeal, "PrintIdeal", Bool)) \ NOT_PRODUCT(option(PrintIdealPhase, "PrintIdealPhase", Ccstrlist)) \ NOT_PRODUCT(option(IGVPrintLevel, "IGVPrintLevel", Intx)) \ NOT_PRODUCT(option(TraceAutoVectorization, "TraceAutoVectorization", Ccstrlist)) \ +NOT_PRODUCT(option(TraceMergeStores, "TraceMergeStores", Ccstrlist)) \ option(Vectorize, "Vectorize", Bool) \ option(CloneMapDebug, "CloneMapDebug", Bool) \ option(IncrementalInlineForceCleanup, "IncrementalInlineForceCleanup", Bool) \ diff --git a/src/hotspot/share/compiler/directivesParser.cpp b/src/hotspot/share/compiler/directivesParser.cpp index 55014900283..731bf33d799 100644 --- a/src/hotspot/share/compiler/directivesParser.cpp +++ b/src/hotspot/share/compiler/directivesParser.cpp @@ -29,6 +29,7 @@ #include "memory/resourceArea.hpp" #include "opto/phasetype.hpp" #include "opto/traceAutoVectorizationTag.hpp" +#include "opto/traceMergeStoresTag.hpp" #include "runtime/os.hpp" #include @@ -347,6 +348,15 @@ bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* opti } else { error(VALUE_ERROR, "Unrecognized tag name detected in TraceAutoVectorization: %s", validator.what()); } + } else if (strncmp(option_key->name, "TraceMergeStores", 16) == 0) { + TraceMergeStores::TagValidator validator(s, false); + + valid = validator.is_valid(); + if (valid) { + set->set_trace_merge_stores_tags(validator.tags()); + } else { + error(VALUE_ERROR, "Unrecognized tag name detected in TraceMergeStores: %s", validator.what()); + } } else if (strncmp(option_key->name, "PrintIdealPhase", 15) == 0) { PhaseNameValidator validator(s); diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index c14162ddf6e..7f6b7c2dceb 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -367,9 +367,6 @@ product(bool, MergeStores, true, DIAGNOSTIC, \ "Optimize stores by combining values into larger store") \ \ - develop(bool, TraceMergeStores, false, \ - "Trace creation of merged stores") \ - \ product_pd(bool, OptoBundling, \ "Generate nops to fill i-cache lines") \ \ diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 27c0d16fac1..919d23fea8d 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -43,11 +43,13 @@ #include "opto/machnode.hpp" #include "opto/matcher.hpp" #include "opto/memnode.hpp" +#include "opto/mempointer.hpp" #include "opto/mulnode.hpp" #include "opto/narrowptrnode.hpp" #include "opto/phaseX.hpp" #include "opto/regmask.hpp" #include "opto/rootnode.hpp" +#include "opto/traceMergeStoresTag.hpp" #include "opto/vectornode.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" @@ -2738,184 +2740,6 @@ uint StoreNode::hash() const { return NO_HASH; } -// Class to parse array pointers, and determine if they are adjacent. We parse the form: -// -// pointer = base -// + constant_offset -// + LShiftL( ConvI2L(int_offset + int_con), int_offset_shift) -// + sum(other_offsets) -// -// -// Note: we accumulate all constant offsets into constant_offset, even the int constant behind -// the "LShiftL(ConvI2L(...))" pattern. We convert "ConvI2L(int_offset + int_con)" to -// "ConvI2L(int_offset) + int_con", which is only safe if we can assume that either all -// compared addresses have an overflow for "int_offset + int_con" or none. -// For loads and stores on arrays, we know that if one overflows and the other not, then -// the two addresses lay almost max_int indices apart, but the maximal array size is -// only about half of that. Therefore, the RangeCheck on at least one of them must have -// failed. -// -// constant_offset += LShiftL( ConvI2L(int_con), int_offset_shift) -// -// pointer = base -// + constant_offset -// + LShiftL( ConvI2L(int_offset), int_offset_shift) -// + sum(other_offsets) -// -class ArrayPointer { -private: - const Node* _pointer; // The final pointer to the position in the array - const Node* _base; // Base address of the array - const jlong _constant_offset; // Sum of collected constant offsets - const Node* _int_offset; // (optional) Offset behind LShiftL and ConvI2L - const GrowableArray* _other_offsets; // List of other AddP offsets - const jint _int_offset_shift; // (optional) Shift value for int_offset - const bool _is_valid; // The parsing succeeded - - ArrayPointer(const bool is_valid, - const Node* pointer, - const Node* base, - const jlong constant_offset, - const Node* int_offset, - const jint int_offset_shift, - const GrowableArray* other_offsets) : - _pointer(pointer), - _base(base), - _constant_offset(constant_offset), - _int_offset(int_offset), - _other_offsets(other_offsets), - _int_offset_shift(int_offset_shift), - _is_valid(is_valid) - { - assert(_pointer != nullptr, "must always have pointer"); - assert(is_valid == (_base != nullptr), "have base exactly if valid"); - assert(is_valid == (_other_offsets != nullptr), "have other_offsets exactly if valid"); - } - - static ArrayPointer make_invalid(const Node* pointer) { - return ArrayPointer(false, pointer, nullptr, 0, nullptr, 0, nullptr); - } - - static bool parse_int_offset(Node* offset, Node*& int_offset, jint& int_offset_shift) { - // offset = LShiftL( ConvI2L(int_offset), int_offset_shift) - if (offset->Opcode() == Op_LShiftL && - offset->in(1)->Opcode() == Op_ConvI2L && - offset->in(2)->Opcode() == Op_ConI) { - int_offset = offset->in(1)->in(1); // LShiftL -> ConvI2L -> int_offset - int_offset_shift = offset->in(2)->get_int(); // LShiftL -> int_offset_shift - return true; - } - - // offset = ConvI2L(int_offset) = LShiftL( ConvI2L(int_offset), 0) - if (offset->Opcode() == Op_ConvI2L) { - int_offset = offset->in(1); - int_offset_shift = 0; - return true; - } - - // parse failed - return false; - } - -public: - // Parse the structure above the pointer - static ArrayPointer make(PhaseGVN* phase, const Node* pointer) { - assert(phase->type(pointer)->isa_aryptr() != nullptr, "must be array pointer"); - if (!pointer->is_AddP()) { return ArrayPointer::make_invalid(pointer); } - - const Node* base = pointer->in(AddPNode::Base); - if (base == nullptr) { return ArrayPointer::make_invalid(pointer); } - - const int search_depth = 5; - Node* offsets[search_depth]; - int count = pointer->as_AddP()->unpack_offsets(offsets, search_depth); - - // We expect at least a constant each - if (count <= 0) { return ArrayPointer::make_invalid(pointer); } - - // We extract the form: - // - // pointer = base - // + constant_offset - // + LShiftL( ConvI2L(int_offset + int_con), int_offset_shift) - // + sum(other_offsets) - // - jlong constant_offset = 0; - Node* int_offset = nullptr; - jint int_offset_shift = 0; - GrowableArray* other_offsets = new GrowableArray(count); - - for (int i = 0; i < count; i++) { - Node* offset = offsets[i]; - if (offset->Opcode() == Op_ConI) { - // Constant int offset - constant_offset += offset->get_int(); - } else if (offset->Opcode() == Op_ConL) { - // Constant long offset - constant_offset += offset->get_long(); - } else if(int_offset == nullptr && parse_int_offset(offset, int_offset, int_offset_shift)) { - // LShiftL( ConvI2L(int_offset), int_offset_shift) - int_offset = int_offset->uncast(); - if (int_offset->Opcode() == Op_AddI && int_offset->in(2)->Opcode() == Op_ConI) { - // LShiftL( ConvI2L(int_offset + int_con), int_offset_shift) - constant_offset += ((jlong)int_offset->in(2)->get_int()) << int_offset_shift; - int_offset = int_offset->in(1); - } - } else { - // All others - other_offsets->append(offset); - } - } - - return ArrayPointer(true, pointer, base, constant_offset, int_offset, int_offset_shift, other_offsets); - } - - bool is_adjacent_to_and_before(const ArrayPointer& other, const jlong data_size) const { - if (!_is_valid || !other._is_valid) { return false; } - - // Offset adjacent? - if (this->_constant_offset + data_size != other._constant_offset) { return false; } - - // All other components identical? - if (this->_base != other._base || - this->_int_offset != other._int_offset || - this->_int_offset_shift != other._int_offset_shift || - this->_other_offsets->length() != other._other_offsets->length()) { - return false; - } - - for (int i = 0; i < this->_other_offsets->length(); i++) { - Node* o1 = this->_other_offsets->at(i); - Node* o2 = other._other_offsets->at(i); - if (o1 != o2) { return false; } - } - - return true; - } - -#ifndef PRODUCT - void dump() { - if (!_is_valid) { - tty->print("ArrayPointer[%d %s, invalid]", _pointer->_idx, _pointer->Name()); - return; - } - tty->print("ArrayPointer[%d %s, base[%d %s] + %lld", - _pointer->_idx, _pointer->Name(), - _base->_idx, _base->Name(), - (long long)_constant_offset); - if (_int_offset != nullptr) { - tty->print(" + I2L[%d %s] << %d", - _int_offset->_idx, _int_offset->Name(), _int_offset_shift); - } - for (int i = 0; i < _other_offsets->length(); i++) { - Node* n = _other_offsets->at(i); - tty->print(" + [%d %s]", n->_idx, n->Name()); - } - tty->print_cr("]"); - } -#endif -}; - // Link together multiple stores (B/S/C/I) into a longer one. // // Example: _store = StoreB[i+3] @@ -2951,13 +2775,18 @@ class ArrayPointer { // of adjacent stores there remains exactly one RangeCheck, located between the // first and the second store (e.g. RangeCheck[i+3]). // -class MergePrimitiveArrayStores : public StackObj { +class MergePrimitiveStores : public StackObj { private: - PhaseGVN* _phase; - StoreNode* _store; + PhaseGVN* const _phase; + StoreNode* const _store; + + NOT_PRODUCT( const CHeapBitMap &_trace_tags; ) public: - MergePrimitiveArrayStores(PhaseGVN* phase, StoreNode* store) : _phase(phase), _store(store) {} + MergePrimitiveStores(PhaseGVN* phase, StoreNode* store) : + _phase(phase), _store(store) + NOT_PRODUCT( COMMA _trace_tags(Compile::current()->directive()->trace_merge_stores_tags()) ) + {} StoreNode* run(); @@ -2988,6 +2817,17 @@ class MergePrimitiveArrayStores : public StackObj { } return Status(found_store, cfg_status == CFGStatus::SuccessWithRangeCheck); } + +#ifndef PRODUCT + void print_on(outputStream* st) const { + if (_found_store == nullptr) { + st->print_cr("None"); + } else { + st->print_cr("Found[%d %s, %s]", _found_store->_idx, _found_store->Name(), + _found_range_check ? "RC" : "no-RC"); + } + } +#endif }; Status find_adjacent_use_store(const StoreNode* def_store) const; @@ -3001,43 +2841,56 @@ class MergePrimitiveArrayStores : public StackObj { Node* make_merged_input_value(const Node_List& merge_list); StoreNode* make_merged_store(const Node_List& merge_list, Node* merged_input_value); - DEBUG_ONLY( void trace(const Node_List& merge_list, const Node* merged_input_value, const StoreNode* merged_store) const; ) -}; +#ifndef PRODUCT + // Access to TraceMergeStores tags + bool is_trace(TraceMergeStores::Tag tag) const { + return _trace_tags.at(tag); + } -StoreNode* MergePrimitiveArrayStores::run() { - // Check for B/S/C/I - int opc = _store->Opcode(); - if (opc != Op_StoreB && opc != Op_StoreC && opc != Op_StoreI) { - return nullptr; + bool is_trace_basic() const { + return is_trace(TraceMergeStores::Tag::BASIC); } - // Only merge stores on arrays, and the stores must have the same size as the elements. - const TypePtr* ptr_t = _store->adr_type(); - if (ptr_t == nullptr) { - return nullptr; + bool is_trace_pointer() const { + return is_trace(TraceMergeStores::Tag::POINTER); } - const TypeAryPtr* aryptr_t = ptr_t->isa_aryptr(); - if (aryptr_t == nullptr) { - return nullptr; + + bool is_trace_aliasing() const { + return is_trace(TraceMergeStores::Tag::ALIASING); } - BasicType bt = aryptr_t->elem()->array_element_basic_type(); - if (!is_java_primitive(bt) || - type2aelembytes(bt) != _store->memory_size()) { - return nullptr; + + bool is_trace_adjacency() const { + return is_trace(TraceMergeStores::Tag::ADJACENCY); + } + + bool is_trace_success() const { + return is_trace(TraceMergeStores::Tag::SUCCESS); } - if (_store->is_unsafe_access()) { +#endif + + NOT_PRODUCT( void trace(const Node_List& merge_list, const Node* merged_input_value, const StoreNode* merged_store) const; ) +}; + +StoreNode* MergePrimitiveStores::run() { + // Check for B/S/C/I + int opc = _store->Opcode(); + if (opc != Op_StoreB && opc != Op_StoreC && opc != Op_StoreI) { return nullptr; } + NOT_PRODUCT( if (is_trace_basic()) { tty->print("[TraceMergeStores] MergePrimitiveStores::run: "); _store->dump(); }) + // The _store must be the "last" store in a chain. If we find a use we could merge with // then that use or a store further down is the "last" store. Status status_use = find_adjacent_use_store(_store); + NOT_PRODUCT( if (is_trace_basic()) { tty->print("[TraceMergeStores] expect no use: "); status_use.print_on(tty); }) if (status_use.found_store() != nullptr) { return nullptr; } // Check if we can merge with at least one def, so that we have at least 2 stores to merge. Status status_def = find_adjacent_def_store(_store); + NOT_PRODUCT( if (is_trace_basic()) { tty->print("[TraceMergeStores] expect def: "); status_def.print_on(tty); }) if (status_def.found_store() == nullptr) { return nullptr; } @@ -3051,45 +2904,25 @@ StoreNode* MergePrimitiveArrayStores::run() { StoreNode* merged_store = make_merged_store(merge_list, merged_input_value); - DEBUG_ONLY( if(TraceMergeStores) { trace(merge_list, merged_input_value, merged_store); } ) + NOT_PRODUCT( if (is_trace_success()) { trace(merge_list, merged_input_value, merged_store); } ) return merged_store; } // Check compatibility between _store and other_store. -bool MergePrimitiveArrayStores::is_compatible_store(const StoreNode* other_store) const { +bool MergePrimitiveStores::is_compatible_store(const StoreNode* other_store) const { int opc = _store->Opcode(); assert(opc == Op_StoreB || opc == Op_StoreC || opc == Op_StoreI, "precondition"); - assert(_store->adr_type()->isa_aryptr() != nullptr, "must be array store"); - assert(!_store->is_unsafe_access(), "no unsafe accesses"); if (other_store == nullptr || - _store->Opcode() != other_store->Opcode() || - other_store->adr_type() == nullptr || - other_store->adr_type()->isa_aryptr() == nullptr || - other_store->is_unsafe_access()) { + _store->Opcode() != other_store->Opcode()) { return false; } - // Check that the size of the stores, and the array elements are all the same. - const TypeAryPtr* aryptr_t1 = _store->adr_type()->is_aryptr(); - const TypeAryPtr* aryptr_t2 = other_store->adr_type()->is_aryptr(); - BasicType aryptr_bt1 = aryptr_t1->elem()->array_element_basic_type(); - BasicType aryptr_bt2 = aryptr_t2->elem()->array_element_basic_type(); - if (!is_java_primitive(aryptr_bt1) || !is_java_primitive(aryptr_bt2)) { - return false; - } - int size1 = type2aelembytes(aryptr_bt1); - int size2 = type2aelembytes(aryptr_bt2); - if (size1 != size2 || - size1 != _store->memory_size() || - _store->memory_size() != other_store->memory_size()) { - return false; - } return true; } -bool MergePrimitiveArrayStores::is_adjacent_pair(const StoreNode* use_store, const StoreNode* def_store) const { +bool MergePrimitiveStores::is_adjacent_pair(const StoreNode* use_store, const StoreNode* def_store) const { if (!is_adjacent_input_pair(def_store->in(MemNode::ValueIn), use_store->in(MemNode::ValueIn), def_store->memory_size())) { @@ -3097,16 +2930,17 @@ bool MergePrimitiveArrayStores::is_adjacent_pair(const StoreNode* use_store, con } ResourceMark rm; - ArrayPointer array_pointer_use = ArrayPointer::make(_phase, use_store->in(MemNode::Address)); - ArrayPointer array_pointer_def = ArrayPointer::make(_phase, def_store->in(MemNode::Address)); - if (!array_pointer_def.is_adjacent_to_and_before(array_pointer_use, use_store->memory_size())) { - return false; - } - - return true; +#ifndef PRODUCT + const TraceMemPointer trace(is_trace_pointer(), + is_trace_aliasing(), + is_trace_adjacency()); +#endif + const MemPointer pointer_use(use_store NOT_PRODUCT( COMMA trace )); + const MemPointer pointer_def(def_store NOT_PRODUCT( COMMA trace )); + return pointer_def.is_adjacent_to_and_before(pointer_use); } -bool MergePrimitiveArrayStores::is_adjacent_input_pair(const Node* n1, const Node* n2, const int memory_size) const { +bool MergePrimitiveStores::is_adjacent_input_pair(const Node* n1, const Node* n2, const int memory_size) const { // Pattern: [n1 = ConI, n2 = ConI] if (n1->Opcode() == Op_ConI) { return n2->Opcode() == Op_ConI; @@ -3148,7 +2982,7 @@ bool MergePrimitiveArrayStores::is_adjacent_input_pair(const Node* n1, const Nod } // Detect pattern: n = base_out >> shift_out -bool MergePrimitiveArrayStores::is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out) { +bool MergePrimitiveStores::is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out) { assert(n != nullptr, "precondition"); int opc = n->Opcode(); @@ -3171,7 +3005,7 @@ bool MergePrimitiveArrayStores::is_con_RShift(const Node* n, Node const*& base_o } // Check if there is nothing between the two stores, except optionally a RangeCheck leading to an uncommon trap. -MergePrimitiveArrayStores::CFGStatus MergePrimitiveArrayStores::cfg_status_for_pair(const StoreNode* use_store, const StoreNode* def_store) { +MergePrimitiveStores::CFGStatus MergePrimitiveStores::cfg_status_for_pair(const StoreNode* use_store, const StoreNode* def_store) { assert(use_store->in(MemNode::Memory) == def_store, "use-def relationship"); Node* ctrl_use = use_store->in(MemNode::Control); @@ -3216,7 +3050,7 @@ MergePrimitiveArrayStores::CFGStatus MergePrimitiveArrayStores::cfg_status_for_p return CFGStatus::SuccessWithRangeCheck; } -MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_adjacent_use_store(const StoreNode* def_store) const { +MergePrimitiveStores::Status MergePrimitiveStores::find_adjacent_use_store(const StoreNode* def_store) const { Status status_use = find_use_store(def_store); StoreNode* use_store = status_use.found_store(); if (use_store != nullptr && !is_adjacent_pair(use_store, def_store)) { @@ -3225,7 +3059,7 @@ MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_adjacent_use_s return status_use; } -MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_adjacent_def_store(const StoreNode* use_store) const { +MergePrimitiveStores::Status MergePrimitiveStores::find_adjacent_def_store(const StoreNode* use_store) const { Status status_def = find_def_store(use_store); StoreNode* def_store = status_def.found_store(); if (def_store != nullptr && !is_adjacent_pair(use_store, def_store)) { @@ -3234,7 +3068,7 @@ MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_adjacent_def_s return status_def; } -MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_use_store(const StoreNode* def_store) const { +MergePrimitiveStores::Status MergePrimitiveStores::find_use_store(const StoreNode* def_store) const { Status status_use = find_use_store_unidirectional(def_store); #ifdef ASSERT @@ -3250,7 +3084,7 @@ MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_use_store(cons return status_use; } -MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_def_store(const StoreNode* use_store) const { +MergePrimitiveStores::Status MergePrimitiveStores::find_def_store(const StoreNode* use_store) const { Status status_def = find_def_store_unidirectional(use_store); #ifdef ASSERT @@ -3266,7 +3100,7 @@ MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_def_store(cons return status_def; } -MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_use_store_unidirectional(const StoreNode* def_store) const { +MergePrimitiveStores::Status MergePrimitiveStores::find_use_store_unidirectional(const StoreNode* def_store) const { assert(is_compatible_store(def_store), "precondition: must be compatible with _store"); for (DUIterator_Fast imax, i = def_store->fast_outs(imax); i < imax; i++) { @@ -3279,7 +3113,7 @@ MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_use_store_unid return Status::make_failure(); } -MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_def_store_unidirectional(const StoreNode* use_store) const { +MergePrimitiveStores::Status MergePrimitiveStores::find_def_store_unidirectional(const StoreNode* use_store) const { assert(is_compatible_store(use_store), "precondition: must be compatible with _store"); StoreNode* def_store = use_store->in(MemNode::Memory)->isa_Store(); @@ -3290,7 +3124,7 @@ MergePrimitiveArrayStores::Status MergePrimitiveArrayStores::find_def_store_unid return Status::make(def_store, cfg_status_for_pair(use_store, def_store)); } -void MergePrimitiveArrayStores::collect_merge_list(Node_List& merge_list) const { +void MergePrimitiveStores::collect_merge_list(Node_List& merge_list) const { // The merged store can be at most 8 bytes. const uint merge_list_max_size = 8 / _store->memory_size(); assert(merge_list_max_size >= 2 && @@ -3303,25 +3137,32 @@ void MergePrimitiveArrayStores::collect_merge_list(Node_List& merge_list) const merge_list.push(current); while (current != nullptr && merge_list.size() < merge_list_max_size) { Status status = find_adjacent_def_store(current); + NOT_PRODUCT( if (is_trace_basic()) { tty->print("[TraceMergeStores] find def: "); status.print_on(tty); }) + current = status.found_store(); if (current != nullptr) { merge_list.push(current); // We can have at most one RangeCheck. if (status.found_range_check()) { + NOT_PRODUCT( if (is_trace_basic()) { tty->print_cr("[TraceMergeStores] found RangeCheck, stop traversal."); }) break; } } } + NOT_PRODUCT( if (is_trace_basic()) { tty->print_cr("[TraceMergeStores] found:"); merge_list.dump(); }) + // Truncate the merge_list to a power of 2. const uint pow2size = round_down_power_of_2(merge_list.size()); assert(pow2size >= 2, "must be merging at least 2 stores"); while (merge_list.size() > pow2size) { merge_list.pop(); } + + NOT_PRODUCT( if (is_trace_basic()) { tty->print_cr("[TraceMergeStores] truncated:"); merge_list.dump(); }) } // Merge the input values of the smaller stores to a single larger input value. -Node* MergePrimitiveArrayStores::make_merged_input_value(const Node_List& merge_list) { +Node* MergePrimitiveStores::make_merged_input_value(const Node_List& merge_list) { int new_memory_size = _store->memory_size() * merge_list.size(); Node* first = merge_list.at(merge_list.size()-1); Node* merged_input_value = nullptr; @@ -3407,7 +3248,7 @@ Node* MergePrimitiveArrayStores::make_merged_input_value(const Node_List& merge_ // | | | | | | | | // // last_store (= _store) merged_store // // // -StoreNode* MergePrimitiveArrayStores::make_merged_store(const Node_List& merge_list, Node* merged_input_value) { +StoreNode* MergePrimitiveStores::make_merged_store(const Node_List& merge_list, Node* merged_input_value) { Node* first_store = merge_list.at(merge_list.size()-1); Node* last_ctrl = _store->in(MemNode::Control); // after (optional) RangeCheck Node* first_mem = first_store->in(MemNode::Memory); @@ -3436,8 +3277,8 @@ StoreNode* MergePrimitiveArrayStores::make_merged_store(const Node_List& merge_l return merged_store; } -#ifdef ASSERT -void MergePrimitiveArrayStores::trace(const Node_List& merge_list, const Node* merged_input_value, const StoreNode* merged_store) const { +#ifndef PRODUCT +void MergePrimitiveStores::trace(const Node_List& merge_list, const Node* merged_input_value, const StoreNode* merged_store) const { stringStream ss; ss.print_cr("[TraceMergeStores]: Replace"); for (int i = (int)merge_list.size() - 1; i >= 0; i--) { @@ -3535,7 +3376,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (MergeStores && UseUnalignedAccesses) { if (phase->C->post_loop_opts_phase()) { - MergePrimitiveArrayStores merge(phase, this); + MergePrimitiveStores merge(phase, this); Node* progress = merge.run(); if (progress != nullptr) { return progress; } } else { diff --git a/src/hotspot/share/opto/mempointer.cpp b/src/hotspot/share/opto/mempointer.cpp new file mode 100644 index 00000000000..df443c69449 --- /dev/null +++ b/src/hotspot/share/opto/mempointer.cpp @@ -0,0 +1,383 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "opto/mempointer.hpp" +#include "utilities/resourceHash.hpp" + +// Recursively parse the pointer expression with a DFS all-path traversal +// (i.e. with node repetitions), starting at the pointer. +MemPointerDecomposedForm MemPointerDecomposedFormParser::parse_decomposed_form() { + assert(_worklist.is_empty(), "no prior parsing"); + assert(_summands.is_empty(), "no prior parsing"); + + Node* pointer = _mem->in(MemNode::Address); + + // Start with the trivial summand. + _worklist.push(MemPointerSummand(pointer, NoOverflowInt(1))); + + // Decompose the summands until only terminal summands remain. This effectively + // parses the pointer expression recursively. + int traversal_count = 0; + while (_worklist.is_nonempty()) { + // Bail out if the graph is too complex. + if (traversal_count++ > 1000) { return MemPointerDecomposedForm::make_trivial(pointer); } + parse_sub_expression(_worklist.pop()); + } + + // Bail out if there is a constant overflow. + if (_con.is_NaN()) { return MemPointerDecomposedForm::make_trivial(pointer); } + + // Sorting by variable idx means that all summands with the same variable are consecutive. + // This simplifies the combining of summands with the same variable below. + _summands.sort(MemPointerSummand::cmp_by_variable_idx); + + // Combine summands for the same variable, adding up the scales. + int pos_put = 0; + int pos_get = 0; + while (pos_get < _summands.length()) { + const MemPointerSummand& summand = _summands.at(pos_get++); + Node* variable = summand.variable(); + NoOverflowInt scale = summand.scale(); + // Add up scale of all summands with the same variable. + while (pos_get < _summands.length() && _summands.at(pos_get).variable() == variable) { + MemPointerSummand s = _summands.at(pos_get++); + scale = scale + s.scale(); + } + // Bail out if scale is NaN. + if (scale.is_NaN()) { + return MemPointerDecomposedForm::make_trivial(pointer); + } + // Keep summands with non-zero scale. + if (!scale.is_zero()) { + _summands.at_put(pos_put++, MemPointerSummand(variable, scale)); + } + } + _summands.trunc_to(pos_put); + + return MemPointerDecomposedForm::make(pointer, _summands, _con); +} + +// Parse a sub-expression of the pointer, starting at the current summand. We parse the +// current node, and see if it can be decomposed into further summands, or if the current +// summand is terminal. +void MemPointerDecomposedFormParser::parse_sub_expression(const MemPointerSummand& summand) { + Node* n = summand.variable(); + const NoOverflowInt scale = summand.scale(); + const NoOverflowInt one(1); + + int opc = n->Opcode(); + if (is_safe_to_decompose_op(opc, scale)) { + switch (opc) { + case Op_ConI: + case Op_ConL: + { + // Terminal: add to constant. + NoOverflowInt con = (opc == Op_ConI) ? NoOverflowInt(n->get_int()) + : NoOverflowInt(n->get_long()); + _con = _con + scale * con; + return; + } + case Op_AddP: + case Op_AddL: + case Op_AddI: + { + // Decompose addition. + Node* a = n->in((opc == Op_AddP) ? 2 : 1); + Node* b = n->in((opc == Op_AddP) ? 3 : 2); + _worklist.push(MemPointerSummand(a, scale)); + _worklist.push(MemPointerSummand(b, scale)); + return; + } + case Op_SubL: + case Op_SubI: + { + // Decompose subtraction. + Node* a = n->in(1); + Node* b = n->in(2); + + NoOverflowInt sub_scale = NoOverflowInt(-1) * scale; + + _worklist.push(MemPointerSummand(a, scale)); + _worklist.push(MemPointerSummand(b, sub_scale)); + return; + } + case Op_MulL: + case Op_MulI: + case Op_LShiftL: + case Op_LShiftI: + { + // Only multiplication with constants is allowed: factor * variable + // IGVN already folds constants to in(2). If we find a variable there + // instead, we cannot further decompose this summand, and have to add + // it to the terminal summands. + Node* variable = n->in(1); + Node* con = n->in(2); + if (!con->is_Con()) { break; } + NoOverflowInt factor; + switch (opc) { + case Op_MulL: // variable * con + factor = NoOverflowInt(con->get_long()); + break; + case Op_MulI: // variable * con + factor = NoOverflowInt(con->get_int()); + break; + case Op_LShiftL: // variable << con = variable * (1 << con) + factor = one << NoOverflowInt(con->get_int()); + break; + case Op_LShiftI: // variable << con = variable * (1 << con) + factor = one << NoOverflowInt(con->get_int()); + break; + } + + // Accumulate scale. + NoOverflowInt new_scale = scale * factor; + + _worklist.push(MemPointerSummand(variable, new_scale)); + return; + } + case Op_CastII: + case Op_CastLL: + case Op_CastX2P: + case Op_ConvI2L: + // On 32bit systems we can also look through ConvL2I, since the final result will always + // be truncated back with ConvL2I. On 64bit systems we cannot decompose ConvL2I because + // such int values will eventually be expanded to long with a ConvI2L: + // + // valL = max_jint + 1 + // ConvI2L(ConvL2I(valL)) = ConvI2L(min_jint) = min_jint != max_jint + 1 = valL + // + NOT_LP64( case Op_ConvL2I: ) + { + // Decompose: look through. + Node* a = n->in(1); + _worklist.push(MemPointerSummand(a, scale)); + return; + } + default: + // All other operations cannot be further decomposed. We just add them to the + // terminal summands below. + break; + } + } + + // Default: we could not parse the "summand" further, i.e. it is terminal. + _summands.push(summand); +} + +// Check if the decomposition of operation opc is guaranteed to be safe. +// Please refer to the definition of "safe decomposition" in mempointer.hpp +bool MemPointerDecomposedFormParser::is_safe_to_decompose_op(const int opc, const NoOverflowInt& scale) const { +#ifndef _LP64 + // On 32-bit platforms, the pointer has 32bits, and thus any higher bits will always + // be truncated. Thus, it does not matter if we have int or long overflows. + // Simply put: all decompositions are (SAFE1). + return true; +#else + + switch (opc) { + // These operations are always safe to decompose, i.e. (SAFE1): + case Op_ConI: + case Op_ConL: + case Op_AddP: + case Op_AddL: + case Op_SubL: + case Op_MulL: + case Op_LShiftL: + case Op_CastII: + case Op_CastLL: + case Op_CastX2P: + case Op_CastPP: + case Op_ConvI2L: + return true; + + // But on 64-bit platforms, these operations are not trivially safe to decompose: + case Op_AddI: // ConvI2L(a + b) != ConvI2L(a) + ConvI2L(b) + case Op_SubI: // ConvI2L(a - b) != ConvI2L(a) - ConvI2L(b) + case Op_MulI: // ConvI2L(a * conI) != ConvI2L(a) * ConvI2L(conI) + case Op_LShiftI: // ConvI2L(a << conI) != ConvI2L(a) << ConvI2L(conI) + break; // Analysis below. + + // All other operations are assumed not safe to decompose, or simply cannot be decomposed + default: + return false; + } + + const TypeAryPtr* ary_ptr_t = _mem->adr_type()->isa_aryptr(); + if (ary_ptr_t != nullptr) { + // Array accesses that are not Unsafe always have a RangeCheck which ensures + // that there is no int overflow. And without overflows, all decompositions + // are (SAFE1). + if (!_mem->is_unsafe_access()) { + return true; + } + + // Intuition: In general, the decomposition of AddI, SubI, MulI or LShiftI is not safe, + // because of overflows. But under some conditions, we can prove that such a + // decomposition is (SAFE2). Intuitively, we want to prove that an overflow + // would mean that the pointers have such a large distance, that at least one + // must lie out of bounds. In the proof of the "MemPointer Lemma", we thus + // get a contradiction with the condition that both pointers are in bounds. + // + // We prove that the decomposition of AddI, SubI, MulI (with constant) and ShiftI (with + // constant) is (SAFE2), under the condition: + // + // abs(scale) % array_element_size_in_bytes = 0 + // + // First, we describe how the decomposition works: + // + // mp_i = con + sum(other_summands) + summand + // ------------------------- ------- + // rest scale * ConvI2L(op) + // + // We decompose the summand depending on the op, where we know that there is some + // integer y, such that: + // + // scale * ConvI2L(a + b) = scale * ConvI2L(a) + scale * ConvI2L(b) + scale * y * 2^32 + // scale * ConvI2L(a - b) = scale * ConvI2L(a) - scale * ConvI2L(b) + scale * y * 2^32 + // scale * ConvI2L(a * con) = scale * con * ConvI2L(a) + scale * y * 2^32 + // scale * ConvI2L(a << con) = scale * (1 << con) * ConvI2L(a) + scale * y * 2^32 + // \_______________________/ \_____________________________________/ \______________/ + // before decomposition after decomposition ("new_summands") overflow correction + // + // Thus, for AddI and SubI, we get: + // summand = new_summand1 + new_summand2 + scale * y * 2^32 + // + // mp_{i+1} = con + sum(other_summands) + new_summand1 + new_summand2 + // = con + sum(other_summands) + summand - scale * y * 2^32 + // = mp_i - scale * y * 2^32 + // + // And for MulI and ShiftI we get: + // summand = new_summand + scale * y * 2^32 + // + // mp_{i+1} = con + sum(other_summands) + new_summand + // = con + sum(other_summands) + summand - scale * y * 2^32 + // = mp_i - scale * y * 2^32 + // + // Further: + // abs(scale) % array_element_size_in_bytes = 0 + // implies that there is some integer z, such that: + // z * array_element_size_in_bytes = scale + // + // And hence, with "x = y * z", the decomposition is (SAFE2) under the assumed condition: + // mp_i = mp_{i+1} + scale * y * 2^32 + // = mp_{i+1} + z * array_element_size_in_bytes * y * 2^32 + // = mp_{i+1} + x * array_element_size_in_bytes * 2^32 + // + BasicType array_element_bt = ary_ptr_t->elem()->array_element_basic_type(); + if (is_java_primitive(array_element_bt)) { + NoOverflowInt array_element_size_in_bytes = NoOverflowInt(type2aelembytes(array_element_bt)); + if (scale.is_multiple_of(array_element_size_in_bytes)) { + return true; + } + } + } + + return false; +#endif +} + +// Compute the aliasing between two MemPointerDecomposedForm. We use the "MemPointer Lemma" to +// prove that the computed aliasing also applies for the underlying pointers. Note that the +// condition (S0) is already given, because the MemPointerDecomposedForm is always constructed +// using only safe decompositions. +// +// Pre-Condition: +// We assume that both pointers are in-bounds of their respective memory object. If this does +// not hold, for example, with the use of Unsafe, then we would already have undefined behavior, +// and we are allowed to do anything. +MemPointerAliasing MemPointerDecomposedForm::get_aliasing_with(const MemPointerDecomposedForm& other + NOT_PRODUCT( COMMA const TraceMemPointer& trace) ) const { +#ifndef PRODUCT + if (trace.is_trace_aliasing()) { + tty->print_cr("MemPointerDecomposedForm::get_aliasing_with:"); + print_on(tty); + other.print_on(tty); + } +#endif + + // "MemPointer Lemma" condition (S2): check if all summands are the same: + for (uint i = 0; i < SUMMANDS_SIZE; i++) { + const MemPointerSummand s1 = summands_at(i); + const MemPointerSummand s2 = other.summands_at(i); + if (s1 != s2) { +#ifndef PRODUCT + if (trace.is_trace_aliasing()) { + tty->print_cr(" -> Aliasing unknown, differ on summand %d.", i); + } +#endif + return MemPointerAliasing::make_unknown(); + } + } + + // "MemPointer Lemma" condition (S3): check that the constants do not differ too much: + const NoOverflowInt distance = other.con() - con(); + // We must check that: abs(distance) < 2^32 + // However, this is only false if: distance = min_jint + if (distance.is_NaN() || distance.value() == min_jint) { +#ifndef PRODUCT + if (trace.is_trace_aliasing()) { + tty->print(" -> Aliasing unknown, bad distance: "); + distance.print_on(tty); + tty->cr(); + } +#endif + return MemPointerAliasing::make_unknown(); + } + + // "MemPointer Lemma" condition (S1): + // Given that all summands are the same, we know that both pointers point into the + // same memory object. With the Pre-Condition, we know that both pointers are in + // bounds of that same memory object. + + // Hence, all 4 conditions of the "MemoryPointer Lemma" are established, and hence + // we know that the distance between the underlying pointers is equal to the distance + // we computed for the MemPointers: + // p_other - p_this = distance = other.con - this.con +#ifndef PRODUCT + if (trace.is_trace_aliasing()) { + tty->print_cr(" -> Aliasing always, distance = %d.", distance.value()); + } +#endif + return MemPointerAliasing::make_always(distance.value()); +} + +bool MemPointer::is_adjacent_to_and_before(const MemPointer& other) const { + const MemPointerDecomposedForm& s1 = decomposed_form(); + const MemPointerDecomposedForm& s2 = other.decomposed_form(); + const MemPointerAliasing aliasing = s1.get_aliasing_with(s2 NOT_PRODUCT( COMMA _trace )); + const jint size = mem()->memory_size(); + const bool is_adjacent = aliasing.is_always_at_distance(size); + +#ifndef PRODUCT + if (_trace.is_trace_adjacency()) { + tty->print("Adjacent: %s, because size = %d and aliasing = ", + is_adjacent ? "true" : "false", size); + aliasing.print_on(tty); + tty->cr(); + } +#endif + + return is_adjacent; +} diff --git a/src/hotspot/share/opto/mempointer.hpp b/src/hotspot/share/opto/mempointer.hpp new file mode 100644 index 00000000000..1e5b2c00b88 --- /dev/null +++ b/src/hotspot/share/opto/mempointer.hpp @@ -0,0 +1,618 @@ +/* + * 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. + * + */ + +#ifndef SHARE_OPTO_MEMPOINTER_HPP +#define SHARE_OPTO_MEMPOINTER_HPP + +#include "opto/memnode.hpp" +#include "opto/noOverflowInt.hpp" + +// The MemPointer is a shared facility to parse pointers and check the aliasing of pointers, +// e.g. checking if two stores are adjacent. +// +// ----------------------------------------------------------------------------------------- +// +// Intuition and Examples: +// We parse / decompose pointers into a linear form: +// +// pointer = SUM(scale_i * variable_i) + con +// +// where SUM() adds all "scale_i * variable_i" for each i together. +// +// The con and scale_i are compile-time constants (NoOverflowInt), and the variable_i are +// compile-time variables (C2 nodes). +// +// For the MemPointer, we do not explicitly track the base address. For Java heap pointers, the +// base address is just a variable in a summand with scale == 1. For native memory (C heap) +// pointers, the base address is null, and is hence implicitly a zero constant. +// +// +// Example 1: byte array access: +// +// array[i] +// +// pointer = array_base + ARRAY_BYTE_BASE_OFFSET + 1 * i +// = 1 * array_base + ARRAY_BYTE_BASE_OFFSET + 1 * i +// -------------------- ---------------------- -------------------- +// = scale_0 * variable_0 + con + scale_1 * variable_1 +// +// +// Example 2: int array access +// +// array[5 + i + 3 * j] +// +// pointer = array_base + ARRAY_INT_BASE_OFFSET + 4 * 5 + 4 * i + 4 * 3 * j +// = 1 * array_base + ARRAY_INT_BASE_OFFSET + 20 + 4 * i + 12 * j +// -------------------- ----------------------------- -------------------- -------------------- +// = scale_0 * variable_0 + con + scale_1 * variable_1 + scale_2 * variable_2 +// +// +// Example 3: Unsafe with int array +// +// UNSAFE.getInt(array, ARRAY_INT_BASE_OFFSET + 4 * i); +// +// pointer = array_base + ARRAY_INT_BASE_OFFSET + 4 * i +// = 1 * array_base + ARRAY_INT_BASE_OFFSET + 4 * i +// -------------------- --------------------- -------------------- +// = scale_0 * variable_0 + con + scale_1 * variable_1 +// +// +// Example 4: Unsafe with native memory address +// +// long address; +// UNSAFE.getInt(null, address + 4 * i); +// +// pointer = address + 4 * i +// = 1 * address + 0 + 4 * i +// -------------------- --- -------------------- +// = scale_0 * variable_0 + con + scale_1 * variable_1 +// +// +// Example 5: MemorySegment with byte array as backing type +// +// byte[] array = new byte[1000]; +// MemorySegment ms = MemorySegment.ofArray(array); +// assert ms.heapBase().get() == array: "array is base"; +// assert ms.address() == 0: "zero offset from base"; +// byte val = ms.get(ValueLayout.JAVA_BYTE, i); +// +// pointer = ms.heapBase() + ARRAY_BYTE_BASE_OFFSET + ms.address() + i +// = 1 * array_base + ARRAY_BYTE_BASE_OFFSET + 0 + 1 * i +// ----------------------- ------------------------------------- -------------------- +// = scale_0 * variable_0 + con + scale_1 * variable_1 +// +// +// Example 6: MemorySegment with native memory +// +// MemorySegment ms = Arena.ofAuto().allocate(1000, 1); +// assert ms.heapBase().isEmpty(): "null base"; +// assert ms.address() != 0: "non-zero native memory address"; +// short val = ms.get(ValueLayout.JAVA_SHORT, 2L * i); +// +// pointer = ms.heapBase() + ms.address() + 2 i +// = 0 + 1 * ms.address() + 2 * i +// ------------ ---------------------- -------------------- +// = con scale_0 * variable_0 + scale_1 * variable_1 +// +// +// Example 7: Non-linear access to int array +// +// array[5 + i + j * k] +// +// pointer = array_base + ARRAY_INT_BASE_OFFSET + 4 * 5 + 4 * i + 4 * j * k +// = 1 * array_base + ARRAY_INT_BASE_OFFSET + 20 + 4 * i + 4 * j * k +// -------------------- ----------------------------- -------------------- -------------------- +// = scale_0 * variable_0 + con + scale_1 * variable_1 + scale_2 * variable_2 +// +// Note: we simply stop parsing once a term is not linear. We keep "j * k" as its own variable. +// +// +// Example 8: Unsafe with native memory address, non-linear access +// +// UNSAFE.getInt(null, i * j); +// +// pointer = i * j +// = 0 + 1 * i * j +// --- -------------------- +// = con + scale_0 * variable_0 +// +// Note: we can always parse a pointer into its trivial linear form: +// +// pointer = 0 + 1 * pointer. +// +// ----------------------------------------------------------------------------------------- +// +// MemPointerDecomposedForm: +// When the pointer is parsed, it is decomposed into a SUM of summands plus a constant: +// +// pointer = SUM(summands) + con +// +// Where each summand_i in summands has the form: +// +// summand_i = scale_i * variable_i +// +// Hence, the full decomposed form is: +// +// pointer = SUM(scale_i * variable_i) + con +// +// Note: the scale_i are compile-time constants (NoOverflowInt), and the variable_i are +// compile-time variables (C2 nodes). +// On 64-bit systems, this decomposed form is computed with long-add/mul, on 32-bit systems +// it is computed with int-add/mul. +// +// MemPointerAliasing: +// The decomposed form allows us to determine the aliasing between two pointers easily. For +// example, if two pointers are identical, except for their constant: +// +// pointer1 = SUM(summands) + con1 +// pointer2 = SUM(summands) + con2 +// +// then we can easily compute the distance between the pointers (distance = con2 - con1), +// and determine if they are adjacent. +// +// MemPointerDecomposedFormParser: +// Any pointer can be parsed into this (default / trivial) decomposed form: +// +// pointer = 1 * pointer + 0 +// scale_0 * variable_0 + con +// +// However, this is not particularly useful to compute aliasing. We would like to decompose +// the pointer as far as possible, i.e. extract as many summands and add up the constants to +// a single constant. +// +// Example (normal int-array access): +// pointer1 = array[i + 0] = array_base + array_int_base_offset + 4L * ConvI2L(i + 0) +// pointer2 = array[i + 1] = array_base + array_int_base_offset + 4L * ConvI2L(i + 1) +// +// At first, computing the aliasing is not immediately straight-forward in the general case because +// the distance is hidden inside the ConvI2L. We can convert this (with array_int_base_offset = 16) +// into these decomposed forms: +// +// pointer1 = 1L * array_base + 4L * i + 16L +// pointer2 = 1L * array_base + 4L * i + 20L +// +// This allows us to easily see that these two pointers are adjacent (distance = 4). +// +// Hence, in MemPointerDecomposedFormParser::parse_decomposed_form, we start with the pointer as +// a trivial summand. A summand can either be decomposed further or it is terminal (cannot +// be decomposed further). We decompose the summands recursively until all remaining summands +// are terminal, see MemPointerDecomposedFormParser::parse_sub_expression. This effectively parses +// the pointer expression recursively. +// +// ----------------------------------------------------------------------------------------- +// +// We have to be careful on 64-bit systems with ConvI2L: decomposing its input is not +// correct in general, overflows may not be preserved in the decomposed form: +// +// AddI: ConvI2L(a + b) != ConvI2L(a) + ConvI2L(b) +// SubI: ConvI2L(a - b) != ConvI2L(a) - ConvI2L(b) +// MulI: ConvI2L(a * conI) != ConvI2L(a) * ConvI2L(conI) +// LShiftI: ConvI2L(a << conI) != ConvI2L(a) << ConvI2L(conI) +// +// If we want to prove the correctness of MemPointerAliasing, we need some guarantees, +// that the MemPointers adequately represent the underlying pointers, such that we can +// compute the aliasing based on the summands and constants. +// +// ----------------------------------------------------------------------------------------- +// +// Below, we will formulate a "MemPointer Lemma" that helps us to prove the correctness of +// the MemPointerAliasing computations. To prove the "MemPointer Lemma", we need to define +// the idea of a "safe decomposition", and then prove that all the decompositions we apply +// are such "safe decompositions". +// +// +// Definition: Safe decomposition +// Trivial decomposition: +// (SAFE0) The trivial decomposition from p to mp_0 = 0 + 1 * p is always safe. +// +// Non-trivial decomposition: +// We decompose summand in: +// mp_i = con + summand + SUM(other_summands) +// resulting in: +-------------------------+ +// mp_{i+1} = con + dec_con + SUM(dec_summands) + SUM(other_summands) +// = new_con + SUM(new_summands) +// where mp_i means that the original pointer p was decomposed i times. +// +// We call a non-trivial decomposition safe if either: +// (SAFE1) No matter the values of the summand variables: +// mp_i = mp_{i+1} +// +// (SAFE2) The pointer is on an array with a known array_element_size_in_bytes, +// and there is an integer x, such that: +// mp_i = mp_{i+1} + x * array_element_size_in_bytes * 2^32 +// +// Note: if "x = 0", we have "mp1 = mp2", and if "x != 0", then mp1 and mp2 +// have a distance at least twice as large as the array size, and so +// at least one of mp1 or mp2 must be out of bounds of the array. +// +// MemPointer Lemma: +// Given two pointers p1 and p2, and their respective MemPointers mp1 and mp2. +// If these conditions hold: +// (S0) mp1 and mp2 are constructed only with safe decompositions (SAFE0, SAFE1, SAFE2) +// from p1 and p2, respectively. +// (S1) Both p1 and p2 are within the bounds of the same memory object. +// (S2) The constants do not differ too much: abs(mp1.con - mp2.con) < 2^31. +// (S3) All summands of mp1 and mp2 are identical (i.e. only the constants are possibly different). +// +// then the pointer difference between p1 and p2 is identical to the difference between +// mp1 and mp2: +// p1 - p2 = mp1 - mp2 +// +// Note: MemPointerDecomposedForm::get_aliasing_with relies on this MemPointer Lemma to +// prove the correctness of its aliasing computation between two MemPointers. +// +// +// Note: MemPointerDecomposedFormParser::is_safe_to_decompose_op checks that all +// decompositions we apply are safe. +// +// +// Proof of the "MemPointer Lemma": +// Assume (S0-S3) and show that +// p1 - p2 = mp1 - mp2 +// +// We make a case distinction over the types of decompositions used in the construction of mp1 and mp2. +// +// Trivial Case: Only trivial (SAFE0) decompositions were used: +// mp1 = 0 + 1 * p1 = p1 +// mp2 = 0 + 1 * p2 = p2 +// => +// p1 - p2 = mp1 - mp2 +// +// Unsafe Case: We apply at least one unsafe decomposition: +// This is a contradiction to (S0) and we are done. +// +// Case 1: Only decomposition of type (SAFE0) and (SAFE1) are used: +// We make an induction proof over the decompositions from p1 to mp1, starting with +// the trivial decomposition (SAFE0): +// mp1_0 = 0 + 1 * p1 = p1 +// Then for the i-th non-trivial decomposition (SAFE1) we know that +// mp1_i = mp1_{i+1} +// and hence, after the n-th non-trivial decomposition from p1: +// p1 = mp1_0 = mp1_i = mp1_n = mp1 +// Analogously, we can prove: +// p2 = mp2 +// +// p1 = mp1 +// p2 = mp2 +// => +// p1 - p2 = mp1 - mp2 +// +// Case 2: At least one decomposition of type (SAFE2) and no unsafe decomposition is used. +// Given we have (SAFE2) decompositions, we know that we are operating on an array of +// known array_element_size_in_bytes. We can weaken the guarantees from (SAFE1) +// decompositions to the same guarantee as (SAFE2) decompositions. Hence all applied +// non-trivial decompositions satisfy: +// mp1_i = mp1_{i+1} + x1_i * array_element_size_in_bytes * 2^32 +// where x1_i = 0 for (SAFE1) decompositions. +// +// We make an induction proof over the decompositions from p1 to mp1, starting with +// the trivial decomposition (SAFE0): +// mp1_0 = 0 + 1 * p1 = p1 +// Then for the i-th non-trivial decomposition (SAFE1) or (SAFE2), we know that +// mp1_i = mp1_{i+1} + x1_i * array_element_size_in_bytes * 2^32 +// and hence, if mp1 was decomposed with n non-trivial decompositions (SAFE1) or (SAFE2) from p1: +// p1 = mp1 + x1 * array_element_size_in_bytes * 2^32 +// where +// x1 = SUM(x1_i) +// Analogously, we can prove: +// p2 = mp2 + x2 * array_element_size_in_bytes * 2^32 +// +// And hence, with x = x1 - x2 we have: +// p1 - p2 = mp1 - mp2 + x * array_element_size_in_bytes * 2^32 +// +// If "x = 0", then it follows: +// p1 - p2 = mp1 - mp2 +// +// If "x != 0", then: +// abs(p1 - p2) = abs(mp1 - mp2 + x * array_element_size_in_bytes * 2^32) +// >= abs(x * array_element_size_in_bytes * 2^32) - abs(mp1 - mp2) +// -- apply x != 0 -- +// >= array_element_size_in_bytes * 2^32 - abs(mp1 - mp2) +// -- apply (S3) -- +// = array_element_size_in_bytes * 2^32 - abs(mp1.con - mp2.con) +// -- apply (S2) -- +// > array_element_size_in_bytes * 2^32 - 2^31 +// -- apply array_element_size_in_bytes > 0 -- +// >= array_element_size_in_bytes * 2^31 +// >= max_possible_array_size_in_bytes +// >= array_size_in_bytes +// +// This shows that p1 and p2 have a distance greater than the array size, and hence at least one of the two +// pointers must be out of bounds. This contradicts our assumption (S1) and we are done. + + +#ifndef PRODUCT +class TraceMemPointer : public StackObj { +private: + const bool _is_trace_pointer; + const bool _is_trace_aliasing; + const bool _is_trace_adjacency; + +public: + TraceMemPointer(const bool is_trace_pointer, + const bool is_trace_aliasing, + const bool is_trace_adjacency) : + _is_trace_pointer( is_trace_pointer), + _is_trace_aliasing( is_trace_aliasing), + _is_trace_adjacency(is_trace_adjacency) + {} + + bool is_trace_pointer() const { return _is_trace_pointer; } + bool is_trace_aliasing() const { return _is_trace_aliasing; } + bool is_trace_adjacency() const { return _is_trace_adjacency; } +}; +#endif + +// Class to represent aliasing between two MemPointer. +class MemPointerAliasing { +public: + enum Aliasing { + Unknown, // Distance unknown. + // Example: two "int[]" with different variable index offsets. + // e.g. "array[i] vs array[j]". + // e.g. "array1[i] vs array2[j]". + Always}; // Constant distance = p1 - p2. + // Example: The same address expression, except for a constant offset + // e.g. "array[i] vs array[i+1]". +private: + const Aliasing _aliasing; + const jint _distance; + + MemPointerAliasing(const Aliasing aliasing, const jint distance) : + _aliasing(aliasing), + _distance(distance) + { + assert(_distance != min_jint, "given by condition (S3) of MemPointer Lemma"); + } + +public: + static MemPointerAliasing make_unknown() { + return MemPointerAliasing(Unknown, 0); + } + + static MemPointerAliasing make_always(const jint distance) { + return MemPointerAliasing(Always, distance); + } + + // Use case: exact aliasing and adjacency. + bool is_always_at_distance(const jint distance) const { + return _aliasing == Always && _distance == distance; + } + +#ifndef PRODUCT + void print_on(outputStream* st) const { + switch(_aliasing) { + case Unknown: st->print("Unknown"); break; + case Always: st->print("Always(%d)", _distance); break; + default: ShouldNotReachHere(); + } + } +#endif +}; + +// Summand of a MemPointerDecomposedForm: +// +// summand = scale * variable +// +// where variable is a C2 node. +class MemPointerSummand : public StackObj { +private: + Node* _variable; + NoOverflowInt _scale; + +public: + MemPointerSummand() : + _variable(nullptr), + _scale(NoOverflowInt::make_NaN()) {} + MemPointerSummand(Node* variable, const NoOverflowInt& scale) : + _variable(variable), + _scale(scale) + { + assert(_variable != nullptr, "must have variable"); + assert(!_scale.is_zero(), "non-zero scale"); + } + + Node* variable() const { return _variable; } + NoOverflowInt scale() const { return _scale; } + + static int cmp_by_variable_idx(MemPointerSummand* p1, MemPointerSummand* p2) { + if (p1->variable() == nullptr) { + return (p2->variable() == nullptr) ? 0 : 1; + } else if (p2->variable() == nullptr) { + return -1; + } + + return p1->variable()->_idx - p2->variable()->_idx; + } + + friend bool operator==(const MemPointerSummand a, const MemPointerSummand b) { + // Both "null" -> equal. + if (a.variable() == nullptr && b.variable() == nullptr) { return true; } + + // Same variable and scale? + if (a.variable() != b.variable()) { return false; } + return a.scale() == b.scale(); + } + + friend bool operator!=(const MemPointerSummand a, const MemPointerSummand b) { + return !(a == b); + } + +#ifndef PRODUCT + void print_on(outputStream* st) const { + st->print("Summand["); + _scale.print_on(st); + tty->print(" * [%d %s]]", _variable->_idx, _variable->Name()); + } +#endif +}; + +// Decomposed form of the pointer sub-expression of "pointer". +// +// pointer = SUM(summands) + con +// +class MemPointerDecomposedForm : public StackObj { +private: + // We limit the number of summands to 10. This is just a best guess, and not at this + // point supported by evidence. But I think it is reasonable: usually, a pointer + // contains a base pointer (e.g. array pointer or null for native memory) and a few + // variables. It should be rare that we have more than 9 variables. + static const int SUMMANDS_SIZE = 10; + + Node* _pointer; // pointer node associated with this (sub)pointer + + MemPointerSummand _summands[SUMMANDS_SIZE]; + NoOverflowInt _con; + +public: + // Empty + MemPointerDecomposedForm() : _pointer(nullptr), _con(NoOverflowInt::make_NaN()) {} + +private: + // Default / trivial: pointer = 0 + 1 * pointer + MemPointerDecomposedForm(Node* pointer) : _pointer(pointer), _con(NoOverflowInt(0)) { + assert(pointer != nullptr, "pointer must be non-null"); + _summands[0] = MemPointerSummand(pointer, NoOverflowInt(1)); + } + + MemPointerDecomposedForm(Node* pointer, const GrowableArray& summands, const NoOverflowInt& con) + : _pointer(pointer), _con(con) { + assert(!_con.is_NaN(), "non-NaN constant"); + assert(summands.length() <= SUMMANDS_SIZE, "summands must fit"); + for (int i = 0; i < summands.length(); i++) { + MemPointerSummand s = summands.at(i); + assert(s.variable() != nullptr, "variable cannot be null"); + assert(!s.scale().is_NaN(), "non-NaN scale"); + _summands[i] = s; + } + } + +public: + static MemPointerDecomposedForm make_trivial(Node* pointer) { + return MemPointerDecomposedForm(pointer); + } + + static MemPointerDecomposedForm make(Node* pointer, const GrowableArray& summands, const NoOverflowInt& con) { + if (summands.length() <= SUMMANDS_SIZE) { + return MemPointerDecomposedForm(pointer, summands, con); + } else { + return MemPointerDecomposedForm::make_trivial(pointer); + } + } + + MemPointerAliasing get_aliasing_with(const MemPointerDecomposedForm& other + NOT_PRODUCT( COMMA const TraceMemPointer& trace) ) const; + + const MemPointerSummand summands_at(const uint i) const { + assert(i < SUMMANDS_SIZE, "in bounds"); + return _summands[i]; + } + + const NoOverflowInt con() const { return _con; } + +#ifndef PRODUCT + void print_on(outputStream* st) const { + if (_pointer == nullptr) { + st->print_cr("MemPointerDecomposedForm empty."); + return; + } + st->print("MemPointerDecomposedForm[%d %s: con = ", _pointer->_idx, _pointer->Name()); + _con.print_on(st); + for (int i = 0; i < SUMMANDS_SIZE; i++) { + const MemPointerSummand& summand = _summands[i]; + if (summand.variable() != nullptr) { + st->print(", "); + summand.print_on(st); + } + } + st->print_cr("]"); + } +#endif +}; + +class MemPointerDecomposedFormParser : public StackObj { +private: + const MemNode* _mem; + + // Internal data-structures for parsing. + NoOverflowInt _con; + GrowableArray _worklist; + GrowableArray _summands; + + // Resulting decomposed-form. + MemPointerDecomposedForm _decomposed_form; + +public: + MemPointerDecomposedFormParser(const MemNode* mem) : _mem(mem), _con(NoOverflowInt(0)) { + _decomposed_form = parse_decomposed_form(); + } + + const MemPointerDecomposedForm decomposed_form() const { return _decomposed_form; } + +private: + MemPointerDecomposedForm parse_decomposed_form(); + void parse_sub_expression(const MemPointerSummand& summand); + + bool is_safe_to_decompose_op(const int opc, const NoOverflowInt& scale) const; +}; + +// Facility to parse the pointer of a Load or Store, so that aliasing between two such +// memory operations can be determined (e.g. adjacency). +class MemPointer : public StackObj { +private: + const MemNode* _mem; + const MemPointerDecomposedForm _decomposed_form; + + NOT_PRODUCT( const TraceMemPointer& _trace; ) + +public: + MemPointer(const MemNode* mem NOT_PRODUCT( COMMA const TraceMemPointer& trace)) : + _mem(mem), + _decomposed_form(init_decomposed_form(_mem)) + NOT_PRODUCT( COMMA _trace(trace) ) + { +#ifndef PRODUCT + if (_trace.is_trace_pointer()) { + tty->print_cr("MemPointer::MemPointer:"); + tty->print("mem: "); mem->dump(); + _mem->in(MemNode::Address)->dump_bfs(5, 0, "d"); + _decomposed_form.print_on(tty); + } +#endif + } + + const MemNode* mem() const { return _mem; } + const MemPointerDecomposedForm decomposed_form() const { return _decomposed_form; } + bool is_adjacent_to_and_before(const MemPointer& other) const; + +private: + static const MemPointerDecomposedForm init_decomposed_form(const MemNode* mem) { + assert(mem->is_Store(), "only stores are supported"); + ResourceMark rm; + MemPointerDecomposedFormParser parser(mem); + return parser.decomposed_form(); + } +}; + +#endif // SHARE_OPTO_MEMPOINTER_HPP diff --git a/src/hotspot/share/opto/noOverflowInt.hpp b/src/hotspot/share/opto/noOverflowInt.hpp new file mode 100644 index 00000000000..9da24645b41 --- /dev/null +++ b/src/hotspot/share/opto/noOverflowInt.hpp @@ -0,0 +1,114 @@ +/* + * 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. + * + */ + +#ifndef SHARE_OPTO_NOOVERFLOWINT_HPP +#define SHARE_OPTO_NOOVERFLOWINT_HPP + +#include "utilities/ostream.hpp" + +// Wrapper around jint, which detects overflow. +// If any operation overflows, then it returns a NaN. +class NoOverflowInt { +private: + bool _is_NaN; // overflow, uninitialized, etc. + jint _value; + +public: + // Default: NaN. + constexpr NoOverflowInt() : _is_NaN(true), _value(0) {} + + // Create from jlong (or jint) -> NaN if overflows jint. + constexpr explicit NoOverflowInt(jlong value) : _is_NaN(true), _value(0) { + jint trunc = (jint)value; + if ((jlong)trunc == value) { + _is_NaN = false; + _value = trunc; + } + } + + static constexpr NoOverflowInt make_NaN() { return NoOverflowInt(); } + + bool is_NaN() const { return _is_NaN; } + jint value() const { assert(!is_NaN(), "NaN not allowed"); return _value; } + bool is_zero() const { return !is_NaN() && value() == 0; } + + friend NoOverflowInt operator+(const NoOverflowInt& a, const NoOverflowInt& b) { + if (a.is_NaN()) { return a; } + if (b.is_NaN()) { return b; } + return NoOverflowInt((jlong)a.value() + (jlong)b.value()); + } + + friend NoOverflowInt operator-(const NoOverflowInt& a, const NoOverflowInt& b) { + if (a.is_NaN()) { return a; } + if (b.is_NaN()) { return b; } + return NoOverflowInt((jlong)a.value() - (jlong)b.value()); + } + + friend NoOverflowInt operator*(const NoOverflowInt& a, const NoOverflowInt& b) { + if (a.is_NaN()) { return a; } + if (b.is_NaN()) { return b; } + return NoOverflowInt((jlong)a.value() * (jlong)b.value()); + } + + friend NoOverflowInt operator<<(const NoOverflowInt& a, const NoOverflowInt& b) { + if (a.is_NaN()) { return a; } + if (b.is_NaN()) { return b; } + jint shift = b.value(); + if (shift < 0 || shift > 31) { return make_NaN(); } + return NoOverflowInt((jlong)a.value() << shift); + } + + friend bool operator==(const NoOverflowInt& a, const NoOverflowInt& b) { + if (a.is_NaN()) { return false; } + if (b.is_NaN()) { return false; } + return a.value() == b.value(); + } + + NoOverflowInt abs() const { + if (is_NaN()) { return *this; } + if (value() >= 0) { return *this; } + return NoOverflowInt(0) - *this; + } + + bool is_multiple_of(const NoOverflowInt& other) const { + NoOverflowInt a = this->abs(); + NoOverflowInt b = other.abs(); + if (a.is_NaN()) { return false; } + if (b.is_NaN()) { return false; } + if (b.is_zero()) { return false; } + return a.value() % b.value() == 0; + } + +#ifndef PRODUCT + void print_on(outputStream* st) const { + if (is_NaN()) { + st->print("NaN"); + } else { + st->print("%d", value()); + } + } +#endif +}; + +#endif // SHARE_OPTO_NOOVERFLOWINT_HPP diff --git a/src/hotspot/share/opto/traceMergeStoresTag.hpp b/src/hotspot/share/opto/traceMergeStoresTag.hpp new file mode 100644 index 00000000000..9f33c9efa05 --- /dev/null +++ b/src/hotspot/share/opto/traceMergeStoresTag.hpp @@ -0,0 +1,138 @@ +/* + * 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. + * + */ + +#ifndef SHARE_OPTO_TRACEMERGESTORESTAG_HPP +#define SHARE_OPTO_TRACEMERGESTORESTAG_HPP + +#include "utilities/bitMap.inline.hpp" +#include "utilities/stringUtils.hpp" + +namespace TraceMergeStores { + #define COMPILER_TAG(flags) \ + flags(BASIC, "Trace basic analysis steps") \ + flags(POINTER, "Trace pointer IR") \ + flags(ALIASING, "Trace MemPointerSimpleForm::get_aliasing_with") \ + flags(ADJACENCY, "Trace adjacency") \ + flags(SUCCESS, "Trace successful merges") \ + + #define table_entry(name, description) name, + enum Tag { + COMPILER_TAG(table_entry) + TAG_NUM, + TAG_NONE + }; + #undef table_entry + + static const char* tag_descriptions[] = { + #define array_of_labels(name, description) description, + COMPILER_TAG(array_of_labels) + #undef array_of_labels + }; + + static const char* tag_names[] = { + #define array_of_labels(name, description) #name, + COMPILER_TAG(array_of_labels) + #undef array_of_labels + }; + + static Tag find_tag(const char* str) { + for (int i = 0; i < TAG_NUM; i++) { + if (strcmp(tag_names[i], str) == 0) { + return (Tag)i; + } + } + return TAG_NONE; + } + + class TagValidator { + private: + CHeapBitMap _tags; + bool _valid; + char* _bad; + bool _is_print_usage; + + public: + TagValidator(ccstrlist option, bool is_print_usage) : + _tags(TAG_NUM, mtCompiler), + _valid(true), + _bad(nullptr), + _is_print_usage(is_print_usage) + { + for (StringUtils::CommaSeparatedStringIterator iter(option); *iter != nullptr && _valid; ++iter) { + char const* tag_name = *iter; + if (strcmp("help", tag_name) == 0) { + if (_is_print_usage) { + print_help(); + } + continue; + } + bool set_bit = true; + // Check for "TAG" or "-TAG" + if (strncmp("-", tag_name, strlen("-")) == 0) { + tag_name++; + set_bit = false; + } + Tag tag = find_tag(tag_name); + if (TAG_NONE == tag) { + // cap len to a value we know is enough for all tags + const size_t len = MIN2(strlen(*iter), 63) + 1; + _bad = NEW_C_HEAP_ARRAY(char, len, mtCompiler); + // strncpy always writes len characters. If the source string is + // shorter, the function fills the remaining bytes with nulls. + strncpy(_bad, *iter, len); + _valid = false; + } else { + assert(tag < TAG_NUM, "out of bounds"); + _tags.at_put(tag, set_bit); + } + } + } + + ~TagValidator() { + if (_bad != nullptr) { + FREE_C_HEAP_ARRAY(char, _bad); + } + } + + bool is_valid() const { return _valid; } + const char* what() const { return _bad; } + const CHeapBitMap& tags() const { + assert(is_valid(), "only read tags when valid"); + return _tags; + } + + static void print_help() { + tty->cr(); + tty->print_cr("Usage for CompileCommand TraceMergeStores:"); + tty->print_cr(" -XX:CompileCommand=TraceMergeStores,,"); + tty->print_cr(" %-22s %s", "tags", "descriptions"); + for (int i = 0; i < TAG_NUM; i++) { + tty->print_cr(" %-22s %s", tag_names[i], tag_descriptions[i]); + } + tty->cr(); + } + }; +} + +#endif // SHARE_OPTO_TRACEMERGESTORESTAG_HPP diff --git a/test/hotspot/gtest/opto/test_no_overflow_int.cpp b/test/hotspot/gtest/opto/test_no_overflow_int.cpp new file mode 100644 index 00000000000..7b4b4259bb8 --- /dev/null +++ b/test/hotspot/gtest/opto/test_no_overflow_int.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "opto/noOverflowInt.hpp" +#include "unittest.hpp" + +static void check_jlong(const jlong val) { + const NoOverflowInt x(val); + + if (val > max_jint || min_jint > val) { + ASSERT_TRUE(x.is_NaN()); + } else { + ASSERT_FALSE(x.is_NaN()); + ASSERT_EQ(x.value(), val); + } +} + +TEST_VM(opto, NoOverflowInt_check_jlong) { + jlong start = (jlong)min_jint - 10000LL; + jlong end = (jlong)max_jint + 10000LL; + for (jlong i = start; i < end; i+= 1000LL) { + check_jlong(i); + } + + check_jlong((jlong)min_jint - 1LL); + check_jlong((jlong)min_jint); + check_jlong((jlong)min_jint + 1LL); + check_jlong((jlong)max_jint - 1LL); + check_jlong((jlong)max_jint); + check_jlong((jlong)max_jint + 1LL); + + const NoOverflowInt nan; + ASSERT_TRUE(nan.is_NaN()); +} + +TEST_VM(opto, NoOverflowInt_add_sub) { + const NoOverflowInt nan; + const NoOverflowInt zero(0); + const NoOverflowInt one(1); + const NoOverflowInt two(2); + const NoOverflowInt big(1 << 30); + + ASSERT_EQ((one + two).value(), 3); + ASSERT_EQ((one - two).value(), -1); + ASSERT_TRUE((nan + one).is_NaN()); + ASSERT_TRUE((one + nan).is_NaN()); + ASSERT_TRUE((nan + nan).is_NaN()); + ASSERT_TRUE((nan - one).is_NaN()); + ASSERT_TRUE((one - nan).is_NaN()); + ASSERT_TRUE((nan - nan).is_NaN()); + + ASSERT_EQ((big + one).value(), (1 << 30) + 1); + ASSERT_TRUE((big + big).is_NaN()); + ASSERT_EQ((big - one).value(), (1 << 30) - 1); + ASSERT_EQ((big - big).value(), 0); + + ASSERT_EQ((big - one + big).value(), max_jint); + ASSERT_EQ((zero - big - big).value(), min_jint); + ASSERT_TRUE((zero - big - big - one).is_NaN()); +} + +TEST_VM(opto, NoOverflowInt_mul) { + const NoOverflowInt nan; + const NoOverflowInt zero(0); + const NoOverflowInt one(1); + const NoOverflowInt two(2); + const NoOverflowInt big(1 << 30); + + ASSERT_EQ((one * two).value(), 2); + ASSERT_TRUE((nan * one).is_NaN()); + ASSERT_TRUE((one * nan).is_NaN()); + ASSERT_TRUE((nan * nan).is_NaN()); + + ASSERT_EQ((big * one).value(), (1 << 30)); + ASSERT_EQ((one * big).value(), (1 << 30)); + ASSERT_EQ((big * zero).value(), 0); + ASSERT_EQ((zero * big).value(), 0); + ASSERT_TRUE((big * big).is_NaN()); + ASSERT_TRUE((big * two).is_NaN()); + + ASSERT_EQ(((big - one) * two).value(), max_jint - 1); + ASSERT_EQ(((one - big) * two).value(), min_jint + 2); + ASSERT_EQ(((zero - big) * two).value(), min_jint); + ASSERT_TRUE(((big + one) * two).is_NaN()); + ASSERT_TRUE(((zero - big - one) * two).is_NaN()); +} + +TEST_VM(opto, NoOverflowInt_lshift) { + const NoOverflowInt nan; + const NoOverflowInt zero(0); + const NoOverflowInt one(1); + const NoOverflowInt two(2); + const NoOverflowInt big(1 << 30); + + for (int i = 0; i < 31; i++) { + ASSERT_EQ((one << NoOverflowInt(i)).value(), 1LL << i); + } + for (int i = 31; i < 1000; i++) { + ASSERT_TRUE((one << NoOverflowInt(i)).is_NaN()); + } + for (int i = -1000; i < 0; i++) { + ASSERT_TRUE((one << NoOverflowInt(i)).is_NaN()); + } + + ASSERT_EQ((NoOverflowInt(3) << NoOverflowInt(2)).value(), 3 * 4); + ASSERT_EQ((NoOverflowInt(11) << NoOverflowInt(5)).value(), 11 * 32); + ASSERT_EQ((NoOverflowInt(-13) << NoOverflowInt(4)).value(), -13 * 16); +} + +TEST_VM(opto, NoOverflowInt_misc) { + const NoOverflowInt nan; + const NoOverflowInt zero(0); + const NoOverflowInt one(1); + const NoOverflowInt two(2); + const NoOverflowInt big(1 << 30); + + // operator== + ASSERT_FALSE(nan == nan); + ASSERT_FALSE(nan == zero); + ASSERT_FALSE(zero == nan); + ASSERT_TRUE(zero == zero); + ASSERT_TRUE(one == one); + ASSERT_TRUE((one + two) == (two + one)); + ASSERT_TRUE((big + two) == (two + big)); + ASSERT_FALSE((big + big) == (big + big)); + ASSERT_TRUE((big - one + big) == (big - one + big)); + + // abs + for (int i = 0; i < (1 << 31); i += 1024) { + ASSERT_EQ(NoOverflowInt(i).abs().value(), i); + ASSERT_EQ(NoOverflowInt(-i).abs().value(), i); + } + ASSERT_EQ(NoOverflowInt(max_jint).abs().value(), max_jint); + ASSERT_EQ(NoOverflowInt(min_jint + 1).abs().value(), max_jint); + ASSERT_TRUE(NoOverflowInt(min_jint).abs().is_NaN()); + ASSERT_TRUE(NoOverflowInt(nan).abs().is_NaN()); + + // is_multiple_of + ASSERT_TRUE(one.is_multiple_of(one)); + ASSERT_FALSE(one.is_multiple_of(nan)); + ASSERT_FALSE(nan.is_multiple_of(one)); + ASSERT_FALSE(nan.is_multiple_of(nan)); + for (int i = 0; i < (1 << 31); i += 1023) { + ASSERT_TRUE(NoOverflowInt(i).is_multiple_of(one)); + ASSERT_TRUE(NoOverflowInt(-i).is_multiple_of(one)); + ASSERT_FALSE(NoOverflowInt(i).is_multiple_of(zero)); + ASSERT_FALSE(NoOverflowInt(-i).is_multiple_of(zero)); + } + ASSERT_TRUE(NoOverflowInt(33 * 7).is_multiple_of(NoOverflowInt(33))); + ASSERT_TRUE(NoOverflowInt(13 * 5).is_multiple_of(NoOverflowInt(5))); + ASSERT_FALSE(NoOverflowInt(7).is_multiple_of(NoOverflowInt(5))); +} + diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java index a94004d8e26..c8e8bd337ad 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java @@ -33,7 +33,7 @@ /* * @test - * @bug 8318446 8331054 8331311 + * @bug 8318446 8331054 8331311 8335392 * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / @@ -42,7 +42,7 @@ /* * @test - * @bug 8318446 8331054 8331311 + * @bug 8318446 8331054 8331311 8335392 * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / @@ -75,6 +75,17 @@ public class TestMergeStores { long vL1; long vL2; + static int zero0 = 0; + static int zero1 = 0; + static int zero2 = 0; + static int zero3 = 0; + static int zero4 = 0; + static int zero5 = 0; + static int zero6 = 0; + static int zero7 = 0; + static int zero8 = 0; + static int zero9 = 0; + interface TestFunction { Object[] run(boolean isWarmUp, int rnd); } @@ -154,6 +165,15 @@ public TestMergeStores() { testGroups.get("test7BE").put("test7RBE", (_,_) -> { return test7RBE(aB.clone(), offset1, vI1); }); testGroups.get("test7BE").put("test7aBE", (_,_) -> { return test7aBE(aB.clone(), offset1, vI1); }); + testGroups.put("test10", new HashMap()); + testGroups.get("test10").put("test10R", (_,_) -> { return test10R(aB.clone()); }); + testGroups.get("test10").put("test10a", (_,_) -> { return test10a(aB.clone()); }); + testGroups.get("test10").put("test10b", (_,_) -> { return test10b(aB.clone()); }); + testGroups.get("test10").put("test10c", (_,_) -> { return test10c(aB.clone()); }); + testGroups.get("test10").put("test10d", (_,_) -> { return test10d(aB.clone()); }); + testGroups.get("test10").put("test10e", (_,_) -> { return test10e(aB.clone()); }); + testGroups.get("test10").put("test10f", (_,_) -> { return test10f(aB.clone()); }); + testGroups.put("test100", new HashMap()); testGroups.get("test100").put("test100R", (_,_) -> { return test100R(aS.clone(), offset1); }); testGroups.get("test100").put("test100a", (_,_) -> { return test100a(aS.clone(), offset1); }); @@ -234,6 +254,10 @@ public TestMergeStores() { testGroups.get("test600").put("test600R", (_,i) -> { return test600R(aB.clone(), aI.clone(), i); }); testGroups.get("test600").put("test600a", (_,i) -> { return test600a(aB.clone(), aI.clone(), i); }); + testGroups.put("test601", new HashMap()); + testGroups.get("test601").put("test601R", (_,i) -> { return test601R(aB.clone(), aI.clone(), i, offset1); }); + testGroups.get("test601").put("test601a", (_,i) -> { return test601a(aB.clone(), aI.clone(), i, offset1); }); + testGroups.put("test700", new HashMap()); testGroups.get("test700").put("test700R", (_,i) -> { return test700R(aI.clone(), i); }); testGroups.get("test700").put("test700a", (_,i) -> { return test700a(aI.clone(), i); }); @@ -274,6 +298,12 @@ public TestMergeStores() { "test5a", "test6a", "test7a", + "test10a", + "test10b", + "test10c", + "test10d", + "test10e", + "test10f", "test7aBE", "test100a", "test101a", @@ -292,6 +322,7 @@ public TestMergeStores() { "test501aBE", "test502aBE", "test600a", + "test601a", "test700a", "test800a", "test800aBE"}) @@ -611,9 +642,8 @@ static Object[] test1e(byte[] a) { } @Test - // Disabled by JDK-8335390, to be enabled again by JDK-8335392. - // @IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, - // applyIf = {"UseUnalignedAccesses", "true"}) + @IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, + applyIf = {"UseUnalignedAccesses", "true"}) static Object[] test1f(byte[] a) { UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 0, (byte)0xbe); UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 1, (byte)0xba); @@ -1124,6 +1154,145 @@ static Object[] test7aBE(byte[] a, int offset1, int v1) { return new Object[]{ a }; } + @DontCompile + static Object[] test10R(byte[] a) { + int zero = zero0 + zero1 + zero2 + zero3 + zero4 + + zero5 + zero6 + zero7 + zero8 + zero9; + a[zero + 0] = 'h'; + a[zero + 1] = 'e'; + a[zero + 2] = 'l'; + a[zero + 3] = 'l'; + a[zero + 4] = 'o'; + a[zero + 5] = ' '; + a[zero + 6] = ':'; + a[zero + 7] = ')'; + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8", // no merge + IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"}) + static Object[] test10a(byte[] a) { + // We have 11 summands: 10x zero variable + 1x array base. + // Parsing only allows 10 summands -> does not merge the stores. + int zero = zero0 + zero1 + zero2 + zero3 + zero4 + + zero5 + zero6 + zero7 + zero8 + zero9; + a[zero + 0] = 'h'; + a[zero + 1] = 'e'; + a[zero + 2] = 'l'; + a[zero + 3] = 'l'; + a[zero + 4] = 'o'; + a[zero + 5] = ' '; + a[zero + 6] = ':'; + a[zero + 7] = ')'; + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1", // 1 left in uncommon trap path of RangeCheck + IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, // all merged + applyIf = {"UseUnalignedAccesses", "true"}) + static Object[] test10b(byte[] a) { + int zero = zero0 + zero1 + zero2 + zero3 + zero4 + + zero5 + zero6 + zero7 + zero8; + // We have 10 summands: 9x zero variable + 1x array base. + // Parsing allows 10 summands, so this should merge the stores. + a[zero + 0] = 'h'; + a[zero + 1] = 'e'; + a[zero + 2] = 'l'; + a[zero + 3] = 'l'; + a[zero + 4] = 'o'; + a[zero + 5] = ' '; + a[zero + 6] = ':'; + a[zero + 7] = ')'; + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1", // 1 left in uncommon trap path of RangeCheck + IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, // all merged + applyIf = {"UseUnalignedAccesses", "true"}) + static Object[] test10c(byte[] a) { + int zero = 7 * zero0 + 7 * zero1 + 7 * zero2 + 7 * zero3 + 7 * zero4 + + 7 * zero5 + 7 * zero6 + 7 * zero7 + 7 * zero8; + // The "7 * zero" is split into "zero << 3 - zero". But the parsing combines it again, lowering the summand count. + // We have 10 summands: 9x zero variable + 1x array base. + // Parsing allows 10 summands, so this should merge the stores. + a[zero + 0] = 'h'; + a[zero + 1] = 'e'; + a[zero + 2] = 'l'; + a[zero + 3] = 'l'; + a[zero + 4] = 'o'; + a[zero + 5] = ' '; + a[zero + 6] = ':'; + a[zero + 7] = ')'; + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, // all merged + applyIf = {"UseUnalignedAccesses", "true"}) + static Object[] test10d(byte[] a) { + // Summand is subtracted from itself -> scale = 0 -> should be removed from list. + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 0) - zero0, (byte)'h'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 1) - zero0, (byte)'e'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 2) - zero0, (byte)'l'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 3) - zero0, (byte)'l'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 4) - zero0, (byte)'o'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 5) - zero0, (byte)' '); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 6) - zero0, (byte)':'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 7) - zero0, (byte)')'); + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, // all merged + applyIf = {"UseUnalignedAccesses", "true"}) + static Object[] test10e(byte[] a) { + // Summand is subtracted from itself -> scale = 0 -> should be removed from list. Thus equal to if not present at all. + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 0) - zero0, (byte)'h'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 1) - zero0, (byte)'e'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 2) - zero0, (byte)'l'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + (long)(zero0 + 3) - zero0, (byte)'l'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 4, (byte)'o'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 5, (byte)' '); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 6, (byte)':'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 7, (byte)')'); + return new Object[]{ a }; + } + + @Test + @IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8", // no merge + IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"}) + static Object[] test10f(byte[] a) { + int big = 1 << 29; + // Adding up the scales overflows -> no merge. + long offset = zero9 * big + zero9 * big + zero9 * big + zero9 * big; + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + 0, (byte)'h'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + 1, (byte)'e'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + 2, (byte)'l'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + 3, (byte)'l'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + 4, (byte)'o'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + 5, (byte)' '); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + 6, (byte)':'); + UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + 7, (byte)')'); + return new Object[]{ a }; + } + @DontCompile static Object[] test100R(short[] a, int offset) { a[offset + 0] = (short)0x0100; @@ -1560,15 +1729,12 @@ static Object[] test400R(int[] a) { } @Test - // We must be careful with mismatched accesses on arrays: - // An int-array can have about 2x max_int size, and hence if we address bytes in it, we can have int-overflows. - // We might consider addresses (x + 0) and (x + 1) as adjacent, even if x = max_int, and therefore the second - // address overflows and is not adjacent at all. - // Therefore, we should only consider stores that have the same size as the element type of the array. - @IR(counts = {IRNode.STORE_B_OF_CLASS, "int\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8", // no merging + // All constants are known, and AddI can be converted to AddL safely, hence the stores can be merged. + @IR(counts = {IRNode.STORE_B_OF_CLASS, "int\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", IRNode.STORE_C_OF_CLASS, "int\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", IRNode.STORE_I_OF_CLASS, "int\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", - IRNode.STORE_L_OF_CLASS, "int\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"}) + IRNode.STORE_L_OF_CLASS, "int\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, // all merged + applyIf = {"UseUnalignedAccesses", "true"}) static Object[] test400a(int[] a) { UNSAFE.putByte(a, UNSAFE.ARRAY_INT_BASE_OFFSET + 0, (byte)0xbe); UNSAFE.putByte(a, UNSAFE.ARRAY_INT_BASE_OFFSET + 1, (byte)0xba); @@ -1858,7 +2024,11 @@ static Object[] test600R(byte[] aB, int[] aI, int i) { } @Test - @IR(counts = {IRNode.STORE_B_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8"}) // note: bottom type + @IR(counts = {IRNode.STORE_B_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_C_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_I_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_L_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, // all merged + applyIf = {"UseUnalignedAccesses", "true"}) static Object[] test600a(byte[] aB, int[] aI, int i) { Object a = null; long base = 0; @@ -1869,7 +2039,7 @@ static Object[] test600a(byte[] aB, int[] aI, int i) { a = aI; base = UNSAFE.ARRAY_INT_BASE_OFFSET; } - // array a is an aryptr, but its element type is unknown, i.e. bottom. + // Array type is unknown, i.e. bottom[]. But all AddI can be safely converted to AddL -> safe to merge. UNSAFE.putByte(a, base + 0, (byte)0xbe); UNSAFE.putByte(a, base + 1, (byte)0xba); UNSAFE.putByte(a, base + 2, (byte)0xad); @@ -1881,6 +2051,63 @@ static Object[] test600a(byte[] aB, int[] aI, int i) { return new Object[]{ aB, aI }; } + @DontCompile + static Object[] test601R(byte[] aB, int[] aI, int i, int offset1) { + Object a = null; + long base = 0; + if (i % 2 == 0) { + a = aB; + base = UNSAFE.ARRAY_BYTE_BASE_OFFSET; + } else { + a = aI; + base = UNSAFE.ARRAY_INT_BASE_OFFSET; + } + UNSAFE.putByte(a, base + (offset1 + 0), (byte)0xbe); + UNSAFE.putByte(a, base + (offset1 + 1), (byte)0xba); + UNSAFE.putByte(a, base + (offset1 + 2), (byte)0xad); + UNSAFE.putByte(a, base + (offset1 + 3), (byte)0xba); + UNSAFE.putByte(a, base + (offset1 + 4), (byte)0xef); + UNSAFE.putByte(a, base + (offset1 + 5), (byte)0xbe); + UNSAFE.putByte(a, base + (offset1 + 6), (byte)0xad); + UNSAFE.putByte(a, base + (offset1 + 7), (byte)0xde); + return new Object[]{ aB, aI }; + } + + @Test + @IR(counts = {IRNode.STORE_B_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8", // nothing merged + IRNode.STORE_C_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_I_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_L_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"}, + applyIfPlatform = {"64-bit", "true"}) + @IR(counts = {IRNode.STORE_B_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_C_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_I_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0", + IRNode.STORE_L_OF_CLASS, "bottom\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, // all merged + applyIf = {"UseUnalignedAccesses", "true"}, + applyIfPlatform = {"32-bit", "true"}) + static Object[] test601a(byte[] aB, int[] aI, int i, int offset1) { + Object a = null; + long base = 0; + if (i % 2 == 0) { + a = aB; + base = UNSAFE.ARRAY_BYTE_BASE_OFFSET; + } else { + a = aI; + base = UNSAFE.ARRAY_INT_BASE_OFFSET; + } + // Array type is unknown, i.e. bottom[]. Hence we do not know the element size of the array. + // Thus, on 64-bits systems merging is not safe, there could be overflows. + UNSAFE.putByte(a, base + (offset1 + 0), (byte)0xbe); + UNSAFE.putByte(a, base + (offset1 + 1), (byte)0xba); + UNSAFE.putByte(a, base + (offset1 + 2), (byte)0xad); + UNSAFE.putByte(a, base + (offset1 + 3), (byte)0xba); + UNSAFE.putByte(a, base + (offset1 + 4), (byte)0xef); + UNSAFE.putByte(a, base + (offset1 + 5), (byte)0xbe); + UNSAFE.putByte(a, base + (offset1 + 6), (byte)0xad); + UNSAFE.putByte(a, base + (offset1 + 7), (byte)0xde); + return new Object[]{ aB, aI }; + } + @DontCompile static Object[] test700R(int[] a, long v1) { a[0] = (int)(v1 >> -1); diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java b/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java new file mode 100644 index 00000000000..a5302d1b515 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java @@ -0,0 +1,426 @@ +/* + * 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 compiler.c2; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.HashMap; +import java.util.Random; +import java.lang.foreign.*; + +/* + * @test id=byte-array + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment ByteArray + */ + +/* + * @test id=char-array + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment CharArray + */ + +/* + * @test id=short-array + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment ShortArray + */ + +/* + * @test id=int-array + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment IntArray + */ + +/* + * @test id=long-array + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment LongArray + */ + +/* + * @test id=float-array + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment FloatArray + */ + +/* + * @test id=double-array + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment DoubleArray + */ + +/* + * @test id=byte-buffer + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment ByteBuffer + */ + +/* + * @test id=byte-buffer-direct + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment ByteBufferDirect + */ + +/* + * @test id=native + * @bug 8335392 + * @summary Test MergeStores optimization for MemorySegment + * @library /test/lib / + * @run driver compiler.c2.TestMergeStoresMemorySegment Native + */ + +// FAILS: mixed providers currently do not merge stores. Maybe there is some inlining issue. +// /* +// * @test id=mixed-array +// * @bug 8335392 +// * @summary Test MergeStores optimization for MemorySegment +// * @library /test/lib / +// * @run driver compiler.c2.TestMergeStoresMemorySegment MixedArray +// */ +// +// /* +// * @test id=MixedBuffer +// * @bug 8335392 +// * @summary Test MergeStores optimization for MemorySegment +// * @library /test/lib / +// * @run driver compiler.c2.TestMergeStoresMemorySegment MixedBuffer +// */ +// +// /* +// * @test id=mixed +// * @bug 8335392 +// * @summary Test MergeStores optimization for MemorySegment +// * @library /test/lib / +// * @run driver compiler.c2.TestMergeStoresMemorySegment Mixed +// */ + +public class TestMergeStoresMemorySegment { + public static void main(String[] args) { + for (String unaligned : new String[]{"-XX:-UseUnalignedAccesses", "-XX:+UseUnalignedAccesses"}) { + TestFramework framework = new TestFramework(TestMergeStoresMemorySegmentImpl.class); + framework.addFlags("-DmemorySegmentProviderNameForTestVM=" + args[0], unaligned); + framework.start(); + } + } +} + +class TestMergeStoresMemorySegmentImpl { + static final int BACKING_SIZE = 1024 * 8; + static final Random RANDOM = Utils.getRandomInstance(); + + private static final String START = "(\\d+(\\s){2}("; + private static final String MID = ".*)+(\\s){2}===.*"; + private static final String END = ")"; + + // Custom Regex: allows us to only match Store that come from MemorySegment internals. + private static final String REGEX_STORE_B_TO_MS_FROM_B = START + "StoreB" + MID + END + "ScopedMemoryAccess::putByteInternal"; + private static final String REGEX_STORE_C_TO_MS_FROM_B = START + "StoreC" + MID + END + "ScopedMemoryAccess::putByteInternal"; + private static final String REGEX_STORE_I_TO_MS_FROM_B = START + "StoreI" + MID + END + "ScopedMemoryAccess::putByteInternal"; + private static final String REGEX_STORE_L_TO_MS_FROM_B = START + "StoreL" + MID + END + "ScopedMemoryAccess::putByteInternal"; + + interface TestFunction { + Object[] run(); + } + + interface MemorySegmentProvider { + MemorySegment newMemorySegment(); + } + + static MemorySegmentProvider provider; + + static { + String providerName = System.getProperty("memorySegmentProviderNameForTestVM"); + provider = switch (providerName) { + case "ByteArray" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfByteArray; + case "CharArray" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfCharArray; + case "ShortArray" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfShortArray; + case "IntArray" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfIntArray; + case "LongArray" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfLongArray; + case "FloatArray" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfFloatArray; + case "DoubleArray" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfDoubleArray; + case "ByteBuffer" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfByteBuffer; + case "ByteBufferDirect" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfByteBufferDirect; + case "Native" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfNative; + case "MixedArray" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfMixedArray; + case "MixedBuffer" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfMixedBuffer; + case "Mixed" -> TestMergeStoresMemorySegmentImpl::newMemorySegmentOfMixed; + default -> throw new RuntimeException("Test argument not recognized: " + providerName); + }; + } + + // List of tests + Map tests = new HashMap<>(); + + // List of golden values, the results from the first run before compilation + Map golds = new HashMap<>(); + + public TestMergeStoresMemorySegmentImpl () { + // Generate two MemorySegments as inputs + MemorySegment a = newMemorySegment(); + MemorySegment b = newMemorySegment(); + fillRandom(a); + fillRandom(b); + + // Future Work: add more test cases. For now, the issue seems to be that + // RangeCheck smearing does not remove the RangeChecks, thus + // we can only ever merge two stores. + // + // Ideas for more test cases, once they are better optimized: + // + // Have about 3 variables, each either int or long. Add all in int or + // long. Give them different scales. Compute the address in the same + // expression or separately. Use different element store sizes (BCIL). + // + tests.put("test_xxx", () -> test_xxx(copy(a), 5, 11, 31)); + tests.put("test_yyy", () -> test_yyy(copy(a), 5, 11, 31)); + tests.put("test_zzz", () -> test_zzz(copy(a), 5, 11, 31)); + + // Compute gold value for all test methods before compilation + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + Object[] gold = test.run(); + golds.put(name, gold); + } + } + + MemorySegment newMemorySegment() { + return provider.newMemorySegment(); + } + + MemorySegment copy(MemorySegment src) { + MemorySegment dst = newMemorySegment(); + MemorySegment.copy(src, 0, dst, 0, src.byteSize()); + return dst; + } + + static MemorySegment newMemorySegmentOfByteArray() { + return MemorySegment.ofArray(new byte[BACKING_SIZE]); + } + + static MemorySegment newMemorySegmentOfCharArray() { + return MemorySegment.ofArray(new char[BACKING_SIZE / 2]); + } + + static MemorySegment newMemorySegmentOfShortArray() { + return MemorySegment.ofArray(new short[BACKING_SIZE / 2]); + } + + static MemorySegment newMemorySegmentOfIntArray() { + return MemorySegment.ofArray(new int[BACKING_SIZE / 4]); + } + + static MemorySegment newMemorySegmentOfLongArray() { + return MemorySegment.ofArray(new long[BACKING_SIZE / 8]); + } + + static MemorySegment newMemorySegmentOfFloatArray() { + return MemorySegment.ofArray(new float[BACKING_SIZE / 4]); + } + + static MemorySegment newMemorySegmentOfDoubleArray() { + return MemorySegment.ofArray(new double[BACKING_SIZE / 8]); + } + + static MemorySegment newMemorySegmentOfByteBuffer() { + return MemorySegment.ofBuffer(ByteBuffer.allocate(BACKING_SIZE)); + } + + static MemorySegment newMemorySegmentOfByteBufferDirect() { + return MemorySegment.ofBuffer(ByteBuffer.allocateDirect(BACKING_SIZE)); + } + + static MemorySegment newMemorySegmentOfNative() { + // Auto arena: GC decides when there is no reference to the MemorySegment, + // and then it deallocates the backing memory. + return Arena.ofAuto().allocate(BACKING_SIZE, 1); + } + + static MemorySegment newMemorySegmentOfMixedArray() { + switch(RANDOM.nextInt(7)) { + case 0 -> { return newMemorySegmentOfByteArray(); } + case 1 -> { return newMemorySegmentOfCharArray(); } + case 2 -> { return newMemorySegmentOfShortArray(); } + case 3 -> { return newMemorySegmentOfIntArray(); } + case 4 -> { return newMemorySegmentOfLongArray(); } + case 5 -> { return newMemorySegmentOfFloatArray(); } + default -> { return newMemorySegmentOfDoubleArray(); } + } + } + + static MemorySegment newMemorySegmentOfMixedBuffer() { + switch (RANDOM.nextInt(2)) { + case 0 -> { return newMemorySegmentOfByteBuffer(); } + default -> { return newMemorySegmentOfByteBufferDirect(); } + } + } + + static MemorySegment newMemorySegmentOfMixed() { + switch (RANDOM.nextInt(3)) { + case 0 -> { return newMemorySegmentOfMixedArray(); } + case 1 -> { return newMemorySegmentOfMixedBuffer(); } + default -> { return newMemorySegmentOfNative(); } + } + } + + static void fillRandom(MemorySegment data) { + for (int i = 0; i < (int)data.byteSize(); i += 8) { + data.set(ValueLayout.JAVA_LONG_UNALIGNED, i, RANDOM.nextLong()); + } + } + + + static void verify(String name, Object[] gold, Object[] result) { + if (gold.length != result.length) { + throw new RuntimeException("verify " + name + ": not the same number of outputs: gold.length = " + + gold.length + ", result.length = " + result.length); + } + for (int i = 0; i < gold.length; i++) { + Object g = gold[i]; + Object r = result[i]; + if (g == r) { + throw new RuntimeException("verify " + name + ": should be two separate objects (with identical content):" + + " gold[" + i + "] == result[" + i + "]"); + } + + if (!(g instanceof MemorySegment && r instanceof MemorySegment)) { + throw new RuntimeException("verify " + name + ": only MemorySegment supported, i=" + i); + } + + MemorySegment mg = (MemorySegment)g; + MemorySegment mr = (MemorySegment)r; + + if (mg.byteSize() != mr.byteSize()) { + throw new RuntimeException("verify " + name + ": MemorySegment must have same byteSize:" + + " gold[" + i + "].byteSize = " + mg.byteSize() + + " result[" + i + "].byteSize = " + mr.byteSize()); + } + + for (int j = 0; j < (int)mg.byteSize(); j++) { + byte vg = mg.get(ValueLayout.JAVA_BYTE, j); + byte vr = mr.get(ValueLayout.JAVA_BYTE, j); + if (vg != vr) { + throw new RuntimeException("verify " + name + ": MemorySegment must have same content:" + + " gold[" + i + "][" + j + "] = " + vg + + " result[" + i + "][" + j + "] = " + vr); + } + } + } + } + + @Run(test = { "test_xxx", "test_yyy", "test_zzz" }) + void runTests() { + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Recall gold value from before compilation + Object[] gold = golds.get(name); + // Compute new result + Object[] result = test.run(); + // Compare gold and new result + verify(name, gold, result); + } + } + + @Test + @IR(counts = {REGEX_STORE_B_TO_MS_FROM_B, "<=5", // 4x RC + REGEX_STORE_C_TO_MS_FROM_B, ">=3", // 4x merged + REGEX_STORE_I_TO_MS_FROM_B, "0", + REGEX_STORE_L_TO_MS_FROM_B, "0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseUnalignedAccesses", "true"}) + static Object[] test_xxx(MemorySegment a, int xI, int yI, int zI) { + // All RangeChecks remain -> RC smearing not good enough? + a.set(ValueLayout.JAVA_BYTE, (long)(xI + yI + zI + 0), (byte)'h'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI + yI + zI + 1), (byte)'e'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI + yI + zI + 2), (byte)'l'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI + yI + zI + 3), (byte)'l'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI + yI + zI + 4), (byte)'o'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI + yI + zI + 5), (byte)' '); + a.set(ValueLayout.JAVA_BYTE, (long)(xI + yI + zI + 6), (byte)':'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI + yI + zI + 7), (byte)')'); + return new Object[]{ a }; + } + + @Test + @IR(counts = {REGEX_STORE_B_TO_MS_FROM_B, "<=5", // 4x RC + REGEX_STORE_C_TO_MS_FROM_B, ">=3", // 4x merged + REGEX_STORE_I_TO_MS_FROM_B, "0", + REGEX_STORE_L_TO_MS_FROM_B, "0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseUnalignedAccesses", "true"}) + static Object[] test_yyy(MemorySegment a, int xI, int yI, int zI) { + // All RangeChecks remain -> RC smearing not good enough? + a.set(ValueLayout.JAVA_BYTE, (long)(xI) + (long)(yI) + (long)(zI) + 0L, (byte)'h'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI) + (long)(yI) + (long)(zI) + 1L, (byte)'e'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI) + (long)(yI) + (long)(zI) + 2L, (byte)'l'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI) + (long)(yI) + (long)(zI) + 3L, (byte)'l'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI) + (long)(yI) + (long)(zI) + 4L, (byte)'o'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI) + (long)(yI) + (long)(zI) + 5L, (byte)' '); + a.set(ValueLayout.JAVA_BYTE, (long)(xI) + (long)(yI) + (long)(zI) + 6L, (byte)':'); + a.set(ValueLayout.JAVA_BYTE, (long)(xI) + (long)(yI) + (long)(zI) + 7L, (byte)')'); + return new Object[]{ a }; + } + + @Test + @IR(counts = {REGEX_STORE_B_TO_MS_FROM_B, "<=5", // 4x RC + REGEX_STORE_C_TO_MS_FROM_B, ">=3", // 4x merged + REGEX_STORE_I_TO_MS_FROM_B, "0", + REGEX_STORE_L_TO_MS_FROM_B, "0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseUnalignedAccesses", "true"}) + static Object[] test_zzz(MemorySegment a, long xL, long yL, long zL) { + // All RangeChecks remain -> RC smearing not good enough? + a.set(ValueLayout.JAVA_BYTE, xL + yL + zL + 0L, (byte)'h'); + a.set(ValueLayout.JAVA_BYTE, xL + yL + zL + 1L, (byte)'e'); + a.set(ValueLayout.JAVA_BYTE, xL + yL + zL + 2L, (byte)'l'); + a.set(ValueLayout.JAVA_BYTE, xL + yL + zL + 3L, (byte)'l'); + a.set(ValueLayout.JAVA_BYTE, xL + yL + zL + 4L, (byte)'o'); + a.set(ValueLayout.JAVA_BYTE, xL + yL + zL + 5L, (byte)' '); + a.set(ValueLayout.JAVA_BYTE, xL + yL + zL + 6L, (byte)':'); + a.set(ValueLayout.JAVA_BYTE, xL + yL + zL + 7L, (byte)')'); + return new Object[]{ a }; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java b/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java index dbfdfe68957..3b65272c3c7 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java @@ -52,6 +52,10 @@ public class TestMergeStoresUnsafeArrayPointer { static final long ANCHOR = BYTE_SIZE / 2; static int four = 4; + static int max_int = Integer.MAX_VALUE; + static int min_int = Integer.MIN_VALUE; + static int val_2_to_30 = (1 << 30); + static int large_by_53 = (int)((1L << 31) / 53L + 1L); public static void main(String[] args) { System.out.println("Allocate big array of SIZE = " + SIZE); @@ -95,6 +99,103 @@ public static void main(String[] args) { } } + val = 0; + System.out.println("test3"); + for (int i = 0; i < 100_000; i++) { + testClear(big); + test3(big, ANCHOR); + long sum = testSum(big); + if (i == 0) { + val = sum; + } else { + if (sum != val) { + System.out.println("ERROR: test3 had wrong value: " + val + " != " + sum); + errors++; + break; + } + } + } + + val = 0; + System.out.println("test4"); + for (int i = 0; i < 100_000; i++) { + testClear(big); + test4(big, ANCHOR); + long sum = testSum(big); + if (i == 0) { + val = sum; + } else { + if (sum != val) { + System.out.println("ERROR: test4 had wrong value: " + val + " != " + sum); + errors++; + break; + } + } + } + + val = 0; + System.out.println("test5"); + for (int i = 0; i < 100_000; i++) { + testClear(big); + test5(big, ANCHOR); + long sum = testSum(big); + if (i == 0) { + val = sum; + } else { + if (sum != val) { + System.out.println("ERROR: test5 had wrong value: " + val + " != " + sum); + errors++; + break; + } + } + } + + val = 0; + System.out.println("test6"); + for (int i = 0; i < 100_000; i++) { + testClear(big); + test6(big, ANCHOR); + long sum = testSum(big); + if (i == 0) { + val = sum; + } else { + if (sum != val) { + System.out.println("ERROR: test6 had wrong value: " + val + " != " + sum); + errors++; + break; + } + } + } + + val = 0; + System.out.println("test7"); + for (int i = 0; i < 100_000; i++) { + testClear(big); + test7(big, ANCHOR); + long sum = testSum(big); + if (i == 0) { + val = sum; + } else { + if (sum != val) { + System.out.println("ERROR: test7 had wrong value: " + val + " != " + sum); + errors++; + break; + } + } + } + + // No result verification here. We only want to make sure we do not hit asserts. + System.out.println("test8 and test9"); + for (int i = 0; i < 100_000; i++) { + test8a(big, ANCHOR); + test8b(big, ANCHOR); + test8c(big, ANCHOR); + test8d(big, ANCHOR); + test9a(big, ANCHOR); + test9b(big, ANCHOR); + test9c(big, ANCHOR); + } + if (errors > 0) { throw new RuntimeException("ERRORS: " + errors); } @@ -129,4 +230,95 @@ static void test2(int[] a, long anchor) { UNSAFE.putInt(a, base + 0 + (long)(four + Integer.MAX_VALUE), 0x42424242); UNSAFE.putInt(a, base + Integer.MAX_VALUE + (long)(four + 4 ), 0x66666666); } + + // Test: if MergeStores is applied this can lead to wrong results + // -> AddI needs overflow check. + static void test3(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putInt(a, base + (long)(max_int + 0), 0x42424242); + UNSAFE.putInt(a, base + (long)(max_int + 4), 0x66666666); + } + + // Test: "max_int - four" cannot be parsed further, but would not make a difference here. + static void test4(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putInt(a, base + (long)(min_int - four) + 0, 0x42424242); + UNSAFE.putInt(a, base + (long)(min_int - four) + 4, 0x66666666); + } + + // Test: if MergeStores is applied this can lead to wrong results + // -> SubI needs overflow check. + static void test5(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putInt(a, base + (long)(min_int) - (long)(four) + 0, 0x42424242); // no overflow + UNSAFE.putInt(a, base + (long)(min_int - four) + 4, 0x66666666); // overflow + } + + // Test: if MergeStores is applied this can lead to wrong results + // -> LShiftI needs overflow check. + static void test6(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putInt(a, base + (long)(2 * val_2_to_30) + 0, 0x42424242); // overflow + UNSAFE.putInt(a, base + 2L * (long)(val_2_to_30) + 4, 0x66666666); // no overflow + } + + // Test: if MergeStores is applied this can lead to wrong results + // -> MulI needs overflow check. + static void test7(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putInt(a, base + (long)(53 * large_by_53) + 0, 0x42424242); // overflow + UNSAFE.putInt(a, base + 53L * (long)(large_by_53) + 4, 0x66666666); // no overflow + } + + // Test: check if large distance leads to assert + static void test8a(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putByte(a, base + (1L << 11) + 0, (byte)42); + UNSAFE.putByte(a, base + (1L << 11) + (1L << 30), (byte)11); + } + + // Test: check if large distance leads to assert + static void test8b(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putByte(a, base + (1L << 11) + (1L << 30), (byte)11); + UNSAFE.putByte(a, base + (1L << 11) + 0, (byte)42); + } + + // Test: check if large distance leads to assert + static void test8c(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putByte(a, base - (1L << 11) - 0, (byte)42); + UNSAFE.putByte(a, base - (1L << 11) - (1L << 30), (byte)11); + } + + // Test: check if large distance leads to assert + static void test8d(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putByte(a, base - (1L << 11) - (1L << 30), (byte)11); + UNSAFE.putByte(a, base - (1L << 11) - 0, (byte)42); + } + + // Test: check if large distance leads to assert + // case: bad distance: NaN + static void test9a(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putByte(a, base - 100, (byte)42); + UNSAFE.putByte(a, base - 100 + (1L << 31), (byte)11); + } + + // Test: check if large distance leads to assert + // case: just before NaN, it is still a valid distance for MemPointer aliasing. + static void test9b(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putByte(a, base - 100, (byte)42); + UNSAFE.putByte(a, base - 100 + (1L << 31) - 1, (byte)11); + } + + // Test: check if large distance leads to assert + // case: constant too large + static void test9c(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putByte(a, base, (byte)42); + UNSAFE.putByte(a, base + (1L << 31), (byte)11); + } } diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java index 93d98116ecc..809ec01f495 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java @@ -41,12 +41,12 @@ @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Warmup(iterations = 3, time = 3) -@Measurement(iterations = 3, time = 3) -@Fork(value = 3, jvmArgs = { +@Warmup(iterations = 2, time = 1) +@Measurement(iterations = 3, time = 1) +@Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.util=ALL-UNNAMED"}) -@State(Scope.Benchmark) +@State(Scope.Thread) public class MergeStores { public static final int RANGE = 100; @@ -66,6 +66,7 @@ public class MergeStores { public static byte[] aB = new byte[RANGE]; public static short[] aS = new short[RANGE]; public static int[] aI = new int[RANGE]; + public static long native_adr = UNSAFE.allocateMemory(RANGE * 8); // ------------------------------------------- // ------- Little-Endian API ---------- @@ -691,4 +692,59 @@ public int[] store_I2_zero_offs_nonalloc_direct() { aI[offset + 1] = 0; return aI; } + + @Benchmark + public void store_unsafe_B8_L_offs_noalloc_direct() { + UNSAFE.putByte(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 0, (byte)(vL >> 0 )); + UNSAFE.putByte(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 1, (byte)(vL >> 8 )); + UNSAFE.putByte(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 2, (byte)(vL >> 16)); + UNSAFE.putByte(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 3, (byte)(vL >> 24)); + UNSAFE.putByte(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 4, (byte)(vL >> 32)); + UNSAFE.putByte(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 5, (byte)(vL >> 40)); + UNSAFE.putByte(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 6, (byte)(vL >> 48)); + UNSAFE.putByte(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 7, (byte)(vL >> 56)); + } + + @Benchmark + public void store_unsafe_B8_L_offs_noalloc_unsafe() { + UNSAFE.putLongUnaligned(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 0, vL); + } + + @Benchmark + public void store_unsafe_C4_L_offs_noalloc_direct() { + UNSAFE.putChar(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 0, (char)(vL >> 0 )); + UNSAFE.putChar(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 2, (char)(vL >> 16)); + UNSAFE.putChar(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 4, (char)(vL >> 32)); + UNSAFE.putChar(aB, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset + 6, (char)(vL >> 48)); + } + + @Benchmark + public void store_unsafe_native_B8_L_offs_noalloc_direct() { + UNSAFE.putByte(null, native_adr + offset + 0, (byte)(vL >> 0 )); + UNSAFE.putByte(null, native_adr + offset + 1, (byte)(vL >> 8 )); + UNSAFE.putByte(null, native_adr + offset + 2, (byte)(vL >> 16)); + UNSAFE.putByte(null, native_adr + offset + 3, (byte)(vL >> 24)); + UNSAFE.putByte(null, native_adr + offset + 4, (byte)(vL >> 32)); + UNSAFE.putByte(null, native_adr + offset + 5, (byte)(vL >> 40)); + UNSAFE.putByte(null, native_adr + offset + 6, (byte)(vL >> 48)); + UNSAFE.putByte(null, native_adr + offset + 7, (byte)(vL >> 56)); + } + + @Benchmark + public void store_unsafe_native_C4_L_offs_noalloc_direct() { + UNSAFE.putChar(null, native_adr + offset + 0, (char)(vL >> 0 )); + UNSAFE.putChar(null, native_adr + offset + 2, (char)(vL >> 16)); + UNSAFE.putChar(null, native_adr + offset + 4, (char)(vL >> 32)); + UNSAFE.putChar(null, native_adr + offset + 6, (char)(vL >> 48)); + } + + @Benchmark + public void store_unsafe_native_B8_L_offs_noalloc_unsafe() { + UNSAFE.putLongUnaligned(null, native_adr + offset + 0, vL); + } + + @Fork(value = 1, jvmArgsPrepend = { + "-XX:+UnlockDiagnosticVMOptions", "-XX:-MergeStores" + }) + public static class MergeStoresDisabled extends MergeStores {} } From f62fc4844125cc20a91dc2be39ba05a2d3aca8cf Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 5 Nov 2024 11:47:42 +0000 Subject: [PATCH 04/23] 8342498: Add test for Allocation elimination after use as alignment reference by SuperWord Reviewed-by: thartmann, kvn --- ...TestEliminateAllocationWithCastP2XUse.java | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestEliminateAllocationWithCastP2XUse.java diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestEliminateAllocationWithCastP2XUse.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestEliminateAllocationWithCastP2XUse.java new file mode 100644 index 00000000000..416781d1b00 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestEliminateAllocationWithCastP2XUse.java @@ -0,0 +1,183 @@ +/* + * 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 compiler.loopopts.superword; + +/* + * @test + * @bug 8342498 + * @summary Test SuperWord, when it aligns to field-store, and the corresponding allocation is eliminated. + * @run driver compiler.loopopts.superword.TestEliminateAllocationWithCastP2XUse + * @run main/othervm -Xbatch + * -XX:-SplitIfBlocks -XX:LoopMaxUnroll=8 + * -XX:+UnlockDiagnosticVMOptions -XX:DominatorSearchLimit=45 + * compiler.loopopts.superword.TestEliminateAllocationWithCastP2XUse + */ + +public class TestEliminateAllocationWithCastP2XUse { + public static void main(String args[]) { + byte[] a = new byte[10_000]; + for (int i = 0; i < 10000; i++) { + test(a); + } + } + + // Summary: + // - Some B allocations are detected as NoEscape, but cannot be removed because of a field load. + // - The field loads cannot be LoadNode::split_through_phi because DominatorSearchLimit is too low + // for the dominates query to look through some IfNode / IfProj path. + // - We go into loop-opts. + // - In theory, the Stores of B::offset would be moved out of the loop. But we disable + // PhaseIdealLoop::try_move_store_after_loop by setting -XX:-SplitIfBlocks. + // - The field loads are folded away because of some MaxUnroll trick, where the val constant folds to 1. + // - SuperWord eventually kicks in, and vectorizes the array stores. + // - Since some vectorization has happened, SuperWord wants to align the main loop with a memory reference + // in the loop. The code here is not very smart, and just picks the memory reference that occurs the + // most often. But the B::offset stores occur more often than the array stores, and so we align to + // one of the B::offset stores. This inserts a CastP2X under the CheckCastPP of the B allocation. + // - Once loop opts is over, we eventually go into macro expansion. + // - During macro expansion, we now discover that the Allocations were marked NoEscape, and that by now + // there are no field loads any more: yay, we can remove the allocation! + // - ... except that there is the CastP2X from SuperWord alignment ... + // - The Allocation removal code wants to pattern match the CastP2X as part of a GC barrier, but then + // the pattern does not conform to the expecatation - it is after all from SuperWord. This leads to + // an assert, and SIGSEGV in product, at least with G1GC. + public static long test(byte[] a) { + // Delay val == 1 until loop-opts, with MaxUnroll trick. + int val = 0; + for (int i = 0; i < 4; i++) { + if ((i % 2) == 0) { + val = 1; + } + } + // during loop opts, we learn val == 1 + // But we don't know that during EscapeAnalysis (EA) yet. + + // 9 Allocations, discovered as NoEscape during EA. + B b1 = new B(); + B b2 = new B(); + B b3 = new B(); + B b4 = new B(); + B b5 = new B(); + B b6 = new B(); + B b7 = new B(); + B b8 = new B(); + B b9 = new B(); + + // Some path of IfNode / IfProj. + // Only folds away once we know val == 1 + // This delays the LoadNode::split_through_phi, because it needs a dominates call + // to succeed, but it cannot look through this path because we set -XX:DominatorSearchLimit=45 + // i.e. just a little too low to be able to look through. + // Without the LoadNode::split_through_phi before the end of EA, the Allocation cannot yet be + // removed, due to a "Field load", i.e. that Load for B::offset. + // But later, this path can actually fold away, when we know that val == 1. At that point, + // also the Load from B::offset folds away because LoadNode::split_through_phi succeeds + // At that point the B allocations have no Loads any more, and can be removed... but this only + // happens at macro expansion, after all loop opts. + if (val == 1010) { throw new RuntimeException("never"); } + if (val == 1020) { throw new RuntimeException("never"); } + if (val == 1030) { throw new RuntimeException("never"); } + if (val == 1040) { throw new RuntimeException("never"); } + if (val == 1060) { throw new RuntimeException("never"); } + if (val == 1070) { throw new RuntimeException("never"); } + if (val == 1080) { throw new RuntimeException("never"); } + if (val == 1090) { throw new RuntimeException("never"); } + + if (val == 2010) { throw new RuntimeException("never"); } + if (val == 2020) { throw new RuntimeException("never"); } + if (val == 2030) { throw new RuntimeException("never"); } + if (val == 2040) { throw new RuntimeException("never"); } + if (val == 2060) { throw new RuntimeException("never"); } + if (val == 2070) { throw new RuntimeException("never"); } + if (val == 2080) { throw new RuntimeException("never"); } + if (val == 2090) { throw new RuntimeException("never"); } + + if (val == 3010) { throw new RuntimeException("never"); } + if (val == 3020) { throw new RuntimeException("never"); } + if (val == 3030) { throw new RuntimeException("never"); } + if (val == 3040) { throw new RuntimeException("never"); } + if (val == 3060) { throw new RuntimeException("never"); } + if (val == 3070) { throw new RuntimeException("never"); } + if (val == 3080) { throw new RuntimeException("never"); } + if (val == 3090) { throw new RuntimeException("never"); } + + if (val == 4010) { throw new RuntimeException("never"); } + if (val == 4020) { throw new RuntimeException("never"); } + if (val == 4030) { throw new RuntimeException("never"); } + if (val == 4040) { throw new RuntimeException("never"); } + if (val == 4060) { throw new RuntimeException("never"); } + if (val == 4070) { throw new RuntimeException("never"); } + if (val == 4080) { throw new RuntimeException("never"); } + if (val == 4090) { throw new RuntimeException("never"); } + + long mulVal = 1; + for (int i = 0; i < a.length; i++) { + mulVal *= 3; + // We do some vector store, so that SuperWord succeeds, and creates the + // alignment code, which emits the CastP2X. + a[i]++; + // But we also have 9 Stores for the B::offset. + // SuperWord now sees more of these stores than of the array stores, and picks + // one of the B::offset stores as the alignment reference... creating a CastP2X + // for the CheckCastPP of the B allocation. + b1.offset = mulVal; + b2.offset = mulVal; + b3.offset = mulVal; + b4.offset = mulVal; + b5.offset = mulVal; + b6.offset = mulVal; + b7.offset = mulVal; + b8.offset = mulVal; + b9.offset = mulVal; + } + + // This folds the loads away, once we know val == 1 + // That happens during loop-opts, so after EA, but before macro expansion. + long ret = 0; + if (val == 42) { + ret = b1.offset + + b2.offset + + b3.offset + + b4.offset + + b5.offset + + b6.offset + + b7.offset + + b8.offset + + b9.offset; + } + + return ret; + } + + static class B { + // Add padding so that the old SuperWord::can_create_pairs accepts the field store to B.offset + long pad1 = 0; // at 16 + long pad2 = 0; // at 24 + long pad3 = 0; // at 32 + long pad4 = 0; // at 40 + long pad5 = 0; // at 48 + long pad6 = 0; // at 56 + long offset = 0; // offset at 64 bytes + } +} From 16feeb7a8e9a02fec4846179fcfbdc3a71b07fe5 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 5 Nov 2024 12:15:42 +0000 Subject: [PATCH 05/23] 8343547: Restore accidentally removed annotations in LambdaForm from ClassFile API port Reviewed-by: asotona --- .../classes/java/lang/invoke/ClassSpecializer.java | 14 ++++++++++++-- .../java/lang/invoke/InvokerBytecodeGenerator.java | 8 +++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java index 1ed7c422c98..8f934d6d67c 100644 --- a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java +++ b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java @@ -27,6 +27,7 @@ import java.lang.classfile.*; import java.lang.classfile.attribute.ExceptionsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.classfile.attribute.SourceFileAttribute; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; @@ -68,6 +69,9 @@ abstract class ClassSpecializer.SpeciesDat private static final ClassDesc CD_LambdaForm = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;"); private static final ClassDesc CD_BoundMethodHandle = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/BoundMethodHandle;"); + private static final RuntimeVisibleAnnotationsAttribute STABLE_ANNOTATION = RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(ConstantUtils.referenceClassDesc(Stable.class)) + ); private final Class topClass; private final Class keyType; @@ -615,7 +619,7 @@ Class generateConcreteSpeciesCode(String className, ClassSpecialize byte[] generateConcreteSpeciesCodeFile(String className0, ClassSpecializer.SpeciesData speciesData) { final ClassDesc classDesc = ClassDesc.of(className0); final ClassDesc superClassDesc = classDesc(speciesData.deriveSuperClass()); - return ClassFile.of().build(classDesc, new Consumer() { + return ClassFile.of().build(classDesc, new Consumer<>() { @Override public void accept(ClassBuilder clb) { clb.withFlags(ACC_FINAL | ACC_SUPER) @@ -623,7 +627,13 @@ public void accept(ClassBuilder clb) { .with(SourceFileAttribute.of(classDesc.displayName())) // emit static types and BMH_SPECIES fields - .withField(sdFieldName, CD_SPECIES_DATA, ACC_STATIC); + .withField(sdFieldName, CD_SPECIES_DATA, new Consumer<>() { + @Override + public void accept(FieldBuilder fb) { + fb.withFlags(ACC_STATIC) + .with(STABLE_ANNOTATION); + } + }); // handy holder for dealing with groups of typed values (ctor arguments and fields) class Var { diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index ec131d67f2b..ffd368f47c1 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -526,7 +526,9 @@ private boolean checkActualReceiver(CodeBuilder cob) { // Suppress method in backtraces displayed to the user, mark this method as // a compiled LambdaForm, then either force or prohibit inlining. public static final RuntimeVisibleAnnotationsAttribute LF_DONTINLINE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, DONTINLINE); + public static final RuntimeVisibleAnnotationsAttribute LF_DONTINLINE_PROFILE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, DONTINLINE, INJECTEDPROFILE); public static final RuntimeVisibleAnnotationsAttribute LF_FORCEINLINE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, FORCEINLINE); + public static final RuntimeVisibleAnnotationsAttribute LF_FORCEINLINE_PROFILE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, FORCEINLINE, INJECTEDPROFILE); /** * Generate an invoker method for the passed {@link LambdaForm}. @@ -586,7 +588,11 @@ public void accept(CodeBuilder cob) { if (PROFILE_GWT) { assert(name.arguments[0] instanceof Name n && n.refersTo(MethodHandleImpl.class, "profileBoolean")); - mb.with(RuntimeVisibleAnnotationsAttribute.of(List.of(INJECTEDPROFILE))); + if (lambdaForm.forceInline) { + mb.with(LF_FORCEINLINE_PROFILE_ANNOTATIONS); + } else { + mb.with(LF_DONTINLINE_PROFILE_ANNOTATIONS); + } } onStack = emitSelectAlternative(cob, name, lambdaForm.names[i+1]); i++; // skip MH.invokeBasic of the selectAlternative result From c33a8f52b613e5eff02f572eda876cbbfc7c22cf Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 5 Nov 2024 13:42:27 +0000 Subject: [PATCH 06/23] 8343314: Move common properties from jpackage jtreg test declarations to TEST.properties file Reviewed-by: almatvee --- test/jdk/tools/jpackage/TEST.properties | 3 +++ .../jpackage/test/DirectoryContentVerifierTest.java | 1 - test/jdk/tools/jpackage/linux/AppAboutUrlTest.java | 8 +++----- test/jdk/tools/jpackage/linux/AppCategoryTest.java | 5 ++--- test/jdk/tools/jpackage/linux/LicenseTypeTest.java | 5 ++--- test/jdk/tools/jpackage/linux/LinuxBundleNameTest.java | 5 ++--- test/jdk/tools/jpackage/linux/LinuxResourceTest.java | 5 ++--- .../tools/jpackage/linux/LinuxWeirdOutputDirTest.java | 5 ++--- test/jdk/tools/jpackage/linux/MaintainerTest.java | 5 ++--- test/jdk/tools/jpackage/linux/PackageDepsTest.java | 5 ++--- test/jdk/tools/jpackage/linux/ReleaseTest.java | 8 +++----- .../tools/jpackage/linux/ServiceAndDesktopTest.java | 5 ++--- test/jdk/tools/jpackage/linux/ShortcutHintTest.java | 8 +++----- test/jdk/tools/jpackage/linux/UpgradeTest.java | 5 ++--- .../jpackage/linux/jdk/jpackage/tests/UsrTreeTest.java | 5 ++--- .../tools/jpackage/macosx/ArgumentsFilteringTest.java | 3 +-- test/jdk/tools/jpackage/macosx/DmgContentTest.java | 10 ++-------- test/jdk/tools/jpackage/macosx/HostArchPkgTest.java | 5 ++--- .../jpackage/macosx/MacAppStoreJlinkOptionsTest.java | 6 ++---- .../tools/jpackage/macosx/MacAppStoreRuntimeTest.java | 6 ++---- .../tools/jpackage/macosx/MacFileAssociationsTest.java | 5 ++--- test/jdk/tools/jpackage/macosx/MacPropertiesTest.java | 5 ++--- test/jdk/tools/jpackage/macosx/NameWithSpaceTest.java | 5 ++--- .../jdk/tools/jpackage/macosx/SigningAppImageTest.java | 5 ++--- .../jpackage/macosx/SigningAppImageTwoStepsTest.java | 5 ++--- test/jdk/tools/jpackage/macosx/SigningOptionsTest.java | 6 ++---- .../macosx/SigningPackageFromTwoStepAppImageTest.java | 5 ++--- test/jdk/tools/jpackage/macosx/SigningPackageTest.java | 5 ++--- .../jpackage/macosx/SigningPackageTwoStepTest.java | 5 ++--- test/jdk/tools/jpackage/share/AddLShortcutTest.java | 6 ++---- test/jdk/tools/jpackage/share/AddLauncherTest.java | 10 +++------- test/jdk/tools/jpackage/share/AppContentTest.java | 5 +---- test/jdk/tools/jpackage/share/AppImagePackageTest.java | 5 ++--- test/jdk/tools/jpackage/share/AppLauncherEnvTest.java | 7 ++----- test/jdk/tools/jpackage/share/ArgumentsTest.java | 3 +-- test/jdk/tools/jpackage/share/EmptyFolderTest.java | 8 ++------ .../jdk/tools/jpackage/share/FileAssociationsTest.java | 8 +++----- test/jdk/tools/jpackage/share/IconTest.java | 6 ++---- test/jdk/tools/jpackage/share/InOutPathTest.java | 3 +-- test/jdk/tools/jpackage/share/InstallDirTest.java | 8 +++----- test/jdk/tools/jpackage/share/LicenseTest.java | 8 +++----- .../jpackage/share/MultiLauncherTwoPhaseTest.java | 7 ++----- .../tools/jpackage/share/MultiNameTwoPhaseTest.java | 6 ++---- test/jdk/tools/jpackage/share/PerUserCfgTest.java | 5 ++--- .../jpackage/share/RuntimeImageSymbolicLinksTest.java | 5 ++--- test/jdk/tools/jpackage/share/RuntimeImageTest.java | 3 +-- test/jdk/tools/jpackage/share/RuntimePackageTest.java | 6 ++---- test/jdk/tools/jpackage/share/ServiceTest.java | 8 ++++---- test/jdk/tools/jpackage/share/SimplePackageTest.java | 5 ++--- .../share/jdk/jpackage/tests/AppVersionTest.java | 5 ++--- .../jpackage/share/jdk/jpackage/tests/BasicTest.java | 3 +-- .../share/jdk/jpackage/tests/CookedRuntimeTest.java | 5 ++--- .../share/jdk/jpackage/tests/DotInNameTest.java | 5 ++--- .../jpackage/share/jdk/jpackage/tests/ErrorTest.java | 8 +++----- .../share/jdk/jpackage/tests/JLinkOptionsTest.java | 5 ++--- .../jdk/jpackage/tests/JavaOptionsEqualsTest.java | 8 +++----- .../share/jdk/jpackage/tests/JavaOptionsTest.java | 5 ++--- .../share/jdk/jpackage/tests/MainClassTest.java | 3 +-- .../share/jdk/jpackage/tests/ModulePathTest.java | 5 ++--- .../share/jdk/jpackage/tests/ModulePathTest2.java | 5 ++--- .../share/jdk/jpackage/tests/ModulePathTest3.java | 5 ++--- .../share/jdk/jpackage/tests/MultipleJarAppTest.java | 5 ++--- .../share/jdk/jpackage/tests/NoMPathRuntimeTest.java | 5 ++--- .../share/jdk/jpackage/tests/NonExistentTest.java | 5 ++--- .../jpackage/tests/PredefinedAppImageErrorTest.java | 5 ++--- .../share/jdk/jpackage/tests/UnicodeArgsTest.java | 5 ++--- .../jpackage/share/jdk/jpackage/tests/VendorTest.java | 8 +++----- test/jdk/tools/jpackage/windows/Win8282351Test.java | 5 ++--- test/jdk/tools/jpackage/windows/Win8301247Test.java | 3 +-- .../tools/jpackage/windows/WinChildProcessTest.java | 4 +--- test/jdk/tools/jpackage/windows/WinConsoleTest.java | 5 ++--- test/jdk/tools/jpackage/windows/WinDirChooserTest.java | 5 ++--- .../tools/jpackage/windows/WinInstallerIconTest.java | 5 ++--- .../jdk/tools/jpackage/windows/WinInstallerUiTest.java | 5 ++--- test/jdk/tools/jpackage/windows/WinL10nTest.java | 3 +-- .../jdk/tools/jpackage/windows/WinLongVersionTest.java | 8 +++----- test/jdk/tools/jpackage/windows/WinMenuGroupTest.java | 5 ++--- test/jdk/tools/jpackage/windows/WinMenuTest.java | 5 ++--- test/jdk/tools/jpackage/windows/WinNoRestartTest.java | 3 +-- .../tools/jpackage/windows/WinPerUserInstallTest.java | 5 ++--- test/jdk/tools/jpackage/windows/WinRenameTest.java | 3 +-- test/jdk/tools/jpackage/windows/WinResourceTest.java | 5 ++--- test/jdk/tools/jpackage/windows/WinScriptTest.java | 5 ++--- .../tools/jpackage/windows/WinShortcutPromptTest.java | 5 ++--- test/jdk/tools/jpackage/windows/WinShortcutTest.java | 5 ++--- .../jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java | 8 +++----- test/jdk/tools/jpackage/windows/WinUrlTest.java | 5 ++--- 87 files changed, 175 insertions(+), 293 deletions(-) diff --git a/test/jdk/tools/jpackage/TEST.properties b/test/jdk/tools/jpackage/TEST.properties index ab013166faa..e01036f0ed3 100644 --- a/test/jdk/tools/jpackage/TEST.properties +++ b/test/jdk/tools/jpackage/TEST.properties @@ -10,3 +10,6 @@ maxOutputSize=2000000 # } # but conditionals are not supported by jtreg configuration files. exclusiveAccess.dirs=share windows + +modules=jdk.jpackage/jdk.jpackage.internal:+open \ + java.base/jdk.internal.util diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java index cf910445abf..1d2b2e3f498 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java @@ -44,7 +44,6 @@ * @summary Test TKit.DirectoryContentVerifier from jpackage test library * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile DirectoryContentVerifierTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.test.DirectoryContentVerifierTest diff --git a/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java b/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java index e3812b0fcee..0d8f0ec4805 100644 --- a/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java +++ b/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,13 +44,12 @@ /* * @test * @summary jpackage with --about-url - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build AppAboutUrlTest * @requires (os.family == "linux") * @requires (jpackage.test.SQETest == null) - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppAboutUrlTest */ @@ -58,13 +57,12 @@ /* * @test * @summary jpackage with --about-url - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build AppAboutUrlTest * @requires (os.family == "linux") * @requires (jpackage.test.SQETest != null) - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppAboutUrlTest.test */ diff --git a/test/jdk/tools/jpackage/linux/AppCategoryTest.java b/test/jdk/tools/jpackage/linux/AppCategoryTest.java index d52b537604d..5fd34ab3bfd 100644 --- a/test/jdk/tools/jpackage/linux/AppCategoryTest.java +++ b/test/jdk/tools/jpackage/linux/AppCategoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -43,12 +43,11 @@ /* * @test * @summary jpackage with --linux-app-category - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build AppCategoryTest * @requires (os.family == "linux") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppCategoryTest */ diff --git a/test/jdk/tools/jpackage/linux/LicenseTypeTest.java b/test/jdk/tools/jpackage/linux/LicenseTypeTest.java index 5a8837a424e..f949284112d 100644 --- a/test/jdk/tools/jpackage/linux/LicenseTypeTest.java +++ b/test/jdk/tools/jpackage/linux/LicenseTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,12 +38,11 @@ /* * @test * @summary jpackage with --linux-rpm-license-type - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build LicenseTypeTest * @requires (os.family == "linux") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=LicenseTypeTest */ diff --git a/test/jdk/tools/jpackage/linux/LinuxBundleNameTest.java b/test/jdk/tools/jpackage/linux/LinuxBundleNameTest.java index 269f176b368..e39af0fb765 100644 --- a/test/jdk/tools/jpackage/linux/LinuxBundleNameTest.java +++ b/test/jdk/tools/jpackage/linux/LinuxBundleNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -43,12 +43,11 @@ /* * @test * @summary jpackage with --linux-package-name - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build LinuxBundleNameTest * @requires (os.family == "linux") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=LinuxBundleNameTest */ diff --git a/test/jdk/tools/jpackage/linux/LinuxResourceTest.java b/test/jdk/tools/jpackage/linux/LinuxResourceTest.java index f38e0763d28..5a460b39ed7 100644 --- a/test/jdk/tools/jpackage/linux/LinuxResourceTest.java +++ b/test/jdk/tools/jpackage/linux/LinuxResourceTest.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 @@ -33,10 +33,9 @@ /* * @test * @summary jpackage with --resource-dir - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @requires (os.family == "linux") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile LinuxResourceTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=LinuxResourceTest diff --git a/test/jdk/tools/jpackage/linux/LinuxWeirdOutputDirTest.java b/test/jdk/tools/jpackage/linux/LinuxWeirdOutputDirTest.java index 4ce3c1a4614..a30c1724611 100644 --- a/test/jdk/tools/jpackage/linux/LinuxWeirdOutputDirTest.java +++ b/test/jdk/tools/jpackage/linux/LinuxWeirdOutputDirTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,9 +30,8 @@ * @summary jpackage with values of --dest parameter breaking jpackage launcher * @requires (os.family == "linux") * @bug 8268974 - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile LinuxWeirdOutputDirTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=LinuxWeirdOutputDirTest diff --git a/test/jdk/tools/jpackage/linux/MaintainerTest.java b/test/jdk/tools/jpackage/linux/MaintainerTest.java index aac4317a26b..a257a5ff92d 100644 --- a/test/jdk/tools/jpackage/linux/MaintainerTest.java +++ b/test/jdk/tools/jpackage/linux/MaintainerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,12 +39,11 @@ /* * @test * @summary jpackage with --linux-deb-maintainer - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build MaintainerTest * @requires (os.family == "linux") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MaintainerTest */ diff --git a/test/jdk/tools/jpackage/linux/PackageDepsTest.java b/test/jdk/tools/jpackage/linux/PackageDepsTest.java index 457d8f01592..1a69582fc84 100644 --- a/test/jdk/tools/jpackage/linux/PackageDepsTest.java +++ b/test/jdk/tools/jpackage/linux/PackageDepsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -46,11 +46,10 @@ /* * @test * @summary jpackage with --linux-package-deps - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @requires (os.family == "linux") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile PackageDepsTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=PackageDepsTest diff --git a/test/jdk/tools/jpackage/linux/ReleaseTest.java b/test/jdk/tools/jpackage/linux/ReleaseTest.java index 1396e76e583..7516b660f4a 100644 --- a/test/jdk/tools/jpackage/linux/ReleaseTest.java +++ b/test/jdk/tools/jpackage/linux/ReleaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -43,13 +43,12 @@ /* * @test * @summary jpackage with --linux-app-release - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build ReleaseTest * @requires (os.family == "linux") * @requires (jpackage.test.SQETest == null) - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=ReleaseTest */ @@ -57,13 +56,12 @@ /* * @test * @summary jpackage with --linux-app-release - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build ReleaseTest * @requires (os.family == "linux") * @requires (jpackage.test.SQETest != null) - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=ReleaseTest.test */ diff --git a/test/jdk/tools/jpackage/linux/ServiceAndDesktopTest.java b/test/jdk/tools/jpackage/linux/ServiceAndDesktopTest.java index b047ce3e8f4..581190ad341 100644 --- a/test/jdk/tools/jpackage/linux/ServiceAndDesktopTest.java +++ b/test/jdk/tools/jpackage/linux/ServiceAndDesktopTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,12 +39,11 @@ /* * @test * @summary jpackage with desktop integration and services on Linux - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires jpackage.test.SQETest == null * @build jdk.jpackage.test.* * @requires (os.family == "linux") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ServiceAndDesktopTest.java * @run main/othervm/timeout=720 jdk.jpackage.test.Main * --jpt-run=ServiceAndDesktopTest diff --git a/test/jdk/tools/jpackage/linux/ShortcutHintTest.java b/test/jdk/tools/jpackage/linux/ShortcutHintTest.java index 812a1941333..01e89075138 100644 --- a/test/jdk/tools/jpackage/linux/ShortcutHintTest.java +++ b/test/jdk/tools/jpackage/linux/ShortcutHintTest.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 @@ -53,12 +53,11 @@ /* * @test * @summary jpackage with --linux-shortcut - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires jpackage.test.SQETest == null * @build jdk.jpackage.test.* * @requires (os.family == "linux") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ShortcutHintTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=ShortcutHintTest @@ -67,12 +66,11 @@ /* * @test * @summary jpackage with --linux-shortcut - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @requires (os.family == "linux") * @requires jpackage.test.SQETest != null - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ShortcutHintTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=ShortcutHintTest.testBasic diff --git a/test/jdk/tools/jpackage/linux/UpgradeTest.java b/test/jdk/tools/jpackage/linux/UpgradeTest.java index 1a4234db86f..4bf13476eb5 100644 --- a/test/jdk/tools/jpackage/linux/UpgradeTest.java +++ b/test/jdk/tools/jpackage/linux/UpgradeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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,11 +32,10 @@ /* * @test * @summary Linux upgrade testing - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @requires (os.family == "linux") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile UpgradeTest.java * @run main/othervm/timeout=360 jdk.jpackage.test.Main * --jpt-run=UpgradeTest diff --git a/test/jdk/tools/jpackage/linux/jdk/jpackage/tests/UsrTreeTest.java b/test/jdk/tools/jpackage/linux/jdk/jpackage/tests/UsrTreeTest.java index 13237cc5aa3..819ea8f245a 100644 --- a/test/jdk/tools/jpackage/linux/jdk/jpackage/tests/UsrTreeTest.java +++ b/test/jdk/tools/jpackage/linux/jdk/jpackage/tests/UsrTreeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,12 +40,11 @@ /* * @test * @summary jpackage command run installing app in /usr directory tree - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires jpackage.test.SQETest == null * @requires (os.family == "linux") * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile UsrTreeTest.java * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=UsrTreeTest diff --git a/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java b/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java index 9eae8c8d556..9b57cd7fbe5 100644 --- a/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java +++ b/test/jdk/tools/jpackage/macosx/ArgumentsFilteringTest.java @@ -36,9 +36,8 @@ /* * @test * @summary jpackage with -psn - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ArgumentsFilteringTest.java * @requires (os.family == "mac") * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main diff --git a/test/jdk/tools/jpackage/macosx/DmgContentTest.java b/test/jdk/tools/jpackage/macosx/DmgContentTest.java index fcedc3c3bdc..fefbe229ec5 100644 --- a/test/jdk/tools/jpackage/macosx/DmgContentTest.java +++ b/test/jdk/tools/jpackage/macosx/DmgContentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -25,28 +25,22 @@ import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.MacHelper; import jdk.jpackage.test.TKit; -import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import java.util.Collection; -import java.util.Arrays; import java.util.ArrayList; import java.util.List; /* * @test * @summary jpackage with --type dmg --mac-dmg-content - * @library ../helpers - * @library /test/lib - * @library base + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build DmgContentTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=DmgContentTest diff --git a/test/jdk/tools/jpackage/macosx/HostArchPkgTest.java b/test/jdk/tools/jpackage/macosx/HostArchPkgTest.java index 7d510c0a819..5829aba23cc 100644 --- a/test/jdk/tools/jpackage/macosx/HostArchPkgTest.java +++ b/test/jdk/tools/jpackage/macosx/HostArchPkgTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,9 +42,8 @@ /* * @test * @summary jpackage test to validate "hostArchitectures" attribute - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile HostArchPkgTest.java * @requires (os.family == "mac") * @key jpackagePlatformPackage diff --git a/test/jdk/tools/jpackage/macosx/MacAppStoreJlinkOptionsTest.java b/test/jdk/tools/jpackage/macosx/MacAppStoreJlinkOptionsTest.java index 8b1cec04ab9..1501fd15d8f 100644 --- a/test/jdk/tools/jpackage/macosx/MacAppStoreJlinkOptionsTest.java +++ b/test/jdk/tools/jpackage/macosx/MacAppStoreJlinkOptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,11 +33,9 @@ /* * @test * @summary jpackage with --mac-app-store and --jlink-options - * @library ../helpers - * @library /test/lib + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @build MacAppStoreJLinkOptionsTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MacAppStoreJLinkOptionsTest diff --git a/test/jdk/tools/jpackage/macosx/MacAppStoreRuntimeTest.java b/test/jdk/tools/jpackage/macosx/MacAppStoreRuntimeTest.java index ea2cee77b4e..ab8b8590b33 100644 --- a/test/jdk/tools/jpackage/macosx/MacAppStoreRuntimeTest.java +++ b/test/jdk/tools/jpackage/macosx/MacAppStoreRuntimeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,11 +43,9 @@ /* * @test * @summary jpackage with --mac-app-store and --runtime-image - * @library ../helpers - * @library /test/lib + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @build MacAppStoreRuntimeTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm -Xmx512m jdk.jpackage.test.Main * --jpt-run=MacAppStoreRuntimeTest diff --git a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java index 0bf972cf51b..01c9e48b5fd 100644 --- a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java +++ b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,10 +40,9 @@ /* * @test * @summary jpackage with --file-associations and mac specific file association args - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @build MacFileAssociationsTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm -Xmx512m jdk.jpackage.test.Main * --jpt-run=MacFileAssociationsTest diff --git a/test/jdk/tools/jpackage/macosx/MacPropertiesTest.java b/test/jdk/tools/jpackage/macosx/MacPropertiesTest.java index 9d4324e2222..5482a3ea508 100644 --- a/test/jdk/tools/jpackage/macosx/MacPropertiesTest.java +++ b/test/jdk/tools/jpackage/macosx/MacPropertiesTest.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 @@ -35,10 +35,9 @@ /* * @test * @summary jpackage with --mac-package-name, --mac-package-identifier - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @requires (os.family == "mac") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile MacPropertiesTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MacPropertiesTest diff --git a/test/jdk/tools/jpackage/macosx/NameWithSpaceTest.java b/test/jdk/tools/jpackage/macosx/NameWithSpaceTest.java index ac505e5ca81..ea95ad964f3 100644 --- a/test/jdk/tools/jpackage/macosx/NameWithSpaceTest.java +++ b/test/jdk/tools/jpackage/macosx/NameWithSpaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,9 +38,8 @@ /* * @test * @summary jpackage test with name containing spaces - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile NameWithSpaceTest.java * @requires (os.family == "mac") * @key jpackagePlatformPackage diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java index 65793baa096..959f6d710b6 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.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 @@ -45,7 +45,7 @@ /* * @test * @summary jpackage with --type app-image --mac-sign - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @library /test/lib * @library base * @build SigningBase @@ -53,7 +53,6 @@ * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningAppImageTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTest diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java index cf479d9ba94..b8763d82e36 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ /* * @test * @summary jpackage with --type app-image --app-image "appImage" --mac-sign - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @library /test/lib * @library base * @build SigningBase @@ -54,7 +54,6 @@ * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningAppImageTwoStepsTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTwoStepsTest diff --git a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java index 9d6cd6472ba..c5df2c1b31b 100644 --- a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java @@ -31,14 +31,13 @@ /* * @test * @summary Test jpackage signing options errors - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @library /test/lib * @library base * @build SigningBase * @build SigningCheck * @build jtreg.SkippedException * @build SigningOptionsTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningOptionsTest @@ -48,14 +47,13 @@ /* * @test * @summary Test jpackage signing options errors - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @library /test/lib * @library base * @build SigningBase * @build SigningCheck * @build jtreg.SkippedException * @build SigningOptionsTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningOptionsTest diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java index 48f5dca8986..0f4f2e77476 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ /* * @test * @summary jpackage with --type pkg,dmg --app-image - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @library /test/lib * @library base * @key jpackagePlatformPackage @@ -59,7 +59,6 @@ * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningPackageFromTwoStepAppImageTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageFromTwoStepAppImageTest diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index c555b0386cd..621fac1cd19 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.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 @@ -48,7 +48,7 @@ /* * @test * @summary jpackage with --type pkg,dmg --mac-sign - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @library /test/lib * @library base * @key jpackagePlatformPackage @@ -57,7 +57,6 @@ * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningPackageTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageTest diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java index a34f7921b91..65211e8c29e 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ /* * @test * @summary jpackage with --type pkg,dmg --app-image - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @library /test/lib * @library base * @key jpackagePlatformPackage @@ -60,7 +60,6 @@ * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningPackageTwoStepTest - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageTwoStepTest diff --git a/test/jdk/tools/jpackage/share/AddLShortcutTest.java b/test/jdk/tools/jpackage/share/AddLShortcutTest.java index 8883cfa82f3..92784abd5cc 100644 --- a/test/jdk/tools/jpackage/share/AddLShortcutTest.java +++ b/test/jdk/tools/jpackage/share/AddLShortcutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,12 +44,10 @@ * @test * @summary jpackage with --add-launcher * @key jpackagePlatformPackage - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile AddLShortcutTest.java * @run main/othervm/timeout=540 -Xmx512m - * --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED * jdk.jpackage.test.Main * --jpt-run=AddLShortcutTest */ diff --git a/test/jdk/tools/jpackage/share/AddLauncherTest.java b/test/jdk/tools/jpackage/share/AddLauncherTest.java index 4a24183647d..ae774b86f3a 100644 --- a/test/jdk/tools/jpackage/share/AddLauncherTest.java +++ b/test/jdk/tools/jpackage/share/AddLauncherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,12 +48,10 @@ * @summary jpackage with --add-launcher * @key jpackagePlatformPackage * @requires (jpackage.test.SQETest != null) - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile AddLauncherTest.java * @run main/othervm/timeout=360 -Xmx512m - * --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED * jdk.jpackage.test.Main * --jpt-run=AddLauncherTest.test */ @@ -63,12 +61,10 @@ * @summary jpackage with --add-launcher * @key jpackagePlatformPackage * @requires (jpackage.test.SQETest == null) - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile AddLauncherTest.java * @run main/othervm/timeout=540 -Xmx512m - * --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED * jdk.jpackage.test.Main * --jpt-run=AddLauncherTest */ diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index 94362530751..e056070a5fc 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -45,13 +45,10 @@ /* * @test * @summary jpackage with --app-content option - * @library ../helpers - * @library /test/lib + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build AppContentTest - * @modules jdk.jpackage/jdk.jpackage.internal - * @modules java.base/jdk.internal.util * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppContentTest */ diff --git a/test/jdk/tools/jpackage/share/AppImagePackageTest.java b/test/jdk/tools/jpackage/share/AppImagePackageTest.java index 949e68faae2..62d5e974f86 100644 --- a/test/jdk/tools/jpackage/share/AppImagePackageTest.java +++ b/test/jdk/tools/jpackage/share/AppImagePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,10 +43,9 @@ * @test * @summary jpackage with --app-image * @key jpackagePlatformPackage - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @requires (jpackage.test.SQETest == null) * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile AppImagePackageTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppImagePackageTest diff --git a/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java b/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java index cc52b285fbe..a16ff9c18f9 100644 --- a/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java +++ b/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,12 +39,9 @@ /* * @test * @summary Tests values of environment variables altered by jpackage launcher - * @library ../helpers - * @library /test/lib - * @build AppLauncherEnvTest + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @build AppLauncherEnvTest - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppLauncherEnvTest */ diff --git a/test/jdk/tools/jpackage/share/ArgumentsTest.java b/test/jdk/tools/jpackage/share/ArgumentsTest.java index f630d7f7168..3be6c36a25c 100644 --- a/test/jdk/tools/jpackage/share/ArgumentsTest.java +++ b/test/jdk/tools/jpackage/share/ArgumentsTest.java @@ -46,9 +46,8 @@ /* * @test * @summary jpackage create image with --arguments test - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ArgumentsTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=ArgumentsTest diff --git a/test/jdk/tools/jpackage/share/EmptyFolderTest.java b/test/jdk/tools/jpackage/share/EmptyFolderTest.java index 230d8a039ea..40a4db03d6f 100644 --- a/test/jdk/tools/jpackage/share/EmptyFolderTest.java +++ b/test/jdk/tools/jpackage/share/EmptyFolderTest.java @@ -37,12 +37,10 @@ /* * @test * @summary jpackage for package with input containing empty folders - * @library ../helpers - * @library /test/lib + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build EmptyFolderTest - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=EmptyFolderTest.testPackage */ @@ -50,11 +48,9 @@ /* * @test * @summary jpackage for app image with input containing empty folders - * @library ../helpers - * @library /test/lib + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @build EmptyFolderTest - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm -Xmx512m jdk.jpackage.test.Main * --jpt-run=EmptyFolderTest.testAppImage */ diff --git a/test/jdk/tools/jpackage/share/FileAssociationsTest.java b/test/jdk/tools/jpackage/share/FileAssociationsTest.java index 326258df600..a06ea82bcba 100644 --- a/test/jdk/tools/jpackage/share/FileAssociationsTest.java +++ b/test/jdk/tools/jpackage/share/FileAssociationsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -57,11 +57,10 @@ /* * @test * @summary jpackage with --file-associations - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires jpackage.test.SQETest == null * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile FileAssociationsTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=FileAssociationsTest @@ -70,11 +69,10 @@ /* * @test * @summary jpackage with --file-associations - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires jpackage.test.SQETest != null * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile FileAssociationsTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=FileAssociationsTest.test diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index 254823d1227..2d6469f5f2e 100644 --- a/test/jdk/tools/jpackage/share/IconTest.java +++ b/test/jdk/tools/jpackage/share/IconTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -49,12 +49,10 @@ /* * @test * @summary jpackage create image and package with custom icons for the main and additional launcher - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile IconTest.java * @run main/othervm/timeout=540 -Xmx512m - * --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED * jdk.jpackage.test.Main * --jpt-run=IconTest */ diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index 699d88e3189..8ea70a06034 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -47,9 +47,8 @@ /* * @test * @summary Test jpackage command line with overlapping input and output paths - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile InOutPathTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=InOutPathTest diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index 1f969149c68..7047f35e87b 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -54,11 +54,10 @@ /* * @test * @summary jpackage with --install-dir - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @compile InstallDirTest.java - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=InstallDirTest.testCommon */ @@ -66,11 +65,10 @@ /* * @test * @summary jpackage with --install-dir - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @compile InstallDirTest.java - * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "linux") * @requires (jpackage.test.SQETest == null) * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main diff --git a/test/jdk/tools/jpackage/share/LicenseTest.java b/test/jdk/tools/jpackage/share/LicenseTest.java index 4211386f243..b0eef94fa7c 100644 --- a/test/jdk/tools/jpackage/share/LicenseTest.java +++ b/test/jdk/tools/jpackage/share/LicenseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -63,11 +63,10 @@ /* * @test * @summary jpackage with --license-file - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @compile LicenseTest.java - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=LicenseTest.testCommon */ @@ -75,13 +74,12 @@ /* * @test * @summary jpackage with --license-file - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @compile LicenseTest.java * @requires (os.family == "linux") * @requires (jpackage.test.SQETest == null) - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=LicenseTest.testCustomDebianCopyright * --jpt-run=LicenseTest.testCustomDebianCopyrightSubst diff --git a/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java b/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java index 030abe99fdf..34962b77ca0 100644 --- a/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java +++ b/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,14 +43,11 @@ /* * @test * @summary Multiple launchers in two phases - * @library ../helpers - * @library /test/lib + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile MultiLauncherTwoPhaseTest.java * @run main/othervm/timeout=360 -Xmx512m - * --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED * jdk.jpackage.test.Main * --jpt-run=MultiLauncherTwoPhaseTest */ diff --git a/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java b/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java index 7b3f484d62d..870804661a7 100644 --- a/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java +++ b/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,12 +41,10 @@ /* * @test * @summary Multiple names in two phases - * @library ../helpers - * @library /test/lib + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires (jpackage.test.SQETest == null) * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile MultiNameTwoPhaseTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MultiNameTwoPhaseTest diff --git a/test/jdk/tools/jpackage/share/PerUserCfgTest.java b/test/jdk/tools/jpackage/share/PerUserCfgTest.java index 9d249a1458a..0fff7eb3a2d 100644 --- a/test/jdk/tools/jpackage/share/PerUserCfgTest.java +++ b/test/jdk/tools/jpackage/share/PerUserCfgTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,12 +43,11 @@ /* * @test * @summary pre-user configuration of app launchers - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires jpackage.test.SQETest == null * @build jdk.jpackage.test.* * @compile PerUserCfgTest.java - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=PerUserCfgTest */ diff --git a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java index 1726fe3eac6..0e48df630af 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,11 +47,10 @@ /* * @test * @summary jpackage with --runtime-image - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires (os.family != "windows") * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile RuntimeImageSymbolicLinksTest.java * @run main/othervm/timeout=1400 -Xmx512m jdk.jpackage.test.Main * --jpt-run=RuntimeImageSymbolicLinksTest diff --git a/test/jdk/tools/jpackage/share/RuntimeImageTest.java b/test/jdk/tools/jpackage/share/RuntimeImageTest.java index 64908b6ac99..f3751c9ee47 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageTest.java @@ -32,10 +32,9 @@ /* * @test * @summary jpackage with --runtime-image - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile RuntimeImageTest.java * @run main/othervm/timeout=1400 jdk.jpackage.test.Main * --jpt-run=RuntimeImageTest diff --git a/test/jdk/tools/jpackage/share/RuntimePackageTest.java b/test/jdk/tools/jpackage/share/RuntimePackageTest.java index da58ed3a73c..0b505babcc5 100644 --- a/test/jdk/tools/jpackage/share/RuntimePackageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimePackageTest.java @@ -55,11 +55,10 @@ /* * @test * @summary jpackage with --runtime-image - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @requires (jpackage.test.SQETest == null) - * @modules jdk.jpackage/jdk.jpackage.internal * @compile RuntimePackageTest.java * @run main/othervm/timeout=1400 -Xmx512m jdk.jpackage.test.Main * --jpt-run=RuntimePackageTest @@ -68,11 +67,10 @@ /* * @test * @summary jpackage with --runtime-image - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @requires (jpackage.test.SQETest != null) - * @modules jdk.jpackage/jdk.jpackage.internal * @compile RuntimePackageTest.java * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=RuntimePackageTest.test diff --git a/test/jdk/tools/jpackage/share/ServiceTest.java b/test/jdk/tools/jpackage/share/ServiceTest.java index 4cf96b62cd2..f1ff65d18b1 100644 --- a/test/jdk/tools/jpackage/share/ServiceTest.java +++ b/test/jdk/tools/jpackage/share/ServiceTest.java @@ -44,13 +44,13 @@ /* * @test * @summary Launcher as service packaging test - * @library ../helpers - * @key jpackagePlatformPackage + * @library /test/jdk/tools/jpackage/helpers + * @library /test/lib * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal + * @build jtreg.SkippedException + * @key jpackagePlatformPackage * @compile ServiceTest.java * @run main/othervm/timeout=360 -Xmx512m - * --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED * jdk.jpackage.test.Main * --jpt-run=ServiceTest */ diff --git a/test/jdk/tools/jpackage/share/SimplePackageTest.java b/test/jdk/tools/jpackage/share/SimplePackageTest.java index d2e8da31c03..e3945b668e0 100644 --- a/test/jdk/tools/jpackage/share/SimplePackageTest.java +++ b/test/jdk/tools/jpackage/share/SimplePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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,10 +40,9 @@ /* * @test * @summary Simple jpackage command run - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile SimplePackageTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SimplePackageTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/AppVersionTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/AppVersionTest.java index f137fabf3d6..d4f28ec17be 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/AppVersionTest.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 @@ -42,9 +42,8 @@ /* * @test * @summary jpackage application version testing - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile AppVersionTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.AppVersionTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java index 8d62dc291b4..1222fa95949 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java @@ -50,9 +50,8 @@ /* * @test * @summary jpackage basic testing - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile BasicTest.java * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.BasicTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/CookedRuntimeTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/CookedRuntimeTest.java index f61fff69fe6..cfb6ec13ccf 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/CookedRuntimeTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/CookedRuntimeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,9 +42,8 @@ /* * @test * @summary test '--runtime-image' option of jpackage - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile CookedRuntimeTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.CookedRuntimeTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/DotInNameTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/DotInNameTest.java index 87c9381bd2d..73be2c2e47a 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/DotInNameTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/DotInNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,8 @@ /* * @test * @summary jpackage create image with --java-options test - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile DotInNameTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.DotInNameTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ErrorTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ErrorTest.java index 8fcd3c8a730..57603809607 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ErrorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,8 @@ /* * @test * @summary Test jpackage output for erroneous input - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ErrorTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.ErrorTest @@ -45,9 +44,8 @@ /* * @test * @summary Test jpackage output for erroneous input - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ErrorTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.ErrorTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JLinkOptionsTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JLinkOptionsTest.java index 40e143763fd..dce60890aba 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JLinkOptionsTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JLinkOptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,8 @@ /* * @test * @summary jpackage application version testing - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile JLinkOptionsTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.JLinkOptionsTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JavaOptionsEqualsTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JavaOptionsEqualsTest.java index c63892a2ca0..e1c809dadd3 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JavaOptionsEqualsTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JavaOptionsEqualsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,9 +35,8 @@ /* * @test * @summary jpackage create image with --java-options test - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile JavaOptionsEqualsTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.JavaOptionsEqualsTest @@ -47,9 +46,8 @@ /* * @test * @summary jpackage create image with --java-options test - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile JavaOptionsEqualsTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.JavaOptionsEqualsTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JavaOptionsTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JavaOptionsTest.java index ab2f7a3d15d..cee455271aa 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JavaOptionsTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/JavaOptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,9 +35,8 @@ /* * @test * @summary jpackage create image with --java-options test - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile JavaOptionsTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.JavaOptionsTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/MainClassTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/MainClassTest.java index 3b8eea86639..641d0fd00bb 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/MainClassTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/MainClassTest.java @@ -52,9 +52,8 @@ /* * @test * @summary test different settings of main class name for jpackage - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile MainClassTest.java * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.MainClassTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest.java index 1c5ead2ad65..c42a24ec310 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest.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 @@ -44,9 +44,8 @@ /* * @test * @summary jpackage with --module-path testing - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ModulePathTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.ModulePathTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest2.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest2.java index 7bfe998014c..7b1ec2f5b63 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest2.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest2.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 @@ -36,9 +36,8 @@ /* * @test * @summary jpackage with --module-path testing - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ModulePathTest2.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.ModulePathTest2 diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest3.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest3.java index 662b2633207..d6fca043920 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest3.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,9 +49,8 @@ /* * @test * @summary jpackage for app's module linked in external runtime - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile ModulePathTest3.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.ModulePathTest3 diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/MultipleJarAppTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/MultipleJarAppTest.java index 3ce9f62d8d2..38878929006 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/MultipleJarAppTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/MultipleJarAppTest.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 @@ -33,9 +33,8 @@ /* * @test * @summary jpackage application packed in multiple jars - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile MultipleJarAppTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.MultipleJarAppTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/NoMPathRuntimeTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/NoMPathRuntimeTest.java index fea6324e46b..4a9aef7860d 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/NoMPathRuntimeTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/NoMPathRuntimeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,9 +43,8 @@ /* * @test * @summary test '--runtime-image' option of jpackage - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile NoMPathRuntimeTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.NoMPathRuntimeTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/NonExistentTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/NonExistentTest.java index 3790c9002ca..8ca18af356c 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/NonExistentTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/NonExistentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,8 @@ /* * @test * @summary jpackage application version testing - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile NonExistentTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.NonExistentTest diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java index d03c7cf28df..b01a78120db 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,9 +37,8 @@ /* * @test * @summary Test jpackage output for erroneous input with --type "app-image" and --app-image - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile PredefinedAppImageErrorTest.java * * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/UnicodeArgsTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/UnicodeArgsTest.java index 7b945f08731..29722086eec 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/UnicodeArgsTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/UnicodeArgsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,8 @@ /* * @test * @summary test how app launcher handles unicode command line arguments - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile UnicodeArgsTest.java * @requires (os.family == "windows") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/VendorTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/VendorTest.java index eb469ea130a..b6e8f44dbf8 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/VendorTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/VendorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,12 +54,11 @@ /* * @test * @summary Test --vendor jpackage command option - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires (os.family == "windows") * @requires jpackage.test.SQETest != null * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile VendorTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.VendorTest @@ -68,12 +67,11 @@ /* * @test * @summary Test --vendor jpackage command option - * @library ../../../../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires (os.family != "mac") * @requires jpackage.test.SQETest == null * @build jdk.jpackage.test.* - * @modules jdk.jpackage/jdk.jpackage.internal * @compile VendorTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=jdk.jpackage.tests.VendorTest diff --git a/test/jdk/tools/jpackage/windows/Win8282351Test.java b/test/jdk/tools/jpackage/windows/Win8282351Test.java index 3b38b9e7f96..17ea5e7d9ab 100644 --- a/test/jdk/tools/jpackage/windows/Win8282351Test.java +++ b/test/jdk/tools/jpackage/windows/Win8282351Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,11 +39,10 @@ /* * @test * @summary Test case for JDK-8248254 - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @build Win8282351Test * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=Win8282351Test */ diff --git a/test/jdk/tools/jpackage/windows/Win8301247Test.java b/test/jdk/tools/jpackage/windows/Win8301247Test.java index f61bb2b6e53..b0c11147a17 100644 --- a/test/jdk/tools/jpackage/windows/Win8301247Test.java +++ b/test/jdk/tools/jpackage/windows/Win8301247Test.java @@ -38,11 +38,10 @@ /* * @test * @summary Test case for JDK-8301247 - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @build Win8301247Test * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=Win8301247Test */ diff --git a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java index a61191d8a4e..5565d3dc503 100644 --- a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java +++ b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java @@ -25,12 +25,10 @@ * @bug 8325203 * @summary Test that Jpackage windows executable application kills the launched 3rd party application * when System.exit(0) is invoked along with terminating java program. - * @library ../helpers - * @library /test/lib + * @library /test/jdk/tools/jpackage/helpers * @requires os.family == "windows" * @build jdk.jpackage.test.* * @build WinChildProcessTest - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinChildProcessTest * diff --git a/test/jdk/tools/jpackage/windows/WinConsoleTest.java b/test/jdk/tools/jpackage/windows/WinConsoleTest.java index 7a4e9ccfa5a..6a1e94a8e83 100644 --- a/test/jdk/tools/jpackage/windows/WinConsoleTest.java +++ b/test/jdk/tools/jpackage/windows/WinConsoleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,10 +34,9 @@ /* * @test * @summary jpackage with --win-console - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinConsoleTest.java * * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main diff --git a/test/jdk/tools/jpackage/windows/WinDirChooserTest.java b/test/jdk/tools/jpackage/windows/WinDirChooserTest.java index 355b89dba3e..a4db21dc618 100644 --- a/test/jdk/tools/jpackage/windows/WinDirChooserTest.java +++ b/test/jdk/tools/jpackage/windows/WinDirChooserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,12 +36,11 @@ /* * @test * @summary jpackage with --win-dir-chooser - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build WinDirChooserTest * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinDirChooserTest */ diff --git a/test/jdk/tools/jpackage/windows/WinInstallerIconTest.java b/test/jdk/tools/jpackage/windows/WinInstallerIconTest.java index 63194d6b256..f104abc9f5e 100644 --- a/test/jdk/tools/jpackage/windows/WinInstallerIconTest.java +++ b/test/jdk/tools/jpackage/windows/WinInstallerIconTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,12 +38,11 @@ /* * @test * @summary jpackage with --icon parameter for exe installer - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build WinInstallerIconTest * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinInstallerIconTest */ diff --git a/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java b/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java index 99c6eb490d5..c6489ab68cf 100644 --- a/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java +++ b/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,12 +39,11 @@ /* * @test * @summary jpackage with --win-dir-chooser, --win-shortcut-prompt and --license parameters - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build WinInstallerUiTest * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinInstallerUiTest */ diff --git a/test/jdk/tools/jpackage/windows/WinL10nTest.java b/test/jdk/tools/jpackage/windows/WinL10nTest.java index a868fd5f051..d951b6f8832 100644 --- a/test/jdk/tools/jpackage/windows/WinL10nTest.java +++ b/test/jdk/tools/jpackage/windows/WinL10nTest.java @@ -42,12 +42,11 @@ /* * @test * @summary Custom l10n of msi installers in jpackage - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires (jpackage.test.SQETest == null) * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinL10nTest.java * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinL10nTest diff --git a/test/jdk/tools/jpackage/windows/WinLongVersionTest.java b/test/jdk/tools/jpackage/windows/WinLongVersionTest.java index 5181a89e6b6..0d52da65630 100644 --- a/test/jdk/tools/jpackage/windows/WinLongVersionTest.java +++ b/test/jdk/tools/jpackage/windows/WinLongVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,12 +70,11 @@ /* * @test * @summary jpackage with long version number - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires (jpackage.test.SQETest != null) * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinLongVersionTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinLongVersionTest.test @@ -84,12 +83,11 @@ /* * @test * @summary jpackage with long version number - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires (jpackage.test.SQETest == null) * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinLongVersionTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinLongVersionTest diff --git a/test/jdk/tools/jpackage/windows/WinMenuGroupTest.java b/test/jdk/tools/jpackage/windows/WinMenuGroupTest.java index 5950418f609..bdf5cf2f0a5 100644 --- a/test/jdk/tools/jpackage/windows/WinMenuGroupTest.java +++ b/test/jdk/tools/jpackage/windows/WinMenuGroupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,11 +39,10 @@ /* * @test * @summary jpackage with --win-menu and --win-menu-group - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinMenuGroupTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinMenuGroupTest diff --git a/test/jdk/tools/jpackage/windows/WinMenuTest.java b/test/jdk/tools/jpackage/windows/WinMenuTest.java index a28d28e24ec..8bacaa05470 100644 --- a/test/jdk/tools/jpackage/windows/WinMenuTest.java +++ b/test/jdk/tools/jpackage/windows/WinMenuTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,11 +36,10 @@ /* * @test * @summary jpackage with --win-menu - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinMenuTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinMenuTest diff --git a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java index 02b24591e92..c76f68476db 100644 --- a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java +++ b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java @@ -36,12 +36,11 @@ * @bug 8340311 * @summary Test that jpackage windows app launcher doesn't create child process * if `win.norestart` property is set in the corresponding .cfg file - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @library /test/lib * @requires os.family == "windows" * @build jdk.jpackage.test.* * @build WinNoRestartTest - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinNoRestartTest */ diff --git a/test/jdk/tools/jpackage/windows/WinPerUserInstallTest.java b/test/jdk/tools/jpackage/windows/WinPerUserInstallTest.java index 5d97bb9357e..48fca9644ea 100644 --- a/test/jdk/tools/jpackage/windows/WinPerUserInstallTest.java +++ b/test/jdk/tools/jpackage/windows/WinPerUserInstallTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,11 +37,10 @@ /* * @test * @summary jpackage with --win-per-user-install, --win-menu, --win-menu-group - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinPerUserInstallTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinPerUserInstallTest diff --git a/test/jdk/tools/jpackage/windows/WinRenameTest.java b/test/jdk/tools/jpackage/windows/WinRenameTest.java index 4b0f8cdfe18..59107c43921 100644 --- a/test/jdk/tools/jpackage/windows/WinRenameTest.java +++ b/test/jdk/tools/jpackage/windows/WinRenameTest.java @@ -32,12 +32,11 @@ /* * @test * @summary jpackage test app can run after changing executable's extension - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build WinRenameTest * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinRenameTest */ diff --git a/test/jdk/tools/jpackage/windows/WinResourceTest.java b/test/jdk/tools/jpackage/windows/WinResourceTest.java index 34111723457..72e805d0a48 100644 --- a/test/jdk/tools/jpackage/windows/WinResourceTest.java +++ b/test/jdk/tools/jpackage/windows/WinResourceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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,10 +40,9 @@ /* * @test * @summary jpackage with --resource-dir - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinResourceTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinResourceTest diff --git a/test/jdk/tools/jpackage/windows/WinScriptTest.java b/test/jdk/tools/jpackage/windows/WinScriptTest.java index 775102cd014..296da482bb0 100644 --- a/test/jdk/tools/jpackage/windows/WinScriptTest.java +++ b/test/jdk/tools/jpackage/windows/WinScriptTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,10 +37,9 @@ /* * @test usage of scripts from resource dir * @summary jpackage with - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinScriptTest.java * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinScriptTest diff --git a/test/jdk/tools/jpackage/windows/WinShortcutPromptTest.java b/test/jdk/tools/jpackage/windows/WinShortcutPromptTest.java index 6c27b6852eb..e202f7e5d2a 100644 --- a/test/jdk/tools/jpackage/windows/WinShortcutPromptTest.java +++ b/test/jdk/tools/jpackage/windows/WinShortcutPromptTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,12 +37,11 @@ /* * @test * @summary jpackage with --win-shortcut-prompt, --win-menu and --win-shortcut parameters - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build WinShortcutPromptTest * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinShortcutPromptTest */ diff --git a/test/jdk/tools/jpackage/windows/WinShortcutTest.java b/test/jdk/tools/jpackage/windows/WinShortcutTest.java index 3efa8b68817..1d2e7e762a5 100644 --- a/test/jdk/tools/jpackage/windows/WinShortcutTest.java +++ b/test/jdk/tools/jpackage/windows/WinShortcutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,11 +37,10 @@ /* * @test * @summary jpackage with --win-shortcut - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinShortcutTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinShortcutTest diff --git a/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java b/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java index 968ed94b345..c48803cfb5f 100644 --- a/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java +++ b/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, 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 @@ -46,12 +46,11 @@ /* * @test * @summary jpackage with --win-upgrade-uuid and --app-version - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires (jpackage.test.SQETest != null) * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinUpgradeUUIDTest.java * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinUpgradeUUIDTest.test @@ -60,12 +59,11 @@ /* * @test * @summary jpackage with --win-upgrade-uuid and --app-version - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @requires (jpackage.test.SQETest == null) * @build jdk.jpackage.test.* * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @compile WinUpgradeUUIDTest.java * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinUpgradeUUIDTest diff --git a/test/jdk/tools/jpackage/windows/WinUrlTest.java b/test/jdk/tools/jpackage/windows/WinUrlTest.java index 208d16d931a..f2e9528594b 100644 --- a/test/jdk/tools/jpackage/windows/WinUrlTest.java +++ b/test/jdk/tools/jpackage/windows/WinUrlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,12 +40,11 @@ * @test * @summary jpackage with --about-url, --win-update-url and --win-help-url * parameters - * @library ../helpers + * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build WinUrlTest * @requires (os.family == "windows") - * @modules jdk.jpackage/jdk.jpackage.internal * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinUrlTest */ From 5890d9438bbde88b89070052926a2eafe13d7b42 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Tue, 5 Nov 2024 15:05:33 +0000 Subject: [PATCH 07/23] 8333893: Optimization for StringBuilder append boolean & null Reviewed-by: liach --- .../java/lang/AbstractStringBuilder.java | 26 +++---- .../share/classes/java/lang/StringLatin1.java | 24 +++++++ .../share/classes/java/lang/StringUTF16.java | 36 ++++------ .../patches/java.base/java/lang/Helper.java | 12 +++- .../bench/java/lang/StringBuilders.java | 71 ++++++++++++++++--- 5 files changed, 115 insertions(+), 54 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index e0c3aa19f54..b40f6274412 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -640,14 +640,11 @@ private AbstractStringBuilder appendNull() { int count = this.count; byte[] val = this.value; if (isLatin1()) { - val[count++] = 'n'; - val[count++] = 'u'; - val[count++] = 'l'; - val[count++] = 'l'; + StringLatin1.putCharsAt(val, count, 'n', 'u', 'l', 'l'); } else { - count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l'); + StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l'); } - this.count = count; + this.count = count + 4; return this; } @@ -772,25 +769,18 @@ public AbstractStringBuilder append(boolean b) { byte[] val = this.value; if (isLatin1()) { if (b) { - val[count++] = 't'; - val[count++] = 'r'; - val[count++] = 'u'; - val[count++] = 'e'; + StringLatin1.putCharsAt(val, count, 't', 'r', 'u', 'e'); } else { - val[count++] = 'f'; - val[count++] = 'a'; - val[count++] = 'l'; - val[count++] = 's'; - val[count++] = 'e'; + StringLatin1.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e'); } } else { if (b) { - count = StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e'); + StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e'); } else { - count = StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e'); + StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e'); } } - this.count = count; + this.count = count + (b ? 4 : 5); return this; } diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index abec36af1d9..c12b8afc21f 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -32,6 +32,7 @@ import java.util.function.IntConsumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.misc.Unsafe; import jdk.internal.util.ArraysSupport; import jdk.internal.util.DecimalDigits; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -42,6 +43,8 @@ import static java.lang.String.checkOffset; final class StringLatin1 { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + public static char charAt(byte[] value, int index) { checkIndex(index, value.length); return (char)(value[index] & 0xff); @@ -824,6 +827,27 @@ static Stream lines(byte[] value) { return StreamSupport.stream(LinesSpliterator.spliterator(value), false); } + static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) { + assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check"; + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + index; + UNSAFE.putByte(val, address , (byte)(c1)); + UNSAFE.putByte(val, address + 1, (byte)(c2)); + UNSAFE.putByte(val, address + 2, (byte)(c3)); + UNSAFE.putByte(val, address + 3, (byte)(c4)); + } + + static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) { + assert index >= 0 && index + 4 < length(val) : "Trusted caller missed bounds check"; + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + index; + UNSAFE.putByte(val, address , (byte)(c1)); + UNSAFE.putByte(val, address + 1, (byte)(c2)); + UNSAFE.putByte(val, address + 2, (byte)(c3)); + UNSAFE.putByte(val, address + 3, (byte)(c4)); + UNSAFE.putByte(val, address + 4, (byte)(c5)); + } + public static void putChar(byte[] val, int index, int c) { //assert (canEncode(c)); val[index] = (byte)(c); diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 000483f29bc..f04b991827f 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -43,7 +43,6 @@ import static java.lang.String.LATIN1; final class StringUTF16 { - // Return a new byte array for a UTF16-coded string for len chars // Throw an exception if out of range public static byte[] newBytesFor(int len) { @@ -1548,27 +1547,20 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { return true; } - public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { - int end = i + 4; - checkBoundsBeginEnd(i, end, value); - putChar(value, i++, c1); - putChar(value, i++, c2); - putChar(value, i++, c3); - putChar(value, i++, c4); - assert(i == end); - return end; - } - - public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { - int end = i + 5; - checkBoundsBeginEnd(i, end, value); - putChar(value, i++, c1); - putChar(value, i++, c2); - putChar(value, i++, c3); - putChar(value, i++, c4); - putChar(value, i++, c5); - assert(i == end); - return end; + static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) { + assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check"; + putChar(val, index , c1); + putChar(val, index + 1, c2); + putChar(val, index + 2, c3); + putChar(val, index + 3, c4); + } + + static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) { + putChar(val, index , c1); + putChar(val, index + 1, c2); + putChar(val, index + 2, c3); + putChar(val, index + 3, c4); + putChar(val, index + 4, c5); } public static char charAt(byte[] value, int index) { diff --git a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java index a24d7b98ada..5ecc01aa2bc 100644 --- a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java +++ b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -133,11 +133,17 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { } public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { - return StringUTF16.putCharsAt(value, i, c1, c2, c3, c4); + int end = i + 4; + StringUTF16.checkBoundsBeginEnd(i, end, value); + StringUTF16.putCharsAt(value, i, c1, c2, c3, c4); + return end; } public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { - return StringUTF16.putCharsAt(value, i, c1, c2, c3, c4, c5); + int end = i + 5; + StringUTF16.checkBoundsBeginEnd(i, end, value); + StringUTF16.putCharsAt(value, i, c1, c2, c3, c4, c5); + return end; } public static char charAt(byte[] value, int index) { diff --git a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java index e7579d72ecb..ed5c0d30db8 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java +++ b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java @@ -226,17 +226,66 @@ public String toStringCharWithInt8() { @Benchmark - public String toStringCharWithBool8() { - StringBuilder result = new StringBuilder(); - result.append(true); - result.append(false); - result.append(true); - result.append(true); - result.append(false); - result.append(true); - result.append(false); - result.append(false); - return result.toString(); + public int appendWithBool8Latin1() { + StringBuilder buf = sbLatin1; + buf.setLength(0); + buf.append(true); + buf.append(false); + buf.append(true); + buf.append(true); + buf.append(false); + buf.append(true); + buf.append(false); + buf.append(false); + return buf.length(); + } + + + @Benchmark + public int appendWithBool8Utf16() { + StringBuilder buf = sbUtf16; + buf.setLength(0); + buf.append(true); + buf.append(false); + buf.append(true); + buf.append(true); + buf.append(false); + buf.append(true); + buf.append(false); + buf.append(false); + return buf.length(); + } + + + @Benchmark + public int appendWithNull8Latin1() { + StringBuilder buf = sbLatin1; + buf.setLength(0); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + return buf.length(); + } + + + @Benchmark + public int appendWithNull8Utf16() { + StringBuilder buf = sbUtf16; + buf.setLength(0); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + return buf.length(); } From 0b733e9a22fd786f3fd133faae3b00d31258e755 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Tue, 5 Nov 2024 15:25:18 +0000 Subject: [PATCH 08/23] 8336874: WhiteBoxAPI: assert(!method->is_abstract() && (osr_bci == InvocationEntryBci || !method->is_native())) failed: cannot compile abstract/native methods Reviewed-by: lmesnik, stuefe --- src/hotspot/share/prims/whitebox.cpp | 4 ++ .../whitebox/TestCompileAbstractMethod.java | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/whitebox/TestCompileAbstractMethod.java diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 54c5279512e..e19da95e075 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1080,6 +1080,10 @@ bool WhiteBox::compile_method(Method* method, int comp_level, int bci, JavaThrea tty->print_cr("WB error: request to compile null method"); return false; } + if (method->is_abstract()) { + tty->print_cr("WB error: request to compile abstract method"); + return false; + } if (comp_level > CompilationPolicy::highest_compile_level()) { tty->print_cr("WB error: invalid compilation level %d", comp_level); return false; diff --git a/test/hotspot/jtreg/compiler/whitebox/TestCompileAbstractMethod.java b/test/hotspot/jtreg/compiler/whitebox/TestCompileAbstractMethod.java new file mode 100644 index 00000000000..47478d6e0ad --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/TestCompileAbstractMethod.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Verify WhiteBox compile abstract method doesn't hit assert. + * @requires vm.compiler2.enabled + * @requires vm.compMode != "Xcomp" + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -ea -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestCompileAbstractMethod + * + */ + +import jdk.test.whitebox.WhiteBox; +import java.lang.reflect.Method; +import compiler.whitebox.CompilerWhiteBoxTest; + +public class TestCompileAbstractMethod { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + public static void main(String[] args) throws NoSuchMethodException { + Method m1 = A.class.getDeclaredMethod("run"); + assert m1 != null; + if (WHITE_BOX.enqueueMethodForCompilation(m1, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) { + throw new RuntimeException("Abstract method should not be enqueued"); + } + } + + abstract class A { + public abstract void run(); + } +} From c799cad1de93aadfe60d9cbccb0499d7299f0598 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Tue, 5 Nov 2024 15:44:54 +0000 Subject: [PATCH 09/23] 8343486: Remove unnecessary @SuppressWarnings annotations and -Xlint:-foo options Reviewed-by: ihse --- make/modules/java.sql.rowset/Java.gmk | 2 +- make/modules/jdk.httpserver/Java.gmk | 2 +- make/modules/jdk.jartool/Java.gmk | 3 +-- make/modules/jdk.jdi/Java.gmk | 2 +- make/modules/jdk.jlink/Java.gmk | 26 ------------------ make/modules/jdk.jstatd/Java.gmk | 26 ------------------ make/modules/jdk.unsupported/Java.gmk | 26 ------------------ make/modules/jdk.zipfs/Java.gmk | 27 ------------------- .../jdk/internal/icu/text/BidiBase.java | 3 +-- .../classes/jdk/dynalink/BiClassValue.java | 4 +-- .../beans/OverloadedDynamicMethod.java | 4 +-- .../share/classes/module-info.java | 1 - .../netscape/javascript/JSException.java | 1 - 13 files changed, 8 insertions(+), 119 deletions(-) delete mode 100644 make/modules/jdk.jlink/Java.gmk delete mode 100644 make/modules/jdk.jstatd/Java.gmk delete mode 100644 make/modules/jdk.unsupported/Java.gmk delete mode 100644 make/modules/jdk.zipfs/Java.gmk diff --git a/make/modules/java.sql.rowset/Java.gmk b/make/modules/java.sql.rowset/Java.gmk index 9f430a7121b..6bc30e3693d 100644 --- a/make/modules/java.sql.rowset/Java.gmk +++ b/make/modules/java.sql.rowset/Java.gmk @@ -23,7 +23,7 @@ # questions. # -DISABLED_WARNINGS_java += dangling-doc-comments this-escape +DISABLED_WARNINGS_java += dangling-doc-comments DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' diff --git a/make/modules/jdk.httpserver/Java.gmk b/make/modules/jdk.httpserver/Java.gmk index 799ff8695a7..95c0f1eb6ab 100644 --- a/make/modules/jdk.httpserver/Java.gmk +++ b/make/modules/jdk.httpserver/Java.gmk @@ -23,6 +23,6 @@ # questions. # -DISABLED_WARNINGS_java += missing-explicit-ctor this-escape +DISABLED_WARNINGS_java += this-escape COPY += .ico diff --git a/make/modules/jdk.jartool/Java.gmk b/make/modules/jdk.jartool/Java.gmk index f9b4538838f..5e06f172070 100644 --- a/make/modules/jdk.jartool/Java.gmk +++ b/make/modules/jdk.jartool/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,5 +23,4 @@ # questions. # -DISABLED_WARNINGS_java += missing-explicit-ctor JAVAC_FLAGS += -XDstringConcat=inline diff --git a/make/modules/jdk.jdi/Java.gmk b/make/modules/jdk.jdi/Java.gmk index 12ec29986b9..6577db98b0a 100644 --- a/make/modules/jdk.jdi/Java.gmk +++ b/make/modules/jdk.jdi/Java.gmk @@ -23,7 +23,7 @@ # questions. # -DISABLED_WARNINGS_java += dangling-doc-comments this-escape +DISABLED_WARNINGS_java += dangling-doc-comments EXCLUDES += \ com/sun/tools/example/debug/bdi \ diff --git a/make/modules/jdk.jlink/Java.gmk b/make/modules/jdk.jlink/Java.gmk deleted file mode 100644 index 269a1195b6a..00000000000 --- a/make/modules/jdk.jlink/Java.gmk +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -DISABLED_WARNINGS_java += this-escape diff --git a/make/modules/jdk.jstatd/Java.gmk b/make/modules/jdk.jstatd/Java.gmk deleted file mode 100644 index 269a1195b6a..00000000000 --- a/make/modules/jdk.jstatd/Java.gmk +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -DISABLED_WARNINGS_java += this-escape diff --git a/make/modules/jdk.unsupported/Java.gmk b/make/modules/jdk.unsupported/Java.gmk deleted file mode 100644 index fc8b2f832d7..00000000000 --- a/make/modules/jdk.unsupported/Java.gmk +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -DISABLED_WARNINGS_java += dangling-doc-comments diff --git a/make/modules/jdk.zipfs/Java.gmk b/make/modules/jdk.zipfs/Java.gmk deleted file mode 100644 index 0771884172f..00000000000 --- a/make/modules/jdk.zipfs/Java.gmk +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -DISABLED_WARNINGS_java += dangling-doc-comments - diff --git a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java index bfeb0b7e621..9ef6add27df 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -4744,7 +4744,6 @@ private static class TextAttributeConstants { static final Boolean RUN_DIRECTION_LTR = (jafa == null) ? Boolean.FALSE : (Boolean)jafa.getTextAttributeConstant("RUN_DIRECTION_LTR"); - @SuppressWarnings("serial") private static AttributedCharacterIterator.Attribute getTextAttribute(String name) { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/BiClassValue.java b/src/jdk.dynalink/share/classes/jdk/dynalink/BiClassValue.java index 0a1b739c493..a1faf464ea6 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/BiClassValue.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/BiClassValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,7 +113,6 @@ T getReverseValue(final Class c) { } private T compute(final VarHandle mapHandle, final Class c, final Function, T> compute) { - @SuppressWarnings("unchecked") Map, T> map = (Map, T>) mapHandle.getVolatile(this); T value; T newValue = null; @@ -128,7 +127,6 @@ private T compute(final VarHandle mapHandle, final Class c, final Function, T>[] entries = map.entrySet().toArray(new Map.Entry[map.size() + 1]); entries[map.size()] = Map.entry(c, newValue); final var newMap = Map.ofEntries(entries); - @SuppressWarnings("unchecked") final var witness = (Map, T>) mapHandle.compareAndExchange(this, map, newMap); if (witness == map) { value = newValue; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/OverloadedDynamicMethod.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/OverloadedDynamicMethod.java index dd771a0ce31..2f3c3315fbf 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/OverloadedDynamicMethod.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/OverloadedDynamicMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -151,7 +151,7 @@ MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final Li // This is typical for very generic signatures at call sites. Typical example: call site specifies // (Object, Object), and we have a method whose parameter types are (String, int). None of the JLS applicability // rules will trigger, but we must consider the method, as it can be the right match for a concrete invocation. - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings("unchecked") final List invokables = (List)methods.clone(); invokables.removeAll(subtypingApplicables.getMethods()); invokables.removeAll(methodInvocationApplicables.getMethods()); diff --git a/src/jdk.jsobject/share/classes/module-info.java b/src/jdk.jsobject/share/classes/module-info.java index 22ee6576af3..13ec8943a21 100644 --- a/src/jdk.jsobject/share/classes/module-info.java +++ b/src/jdk.jsobject/share/classes/module-info.java @@ -31,7 +31,6 @@ * @deprecated The jdk.jsobject module will be delivered with JavaFX. */ @Deprecated(since = "24", forRemoval = true) -@SuppressWarnings("removal") module jdk.jsobject { exports netscape.javascript; } diff --git a/src/jdk.jsobject/share/classes/netscape/javascript/JSException.java b/src/jdk.jsobject/share/classes/netscape/javascript/JSException.java index 7fe8ad8dd04..fe3fd7190e6 100644 --- a/src/jdk.jsobject/share/classes/netscape/javascript/JSException.java +++ b/src/jdk.jsobject/share/classes/netscape/javascript/JSException.java @@ -33,7 +33,6 @@ * @deprecated The jdk.jsobject module will be delivered with JavaFX. */ @Deprecated(since = "24", forRemoval = true) -@SuppressWarnings("removal") public class JSException extends RuntimeException { private static final long serialVersionUID = 2778103758223661489L; From f95097cc64f1d7647f8328b623e9bd9f1180b6d8 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Tue, 5 Nov 2024 15:46:00 +0000 Subject: [PATCH 10/23] 8343482: Remove unnecessary @SuppressWarnings annotations (net) Reviewed-by: dfuchs --- src/java.base/share/classes/java/net/Socket.java | 1 - .../sun/net/www/protocol/http/NegotiateAuthentication.java | 4 +--- .../sun/net/www/protocol/http/ntlm/NTLMAuthentication.java | 4 +--- src/jdk.net/share/classes/jdk/net/Sockets.java | 3 +-- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java index 309fa7a80d0..5fe6d1e0bb3 100644 --- a/src/java.base/share/classes/java/net/Socket.java +++ b/src/java.base/share/classes/java/net/Socket.java @@ -2057,7 +2057,6 @@ public Socket setOption(SocketOption name, T value) throws IOException { * * @since 9 */ - @SuppressWarnings("unchecked") public T getOption(SocketOption name) throws IOException { Objects.requireNonNull(name); if (isClosed()) diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java b/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java index 7881a1480c9..27442382ec7 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,6 @@ class NegotiateAuthentication extends AuthenticationInfo { @java.io.Serial private static final long serialVersionUID = 100L; - @SuppressWarnings("serial") // Not statically typed as Serializable private final HttpCallerInfo hci; // These maps are used to manage the GSS availability for different @@ -71,7 +70,6 @@ class NegotiateAuthentication extends AuthenticationInfo { } // The HTTP Negotiate Helper - @SuppressWarnings("serial") // Not statically typed as Serializable private Negotiator negotiator = null; /** diff --git a/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index 050e12e3594..8a2944081d5 100644 --- a/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,10 +120,8 @@ public String run() { }); }; - @SuppressWarnings("serial") // Type of field is not Serializable PasswordAuthentication pw; - @SuppressWarnings("serial") // Type of field is not Serializable Client client; /** * Create a NTLMAuthentication: diff --git a/src/jdk.net/share/classes/jdk/net/Sockets.java b/src/jdk.net/share/classes/jdk/net/Sockets.java index a8effd8dba6..3d113b562ae 100644 --- a/src/jdk.net/share/classes/jdk/net/Sockets.java +++ b/src/jdk.net/share/classes/jdk/net/Sockets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -303,7 +303,6 @@ static boolean isReusePortAvailable() { return isReusePortAvailable; } - @SuppressWarnings("removal") private static Map,Set>> optionSets() { Map,Set>> options = new HashMap<>(); boolean incomingNapiIdsupported = PlatformSocketOptions.get().incomingNapiIdSupported(); From fbf9b96b6103250a2f72c3cbc47d73e9ddea6dbd Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Tue, 5 Nov 2024 15:48:02 +0000 Subject: [PATCH 11/23] 8343480: Remove unnecessary @SuppressWarnings annotations (javadoc) Reviewed-by: hannesw --- .../internal/doclets/formats/html/taglets/TagletWriter.java | 3 +-- .../share/classes/jdk/javadoc/internal/doclint/Checker.java | 2 +- .../share/classes/jdk/javadoc/internal/tool/Start.java | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java index 79b4433a58b..ca1b6ae016b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -367,7 +367,6 @@ public Content createAnchorAndSearchIndex(Element element, String tagText, Strin return createAnchorAndSearchIndex(element, tagText, Text.of(tagText), desc, tree); } - @SuppressWarnings("preview") Content createAnchorAndSearchIndex(Element element, String tagText, Content tagContent, String desc, DocTree tree) { Content result; if (context.isFirstSentence && context.inSummary || context.inTags.contains(DocTree.Kind.INDEX) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index 7bc55639501..3669c800a8e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -678,7 +678,7 @@ void warnIfEmpty(TagStackItem tsi, DocTree endTree) { // - @Override @DefinedBy(Api.COMPILER_TREE) @SuppressWarnings("fallthrough") + @Override @DefinedBy(Api.COMPILER_TREE) public Void visitAttribute(AttributeTree tree, Void ignore) { // for now, ensure we're in an HTML StartElementTree; // in time, we might check uses of attributes in other tree nodes diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java index 4422c2caa27..2a695d876a2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java @@ -336,7 +336,6 @@ private void showLines(String message) { /** * Main program - external wrapper. */ - @SuppressWarnings("deprecation") Result begin(String... argv) { // Preprocess @file arguments List allArgs; From 8cb122119409fb13b4b9b2e74851207734d5c198 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 5 Nov 2024 15:48:23 +0000 Subject: [PATCH 12/23] 8343532: Test test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java fails on Linux ppc64le after JDK-8319343 Reviewed-by: mdoerr, lucy --- .../appcds/jigsaw/addmods/AddmodsOption.java | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java index 4bc779899ac..114dd6b9f3a 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java @@ -28,12 +28,19 @@ * @requires vm.cds.write.archived.java.heap * @requires vm.flagless * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds - * @run driver AddmodsOption + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AddmodsOption */ import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.whitebox.WhiteBox; public class AddmodsOption { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final boolean isJVMCISupported = (WB.getBooleanVMFlag("EnableJVMCI") != null); + public static void main(String[] args) throws Exception { final String moduleOption = "jdk.httpserver/sun.net.httpserver.simpleserver.Main"; final String incubatorModule = "jdk.incubator.vector"; @@ -42,7 +49,7 @@ public static void main(String[] args) throws Exception { final String allSystem = "ALL-SYSTEM"; final String allModulePath = "ALL-MODULE-PATH"; final String loggingOption = "-Xlog:cds=debug,cds+module=debug,cds+heap=info,module=trace"; - final String versionPattern = "java.[0-9][0-9][-].*"; + final String versionPattern = "java.[0-9][0-9].*"; final String subgraphCannotBeUsed = "subgraph jdk.internal.module.ArchivedBootLayer cannot be used because full module graph is disabled"; final String warningIncubator = "WARNING: Using incubator modules: jdk.incubator.vector"; String archiveName = TestCommon.getNewArchiveName("addmods-option"); @@ -136,31 +143,33 @@ public static void main(String[] args) throws Exception { .shouldContain("subgraph jdk.internal.module.ArchivedBootLayer is not recorde") .shouldHaveExitValue(0); - // dump an archive with JVMCI option which indirectly adds the - // jdk.internal.vm.ci module using the --add-modules option - archiveName = TestCommon.getNewArchiveName("jvmci-module"); - TestCommon.setCurrentArchiveName(archiveName); - oa = TestCommon.dumpBaseArchive( - archiveName, - loggingOption, - "-XX:+UnlockExperimentalVMOptions", - "-XX:+EagerJVMCI", "-XX:+UseJVMCICompiler", - "-version"); - oa.shouldHaveExitValue(0); - - // run with the JVMCI option - oa = TestCommon.execCommon( - loggingOption, - "-XX:+UnlockExperimentalVMOptions", - "-XX:+EagerJVMCI", "-XX:+UseJVMCICompiler", - "-version"); - try { - oa.shouldHaveExitValue(0) - .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.internal.vm.ci"); - } catch (RuntimeException re) { - // JVMCI compile may not be available - oa.shouldHaveExitValue(1) - .shouldContain("Cannot use JVMCI compiler: No JVMCI compiler found"); + if (isJVMCISupported) { + // dump an archive with JVMCI option which indirectly adds the + // jdk.internal.vm.ci module using the --add-modules option + archiveName = TestCommon.getNewArchiveName("jvmci-module"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "-XX:+UnlockExperimentalVMOptions", + "-XX:+EagerJVMCI", "-XX:+UseJVMCICompiler", + "-version"); + oa.shouldHaveExitValue(0); + + // run with the JVMCI option + oa = TestCommon.execCommon( + loggingOption, + "-XX:+UnlockExperimentalVMOptions", + "-XX:+EagerJVMCI", "-XX:+UseJVMCICompiler", + "-version"); + try { + oa.shouldHaveExitValue(0) + .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.internal.vm.ci"); + } catch (RuntimeException re) { + // JVMCI compile may not be available + oa.shouldHaveExitValue(1) + .shouldContain("Cannot use JVMCI compiler: No JVMCI compiler found"); + } } // dump an archive with multiple modules in -add-modules From 839de82c314697d7461b77caa9d85407e3578de3 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Tue, 5 Nov 2024 17:06:04 +0000 Subject: [PATCH 13/23] 8332744: [REDO] 'internal proprietary API' diagnostics if --system is configured to an earlier JDK version Reviewed-by: vromero --- .../com/sun/tools/javac/code/ClassFinder.java | 23 ++-- .../options/system/SystemSunProprietary.java | 127 ++++++++++++++++++ .../bench/java/lang/foreign/BulkOps.java | 2 +- .../java/lang/foreign/LoopOverConstant.java | 2 +- .../bench/java/lang/foreign/LoopOverNew.java | 2 +- .../java/lang/foreign/LoopOverNewHeap.java | 2 +- .../lang/foreign/LoopOverNonConstant.java | 2 +- .../foreign/LoopOverNonConstantAsType.java | 2 +- .../lang/foreign/LoopOverNonConstantFP.java | 2 +- .../lang/foreign/LoopOverNonConstantHeap.java | 2 +- .../foreign/LoopOverNonConstantMapped.java | 2 +- .../foreign/LoopOverNonConstantShared.java | 2 +- .../lang/foreign/LoopOverPollutedBuffer.java | 2 +- .../foreign/LoopOverPollutedSegments.java | 2 +- .../lang/foreign/MemorySegmentCopyUnsafe.java | 2 +- .../lang/foreign/MemorySegmentGetUnsafe.java | 2 +- .../lang/foreign/MemorySegmentZeroUnsafe.java | 2 +- .../bench/java/lang/foreign/ParallelSum.java | 2 +- .../java/lang/foreign/UnrolledAccess.java | 2 +- .../bench/java/lang/foreign/Utils.java | 2 +- .../foreign/xor/GetArrayUnsafeXorOpImpl.java | 2 +- .../org/openjdk/bench/sun/misc/UnsafeOps.java | 2 +- 22 files changed, 161 insertions(+), 29 deletions(-) create mode 100644 test/langtools/tools/javac/options/system/SystemSunProprietary.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java index 95f8f847923..972d6a1075b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java @@ -241,7 +241,7 @@ protected ClassFinder(Context context) { * available from the module system. */ long getSupplementaryFlags(ClassSymbol c) { - if (jrtIndex == null || !jrtIndex.isInJRT(c.classfile) || c.name == names.module_info) { + if (c.name == names.module_info) { return 0; } @@ -257,17 +257,22 @@ long getSupplementaryFlags(ClassSymbol c) { try { ModuleSymbol owningModule = packge.modle; if (owningModule == syms.noModule) { - JRTIndex.CtSym ctSym = jrtIndex.getCtSym(packge.flatName()); - Profile minProfile = Profile.DEFAULT; - if (ctSym.proprietary) - newFlags |= PROPRIETARY; - if (ctSym.minProfile != null) - minProfile = Profile.lookup(ctSym.minProfile); - if (profile != Profile.DEFAULT && minProfile.value > profile.value) { - newFlags |= NOT_IN_PROFILE; + if (jrtIndex != null && jrtIndex.isInJRT(c.classfile)) { + JRTIndex.CtSym ctSym = jrtIndex.getCtSym(packge.flatName()); + Profile minProfile = Profile.DEFAULT; + if (ctSym.proprietary) + newFlags |= PROPRIETARY; + if (ctSym.minProfile != null) + minProfile = Profile.lookup(ctSym.minProfile); + if (profile != Profile.DEFAULT && minProfile.value > profile.value) { + newFlags |= NOT_IN_PROFILE; + } } } else if (owningModule.name == names.jdk_unsupported) { newFlags |= PROPRIETARY; + } else { + // don't accumulate user modules in supplementaryFlags + return 0; } } catch (IOException ignore) { } diff --git a/test/langtools/tools/javac/options/system/SystemSunProprietary.java b/test/langtools/tools/javac/options/system/SystemSunProprietary.java new file mode 100644 index 00000000000..0a16305aaba --- /dev/null +++ b/test/langtools/tools/javac/options/system/SystemSunProprietary.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2024, Alphabet LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8331081 + * @summary Verify 'internal proprietary API' diagnostics if --system is configured + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.jvm jdk.jdeps/com.sun.tools.javap + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavapTask toolbox.TestRunner + * @run main SystemSunProprietary + */ +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.Task.Expect; +import toolbox.TestRunner; +import toolbox.ToolBox; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +public class SystemSunProprietary extends TestRunner { + + private final ToolBox tb = new ToolBox(); + + public SystemSunProprietary() { + super(System.err); + } + + public static void main(String... args) throws Exception { + new SystemSunProprietary().runTests(); + } + + @Test + public void testUnsafe(Path base) throws IOException { + Path src = base.resolve("src"); + tb.writeJavaFiles( + src, + "module m { requires jdk.unsupported; }", + "package test; public class Test { sun.misc.Unsafe unsafe; } "); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log; + List expected = + Arrays.asList( + "Test.java:1:43: compiler.warn.sun.proprietary: sun.misc.Unsafe", + "1 warning"); + + log = + new JavacTask(tb) + .options("-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + if (!expected.equals(log)) { + throw new AssertionError("Unexpected output: " + log); + } + + log = + new JavacTask(tb) + .options("-XDrawDiagnostics", "--system", System.getProperty("java.home")) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + if (!expected.equals(log)) { + throw new AssertionError("Unexpected output: " + log); + } + + // Create a valid argument to system that isn't the current java.home + Path originalSystem = Path.of(System.getProperty("java.home")); + Path system = base.resolve("system"); + for (String path : List.of("release", "lib/modules", "lib/jrt-fs.jar")) { + Path to = system.resolve(path); + Files.createDirectories(to.getParent()); + Files.copy(originalSystem.resolve(path), to); + } + + log = + new JavacTask(tb) + .options("-XDrawDiagnostics", "--system", system.toString()) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + if (!expected.equals(log)) { + throw new AssertionError("Unexpected output: " + log); + } + } + + protected void runTests() throws Exception { + runTests(m -> new Object[] {Paths.get(m.getName())}); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java b/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java index 3546fa1cca4..f779d52151c 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java @@ -35,7 +35,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverConstant.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverConstant.java index 05e764d7fe3..8f758477cbe 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverConstant.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverConstant.java @@ -33,7 +33,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.lang.foreign.MemorySegment; import java.lang.foreign.Arena; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNew.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNew.java index db456f57aaa..d74ac8fbcee 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNew.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNew.java @@ -34,7 +34,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNewHeap.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNewHeap.java index feafb721028..94c220292a0 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNewHeap.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNewHeap.java @@ -35,7 +35,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.nio.IntBuffer; import java.util.concurrent.TimeUnit; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstant.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstant.java index 91ce8faec38..da7d15483e8 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstant.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstant.java @@ -36,7 +36,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java index 834d051cff0..547e3bc298f 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java @@ -37,7 +37,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantFP.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantFP.java index 251d5621bcf..4a24512b22d 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantFP.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantFP.java @@ -35,7 +35,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantHeap.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantHeap.java index 7db3bc14665..e123e5baf1a 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantHeap.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantHeap.java @@ -36,7 +36,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantMapped.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantMapped.java index f1b9a81091f..ee4a4f3c60b 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantMapped.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantMapped.java @@ -35,7 +35,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.io.File; import java.io.IOException; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantShared.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantShared.java index c64391f242b..9504439bda1 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantShared.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantShared.java @@ -35,7 +35,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverPollutedBuffer.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverPollutedBuffer.java index 434d75bcd84..99cf83b75e5 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverPollutedBuffer.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverPollutedBuffer.java @@ -33,7 +33,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverPollutedSegments.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverPollutedSegments.java index 2077a47d86a..4ad60297a32 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverPollutedSegments.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverPollutedSegments.java @@ -35,7 +35,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.util.concurrent.TimeUnit; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentCopyUnsafe.java b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentCopyUnsafe.java index c5cdd26016d..ffdff6e64ef 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentCopyUnsafe.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentCopyUnsafe.java @@ -34,7 +34,7 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.util.concurrent.TimeUnit; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentGetUnsafe.java b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentGetUnsafe.java index 31303e51141..11cb1e98889 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentGetUnsafe.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentGetUnsafe.java @@ -39,7 +39,7 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.util.concurrent.TimeUnit; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentZeroUnsafe.java b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentZeroUnsafe.java index 6a52ed3fc5b..72fdded386f 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentZeroUnsafe.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentZeroUnsafe.java @@ -23,7 +23,7 @@ package org.openjdk.bench.java.lang.foreign; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/ParallelSum.java b/test/micro/org/openjdk/bench/java/lang/foreign/ParallelSum.java index 2fcd444989f..3d00674f89e 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/ParallelSum.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/ParallelSum.java @@ -25,7 +25,7 @@ import java.lang.foreign.*; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/UnrolledAccess.java b/test/micro/org/openjdk/bench/java/lang/foreign/UnrolledAccess.java index 36c2ba32887..197dcf99e28 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/UnrolledAccess.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/UnrolledAccess.java @@ -30,7 +30,7 @@ import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.util.concurrent.TimeUnit; import static java.lang.foreign.ValueLayout.*; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/Utils.java b/test/micro/org/openjdk/bench/java/lang/foreign/Utils.java index 0bb7fa604a6..453025ed929 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/Utils.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/Utils.java @@ -22,7 +22,7 @@ */ package org.openjdk.bench.java.lang.foreign; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.lang.reflect.Field; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/xor/GetArrayUnsafeXorOpImpl.java b/test/micro/org/openjdk/bench/java/lang/foreign/xor/GetArrayUnsafeXorOpImpl.java index ae6869c40d5..9054c0dbd1e 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/xor/GetArrayUnsafeXorOpImpl.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/xor/GetArrayUnsafeXorOpImpl.java @@ -1,7 +1,7 @@ package org.openjdk.bench.java.lang.foreign.xor; import org.openjdk.bench.java.lang.foreign.Utils; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; diff --git a/test/micro/org/openjdk/bench/sun/misc/UnsafeOps.java b/test/micro/org/openjdk/bench/sun/misc/UnsafeOps.java index 1d4a80e43dd..02bd357da93 100644 --- a/test/micro/org/openjdk/bench/sun/misc/UnsafeOps.java +++ b/test/micro/org/openjdk/bench/sun/misc/UnsafeOps.java @@ -24,7 +24,7 @@ import java.lang.reflect.Field; import java.util.concurrent.TimeUnit; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; import org.openjdk.jmh.annotations.*; @BenchmarkMode(Mode.AverageTime) From 3fab8e37bbebbb3930108b2015efe488b1fa1e97 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Tue, 5 Nov 2024 17:12:17 +0000 Subject: [PATCH 14/23] 8341903: Implementation of Scoped Values (Fourth Preview) Reviewed-by: alanb --- .../share/classes/java/lang/ScopedValue.java | 111 ++++-------------- .../util/concurrent/StructuredTaskScope.java | 4 +- .../classes/javax/security/auth/Subject.java | 2 +- .../jdk/internal/javac/PreviewFeature.java | 2 +- .../java/lang/ScopedValue/ScopedValueAPI.java | 74 ++++++------ .../StructuredTaskScope/WithScopedValue.java | 22 ++-- .../misc/ThreadFlock/WithScopedValue.java | 30 ++--- 7 files changed, 88 insertions(+), 157 deletions(-) diff --git a/src/java.base/share/classes/java/lang/ScopedValue.java b/src/java.base/share/classes/java/lang/ScopedValue.java index 635fadfa8c8..ac9b598b531 100644 --- a/src/java.base/share/classes/java/lang/ScopedValue.java +++ b/src/java.base/share/classes/java/lang/ScopedValue.java @@ -75,34 +75,34 @@ * // @link substring="newInstance" target="#newInstance" : * private static final ScopedValue NAME = ScopedValue.newInstance(); * - * // @link substring="runWhere" target="#runWhere(ScopedValue, Object, Runnable)" : - * ScopedValue.runWhere(NAME, "duke", () -> doSomething()); + * // @link substring="run" target="Carrier#run(Runnable)" : + * ScopedValue.where(NAME, "duke").run(() -> doSomething()); * } * Code executed directly or indirectly by {@code doSomething}, with access to the field * {@code NAME}, can invoke {@code NAME.get()} to read the value "{@code duke}". {@code * NAME} is bound while executing the {@code run} method. It reverts to being unbound when * the {@code run} method completes. * - *

The example using {@code runWhere} invokes a method that does not return a result. - * The {@link #callWhere(ScopedValue, Object, CallableOp) callWhere} method can be used + *

The example using {@code run} invokes a method that does not return a result. + * The {@link Carrier#call(CallableOp) call} method can be used * to invoke a method that returns a result. - * In addition, {@code ScopedValue} defines the {@link #where(ScopedValue, Object)} method + * {@code ScopedValue} defines the {@link #where(ScopedValue, Object)} method * for cases where multiple mappings (of {@code ScopedValue} to value) are accumulated * in advance of calling a method with all {@code ScopedValue}s bound to their value. * *

Bindings are per-thread

* - * A {@code ScopedValue} binding to a value is per-thread. Invoking {@code xxxWhere} + * A {@code ScopedValue} binding to a value is per-thread. Invoking {@code run} * executes a method with a {@code ScopedValue} bound to a value for the current thread. * The {@link #get() get} method returns the value bound for the current thread. * *

In the example, if code executed by one thread invokes this: * {@snippet lang=java : - * ScopedValue.runWhere(NAME, "duke1", () -> doSomething()); + * ScopedValue.where(NAME, "duke1").run(() -> doSomething()); * } * and code executed by another thread invokes: * {@snippet lang=java : - * ScopedValue.runWhere(NAME, "duke2", () -> doSomething()); + * ScopedValue.where(NAME, "duke2").run(() -> doSomething()); * } * then code in {@code doSomething} (or any method that it calls) invoking {@code NAME.get()} * will read the value "{@code duke1}" or "{@code duke2}", depending on which thread is @@ -129,7 +129,7 @@ *

In the above example, suppose that code executed by {@code doSomething} binds * {@code NAME} to a new value with: * {@snippet lang=java : - * ScopedValue.runWhere(NAME, "duchess", () -> doMore()); + * ScopedValue.where(NAME, "duchess").run(() -> doMore()); * } * Code executed directly or indirectly by {@code doMore()} that invokes {@code * NAME.get()} will read the value "{@code duchess}". When {@code doMore()} completes @@ -157,14 +157,18 @@ * {@snippet lang=java : * private static final ScopedValue NAME = ScopedValue.newInstance(); - * ScopedValue.runWhere(NAME, "duke", () -> { + * ScopedValue.where(NAME, "duke").run(() -> { * try (var scope = new StructuredTaskScope()) { * - * scope.fork(() -> childTask1()); - * scope.fork(() -> childTask2()); - * scope.fork(() -> childTask3()); + * // @link substring="fork" target="StructuredTaskScope#fork(java.util.concurrent.Callable)" : + * scope.fork(() -> childTask1()); + * scope.fork(() -> childTask2()); + * scope.fork(() -> childTask3()); * - * ... + * // @link substring="join" target="StructuredTaskScope#join()" : + * scope.join(); + * + * .. * } * }); * } @@ -310,7 +314,7 @@ Object find(ScopedValue key) { */ @PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES) public static final class Carrier { - // Bit masks: a 1 in postion n indicates that this set of bound values + // Bit masks: a 1 in position n indicates that this set of bound values // hits that slot in the cache. final int bitmask; final ScopedValue key; @@ -385,7 +389,7 @@ public T get(ScopedValue key) { return (T) value; } } - throw new NoSuchElementException(); + throw new NoSuchElementException("No mapping present"); } /** @@ -409,7 +413,6 @@ public T get(ScopedValue key) { * @return the result * @throws StructureViolationException if a structure violation is detected * @throws X if {@code op} completes with an exception - * @see ScopedValue#callWhere(ScopedValue, Object, CallableOp) * @since 23 */ public R call(CallableOp op) throws X { @@ -458,7 +461,6 @@ private R runWith(Snapshot newSnapshot, CallableOp Carrier where(ScopedValue key, T value) { return Carrier.of(key, value); } - /** - * Calls a value-returning operation with a {@code ScopedValue} bound to a value - * in the current thread. When the operation completes (normally or with an - * exception), the {@code ScopedValue} will revert to being unbound, or revert to - * its previous value when previously bound, in the current thread. If {@code op} - * completes with an exception then it propagated by this method. - * - *

Scoped values are intended to be used in a structured manner. If code - * invoked directly or indirectly by the operation creates a {@link StructuredTaskScope} - * but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected - * as a structure violation when the operation completes (normally or with an - * exception). In that case, the underlying construct of the {@code StructuredTaskScope} - * is closed and {@link StructureViolationException} is thrown. - * - * @implNote - * This method is implemented to be equivalent to: - * {@snippet lang=java : - * // @link substring="call" target="Carrier#call(CallableOp)" : - * ScopedValue.where(key, value).call(op); - * } - * - * - * - * @param key the {@code ScopedValue} key - * @param value the value, can be {@code null} - * @param the type of the value - * @param the result type - * @param type of the exception thrown by the operation - * @param op the operation to call - * @return the result - * @throws StructureViolationException if a structure violation is detected - * @throws X if the operation completes with an exception - * @since 23 - */ - public static R callWhere(ScopedValue key, - T value, - CallableOp op) throws X { - return where(key, value).call(op); - } - - /** - * Run an operation with a {@code ScopedValue} bound to a value in the current - * thread. When the operation completes (normally or with an exception), the - * {@code ScopedValue} will revert to being unbound, or revert to its previous value - * when previously bound, in the current thread. If {@code op} completes with an - * exception then it propagated by this method. - * - *

Scoped values are intended to be used in a structured manner. If code - * invoked directly or indirectly by the operation creates a {@link StructuredTaskScope} - * but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected - * as a structure violation when the operation completes (normally or with an - * exception). In that case, the underlying construct of the {@code StructuredTaskScope} - * is closed and {@link StructureViolationException} is thrown. - * - * @implNote - * This method is implemented to be equivalent to: - * {@snippet lang=java : - * // @link substring="run" target="Carrier#run(Runnable)" : - * ScopedValue.where(key, value).run(op); - * } - * - * @param key the {@code ScopedValue} key - * @param value the value, can be {@code null} - * @param the type of the value - * @param op the operation to call - * @throws StructureViolationException if a structure violation is detected - */ - public static void runWhere(ScopedValue key, T value, Runnable op) { - where(key, value).run(op); - } - private ScopedValue() { this.hash = generateKey(); } @@ -642,7 +573,7 @@ public T get() { private T slowGet() { var value = findBinding(); if (value == Snapshot.NIL) { - throw new NoSuchElementException(); + throw new NoSuchElementException("ScopedValue not bound"); } Cache.put(this, value); return (T)value; diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java index edb2708934d..94dac686943 100644 --- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java @@ -261,8 +261,8 @@ * {@snippet lang=java : * private static final ScopedValue USERNAME = ScopedValue.newInstance(); * - * // @link substring="runWhere" target="ScopedValue#runWhere(ScopedValue, Object, Runnable)" : - * ScopedValue.runWhere(USERNAME, "duke", () -> { + * // @link substring="run" target="ScopedValue.Carrier#run(Runnable)" : + * ScopedValue.where(USERNAME, "duke").run(() -> { * try (var scope = new StructuredTaskScope()) { * * scope.fork(() -> childTask()); // @highlight substring="fork" diff --git a/src/java.base/share/classes/javax/security/auth/Subject.java b/src/java.base/share/classes/javax/security/auth/Subject.java index feb9e70b752..8815a3b2763 100644 --- a/src/java.base/share/classes/javax/security/auth/Subject.java +++ b/src/java.base/share/classes/javax/security/auth/Subject.java @@ -436,7 +436,7 @@ public static T callAs(final Subject subject, Objects.requireNonNull(action); if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) { try { - return ScopedValue.callWhere(SCOPED_SUBJECT, subject, action::call); + return ScopedValue.where(SCOPED_SUBJECT, subject).call(action::call); } catch (Exception e) { throw new CompletionException(e); } diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index c6ae5b13787..6ac3bfd8bce 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -70,7 +70,7 @@ public enum Feature { //--- @JEP(number=477, title="Implicitly Declared Classes and Instance Main Methods", status="Third Preview") IMPLICIT_CLASSES, - @JEP(number=481, title="Scoped Values", status="Third Preview") + @JEP(number=487, title="Scoped Values", status="Fourth Preview") SCOPED_VALUES, @JEP(number=480, title="Structured Concurrency", status="Third Preview") STRUCTURED_CONCURRENCY, diff --git a/test/jdk/java/lang/ScopedValue/ScopedValueAPI.java b/test/jdk/java/lang/ScopedValue/ScopedValueAPI.java index 615f8472e4f..3cb96533cc4 100644 --- a/test/jdk/java/lang/ScopedValue/ScopedValueAPI.java +++ b/test/jdk/java/lang/ScopedValue/ScopedValueAPI.java @@ -48,7 +48,7 @@ private static Stream factories() { } /** - * Test that runWhere invokes the Runnable's run method. + * Test that where invokes the Runnable's run method. */ @ParameterizedTest @MethodSource("factories") @@ -56,13 +56,13 @@ void testRunWhere(ThreadFactory factory) throws Exception { test(factory, () -> { class Box { static boolean executed; } ScopedValue name = ScopedValue.newInstance(); - ScopedValue.runWhere(name, "duke", () -> { Box.executed = true; }); + ScopedValue.where(name, "duke").run(() -> { Box.executed = true; }); assertTrue(Box.executed); }); } /** - * Test runWhere when the run method throws an exception. + * Test where when the run method throws an exception. */ @ParameterizedTest @MethodSource("factories") @@ -71,7 +71,7 @@ void testRunWhereThrows(ThreadFactory factory) throws Exception { class FooException extends RuntimeException { } ScopedValue name = ScopedValue.newInstance(); Runnable op = () -> { throw new FooException(); }; - assertThrows(FooException.class, () -> ScopedValue.runWhere(name, "duke", op)); + assertThrows(FooException.class, () -> ScopedValue.where(name, "duke").run(op)); assertFalse(name.isBound()); }); } @@ -84,7 +84,7 @@ class FooException extends RuntimeException { } void testCallWhere(ThreadFactory factory) throws Exception { test(factory, () -> { ScopedValue name = ScopedValue.newInstance(); - String result = ScopedValue.callWhere(name, "duke", name::get); + String result = ScopedValue.where(name, "duke").call(name::get); assertEquals("duke", result); }); } @@ -99,7 +99,7 @@ void testCallWhereThrows(ThreadFactory factory) throws Exception { class FooException extends RuntimeException { } ScopedValue name = ScopedValue.newInstance(); CallableOp op = () -> { throw new FooException(); }; - assertThrows(FooException.class, () -> ScopedValue.callWhere(name, "duke", op)); + assertThrows(FooException.class, () -> ScopedValue.where(name, "duke").call(op)); assertFalse(name.isBound()); }); } @@ -116,8 +116,8 @@ void testGet(ThreadFactory factory) throws Exception { assertThrows(NoSuchElementException.class, name1::get); assertThrows(NoSuchElementException.class, name2::get); - // runWhere - ScopedValue.runWhere(name1, "duke", () -> { + // where + ScopedValue.where(name1, "duke").run(() -> { assertEquals("duke", name1.get()); assertThrows(NoSuchElementException.class, name2::get); @@ -126,7 +126,7 @@ void testGet(ThreadFactory factory) throws Exception { assertThrows(NoSuchElementException.class, name2::get); // callWhere - ScopedValue.callWhere(name1, "duke", () -> { + ScopedValue.where(name1, "duke").call(() -> { assertEquals("duke", name1.get()); assertThrows(NoSuchElementException.class, name2::get); return null; @@ -148,8 +148,8 @@ void testIsBound(ThreadFactory factory) throws Exception { assertFalse(name1.isBound()); assertFalse(name2.isBound()); - // runWhere - ScopedValue.runWhere(name1, "duke", () -> { + // where + ScopedValue.where(name1, "duke").run(() -> { assertTrue(name1.isBound()); assertFalse(name2.isBound()); }); @@ -157,7 +157,7 @@ void testIsBound(ThreadFactory factory) throws Exception { assertFalse(name2.isBound()); // callWhere - ScopedValue.callWhere(name1, "duke", () -> { + ScopedValue.where(name1, "duke").call(() -> { assertTrue(name1.isBound()); assertFalse(name2.isBound()); return null; @@ -178,14 +178,14 @@ void testOrElse(ThreadFactory factory) throws Exception { assertNull(name.orElse(null)); assertEquals("default", name.orElse("default")); - // runWhere - ScopedValue.runWhere(name, "duke", () -> { + // where + ScopedValue.where(name, "duke").run(() -> { assertEquals("duke", name.orElse(null)); assertEquals("duke", name.orElse("default")); }); // callWhere - ScopedValue.callWhere(name, "duke", () -> { + ScopedValue.where(name, "duke").call(() -> { assertEquals("duke", name.orElse(null)); assertEquals("duke", name.orElse("default")); return null; @@ -204,13 +204,13 @@ class FooException extends RuntimeException { } ScopedValue name = ScopedValue.newInstance(); assertThrows(FooException.class, () -> name.orElseThrow(FooException::new)); - // runWhere - ScopedValue.runWhere(name, "duke", () -> { + // where + ScopedValue.where(name, "duke").run(() -> { assertEquals("duke", name.orElseThrow(FooException::new)); }); // callWhere - ScopedValue.callWhere(name, "duke", () -> { + ScopedValue.where(name, "duke").call(() -> { assertEquals("duke", name.orElseThrow(FooException::new)); return null; }); @@ -259,12 +259,12 @@ void testRebinding(ThreadFactory factory) throws Exception { test(factory, () -> { ScopedValue name = ScopedValue.newInstance(); - // runWhere - ScopedValue.runWhere(name, "duke", () -> { + // where + ScopedValue.where(name, "duke").run(() -> { assertTrue(name.isBound()); assertEquals("duke", name.get()); - ScopedValue.runWhere(name, "duchess", () -> { + ScopedValue.where(name, "duchess").run(() -> { assertTrue(name.isBound()); assertEquals("duchess", name.get()); }); @@ -275,11 +275,11 @@ void testRebinding(ThreadFactory factory) throws Exception { assertFalse(name.isBound()); // callWhere - ScopedValue.callWhere(name, "duke", () -> { + ScopedValue.where(name, "duke").call(() -> { assertTrue(name.isBound()); assertEquals("duke", name.get()); - ScopedValue.callWhere(name, "duchess", () -> { + ScopedValue.where(name, "duchess").call(() -> { assertTrue(name.isBound()); assertEquals("duchess", name.get()); return null; @@ -302,12 +302,12 @@ void testRebindingFromNull(ThreadFactory factory) throws Exception { test(factory, () -> { ScopedValue name = ScopedValue.newInstance(); - // runWhere - ScopedValue.runWhere(name, null, () -> { + // where + ScopedValue.where(name, null).run(() -> { assertTrue(name.isBound()); assertNull(name.get()); - ScopedValue.runWhere(name, "duchess", () -> { + ScopedValue.where(name, "duchess").run(() -> { assertTrue(name.isBound()); assertTrue("duchess".equals(name.get())); }); @@ -318,11 +318,11 @@ void testRebindingFromNull(ThreadFactory factory) throws Exception { assertFalse(name.isBound()); // callWhere - ScopedValue.callWhere(name, null, () -> { + ScopedValue.where(name, null).call(() -> { assertTrue(name.isBound()); assertNull(name.get()); - ScopedValue.callWhere(name, "duchess", () -> { + ScopedValue.where(name, "duchess").call(() -> { assertTrue(name.isBound()); assertTrue("duchess".equals(name.get())); return null; @@ -345,12 +345,12 @@ void testRebindingToNull(ThreadFactory factory) throws Exception { test(factory, () -> { ScopedValue name = ScopedValue.newInstance(); - // runWhere - ScopedValue.runWhere(name, "duke", () -> { + // where + ScopedValue.where(name, "duke").run(() -> { assertTrue(name.isBound()); assertEquals("duke", name.get()); - ScopedValue.runWhere(name, null, () -> { + ScopedValue.where(name, null).run(() -> { assertTrue(name.isBound()); assertNull(name.get()); }); @@ -361,11 +361,11 @@ void testRebindingToNull(ThreadFactory factory) throws Exception { assertFalse(name.isBound()); // callWhere - ScopedValue.callWhere(name, "duke", () -> { + ScopedValue.where(name, "duke").call(() -> { assertTrue(name.isBound()); assertEquals("duke", name.get()); - ScopedValue.callWhere(name, null, () -> { + ScopedValue.where(name, null).call(() -> { assertTrue(name.isBound()); assertNull(name.get()); return null; @@ -410,11 +410,11 @@ void testNullPointerException() { assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke")); - assertThrows(NullPointerException.class, () -> ScopedValue.runWhere(null, "duke", () -> { })); - assertThrows(NullPointerException.class, () -> ScopedValue.runWhere(name, "duke", null)); + assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke").run(() -> { })); + assertThrows(NullPointerException.class, () -> ScopedValue.where(name, "duke").run(null)); - assertThrows(NullPointerException.class, () -> ScopedValue.callWhere(null, "duke", () -> "")); - assertThrows(NullPointerException.class, () -> ScopedValue.callWhere(name, "duke", null)); + assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke").call(() -> "")); + assertThrows(NullPointerException.class, () -> ScopedValue.where(name, "duke").call(null)); assertThrows(NullPointerException.class, () -> name.orElseThrow(null)); diff --git a/test/jdk/java/util/concurrent/StructuredTaskScope/WithScopedValue.java b/test/jdk/java/util/concurrent/StructuredTaskScope/WithScopedValue.java index 1d6e5e06af3..e119756d916 100644 --- a/test/jdk/java/util/concurrent/StructuredTaskScope/WithScopedValue.java +++ b/test/jdk/java/util/concurrent/StructuredTaskScope/WithScopedValue.java @@ -54,7 +54,7 @@ private static Stream factories() { @MethodSource("factories") void testForkInheritsScopedValue1(ThreadFactory factory) throws Exception { ScopedValue name = ScopedValue.newInstance(); - String value = ScopedValue.callWhere(name, "x", () -> { + String value = ScopedValue.where(name, "x").call(() -> { try (var scope = new StructuredTaskScope(null, factory)) { Subtask subtask = scope.fork(() -> { return name.get(); // child should read "x" @@ -73,7 +73,7 @@ void testForkInheritsScopedValue1(ThreadFactory factory) throws Exception { @MethodSource("factories") void testForkInheritsScopedValue2(ThreadFactory factory) throws Exception { ScopedValue name = ScopedValue.newInstance(); - String value = ScopedValue.callWhere(name, "x", () -> { + String value = ScopedValue.where(name, "x").call(() -> { try (var scope1 = new StructuredTaskScope(null, factory)) { Subtask subtask1 = scope1.fork(() -> { try (var scope2 = new StructuredTaskScope(null, factory)) { @@ -98,13 +98,13 @@ void testForkInheritsScopedValue2(ThreadFactory factory) throws Exception { @MethodSource("factories") void testForkInheritsScopedValue3(ThreadFactory factory) throws Exception { ScopedValue name = ScopedValue.newInstance(); - String value = ScopedValue.callWhere(name, "x", () -> { + String value = ScopedValue.where(name, "x").call(() -> { try (var scope1 = new StructuredTaskScope(null, factory)) { Subtask subtask1 = scope1.fork(() -> { assertEquals(name.get(), "x"); // child should read "x" // rebind name to "y" - String grandchildValue = ScopedValue.callWhere(name, "y", () -> { + String grandchildValue = ScopedValue.where(name, "y").call(() -> { try (var scope2 = new StructuredTaskScope(null, factory)) { Subtask subtask2 = scope2.fork(() -> { return name.get(); // grandchild should read "y" @@ -136,7 +136,7 @@ class Box { var box = new Box(); try { try { - ScopedValue.runWhere(name, "x", () -> { + ScopedValue.where(name, "x").run(() -> { box.scope = new StructuredTaskScope(); }); fail(); @@ -167,7 +167,7 @@ class Box { void testStructureViolation2() throws Exception { ScopedValue name = ScopedValue.newInstance(); try (var scope = new StructuredTaskScope()) { - ScopedValue.runWhere(name, "x", () -> { + ScopedValue.where(name, "x").run(() -> { assertThrows(StructureViolationException.class, scope::close); }); } @@ -180,7 +180,7 @@ void testStructureViolation2() throws Exception { void testStructureViolation3() throws Exception { ScopedValue name = ScopedValue.newInstance(); try (var scope = new StructuredTaskScope()) { - ScopedValue.runWhere(name, "x", () -> { + ScopedValue.where(name, "x").run(() -> { assertThrows(StructureViolationException.class, () -> scope.fork(() -> "foo")); }); @@ -196,9 +196,9 @@ void testStructureViolation4() throws Exception { ScopedValue name2 = ScopedValue.newInstance(); // rebind - ScopedValue.runWhere(name1, "x", () -> { + ScopedValue.where(name1, "x").run(() -> { try (var scope = new StructuredTaskScope()) { - ScopedValue.runWhere(name1, "y", () -> { + ScopedValue.where(name1, "y").run(() -> { assertThrows(StructureViolationException.class, () -> scope.fork(() -> "foo")); }); @@ -206,9 +206,9 @@ void testStructureViolation4() throws Exception { }); // new binding - ScopedValue.runWhere(name1, "x", () -> { + ScopedValue.where(name1, "x").run(() -> { try (var scope = new StructuredTaskScope()) { - ScopedValue.runWhere(name2, "y", () -> { + ScopedValue.where(name2, "y").run(() -> { assertThrows(StructureViolationException.class, () -> scope.fork(() -> "foo")); }); diff --git a/test/jdk/jdk/internal/misc/ThreadFlock/WithScopedValue.java b/test/jdk/jdk/internal/misc/ThreadFlock/WithScopedValue.java index f2bfd241722..19b829bc7e8 100644 --- a/test/jdk/jdk/internal/misc/ThreadFlock/WithScopedValue.java +++ b/test/jdk/jdk/internal/misc/ThreadFlock/WithScopedValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ private static Stream factories() { @MethodSource("factories") void testInheritsScopedValue(ThreadFactory factory) throws Exception { ScopedValue name = ScopedValue.newInstance(); - String value = ScopedValue.callWhere(name, "duke", () -> { + String value = ScopedValue.where(name, "duke").call(() -> { var result = new AtomicReference(); try (var flock = ThreadFlock.open(null)) { Thread thread = factory.newThread(() -> { @@ -79,7 +79,7 @@ class Box { } var box = new Box(); try { - ScopedValue.runWhere(name, "x1", () -> { + ScopedValue.where(name, "x1").run(() -> { box.flock1 = ThreadFlock.open(null); box.flock2 = ThreadFlock.open(null); }); @@ -97,11 +97,11 @@ class Box { void testStructureViolation2() { ScopedValue name = ScopedValue.newInstance(); try (var flock1 = ThreadFlock.open("flock1")) { - ScopedValue.runWhere(name, "x1", () -> { + ScopedValue.where(name, "x1").run(() -> { try (var flock2 = ThreadFlock.open("flock2")) { - ScopedValue.runWhere(name, "x2", () -> { + ScopedValue.where(name, "x2").run(() -> { try (var flock3 = ThreadFlock.open("flock3")) { - ScopedValue.runWhere(name, "x3", () -> { + ScopedValue.where(name, "x3").run(() -> { var flock4 = ThreadFlock.open("flock4"); try { @@ -129,11 +129,11 @@ void testStructureViolation2() { void testStructureViolation3() { ScopedValue name = ScopedValue.newInstance(); try (var flock1 = ThreadFlock.open("flock1")) { - ScopedValue.runWhere(name, "x1", () -> { + ScopedValue.where(name, "x1").run(() -> { try (var flock2 = ThreadFlock.open("flock2")) { - ScopedValue.runWhere(name, "x2", () -> { + ScopedValue.where(name, "x2").run(() -> { try (var flock3 = ThreadFlock.open("flock3")) { - ScopedValue.runWhere(name, "x3", () -> { + ScopedValue.where(name, "x3").run(() -> { var flock4 = ThreadFlock.open("flock4"); try { @@ -161,11 +161,11 @@ void testStructureViolation3() { void testStructureViolation4() { ScopedValue name = ScopedValue.newInstance(); try (var flock1 = ThreadFlock.open("flock1")) { - ScopedValue.runWhere(name, "x1", () -> { + ScopedValue.where(name, "x1").run(() -> { try (var flock2 = ThreadFlock.open("flock2")) { - ScopedValue.runWhere(name, "x2", () -> { + ScopedValue.where(name, "x2").run(() -> { try (var flock3 = ThreadFlock.open("flock3")) { - ScopedValue.runWhere(name, "x3", () -> { + ScopedValue.where(name, "x3").run(() -> { var flock4 = ThreadFlock.open("flock4"); try { @@ -193,7 +193,7 @@ void testStructureViolation4() { void testStructureViolation5(ThreadFactory factory) throws Exception { ScopedValue name = ScopedValue.newInstance(); try (var flock = ThreadFlock.open(null)) { - ScopedValue.runWhere(name, "duke", () -> { + ScopedValue.where(name, "duke").run(() -> { Thread thread = factory.newThread(() -> { }); assertThrows(StructureViolationException.class, () -> flock.start(thread)); }); @@ -207,9 +207,9 @@ void testStructureViolation5(ThreadFactory factory) throws Exception { @MethodSource("factories") void testStructureViolation6(ThreadFactory factory) throws Exception { ScopedValue name = ScopedValue.newInstance(); - ScopedValue.runWhere(name, "duke", () -> { + ScopedValue.where(name, "duke").run(() -> { try (var flock = ThreadFlock.open(null)) { - ScopedValue.runWhere(name, "duchess", () -> { + ScopedValue.where(name, "duchess").run(() -> { Thread thread = factory.newThread(() -> { }); assertThrows(StructureViolationException.class, () -> flock.start(thread)); }); From 847cc5ebac43b83746d8f238c5f9ecf2972a2796 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 5 Nov 2024 20:53:08 +0000 Subject: [PATCH 15/23] 8343173: Remove ZGC-specific non-JVMCI test groups Reviewed-by: kvn --- test/hotspot/jtreg/ProblemList-zgc.txt | 8 ++++++++ test/hotspot/jtreg/TEST.groups | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 7b2978ba491..0d4cfe1cbb6 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -116,3 +116,11 @@ serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic- serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 + +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java 8343233 generic-all +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InterpreterFrameSizeTest.java 8343233 generic-aarch64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java 8343233 generic-aarch64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java 8343233 generic-aarch64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java 8343233 generic-aarch64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java 8343233 generic-aarch64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java 8343233 generic-aarch64 diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index f54dc79fcfc..2a08266d79f 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -42,10 +42,6 @@ hotspot_compiler_xcomp = \ :hotspot_compiler \ -:tier1_compiler_not_xcomp -hotspot_compiler_all_gcs = \ - :hotspot_compiler \ - -compiler/jvmci - hotspot_gc = \ gc From 2a1ae0ff89a8ac364206b09059d9dc884adcc5ac Mon Sep 17 00:00:00 2001 From: Kevin Driver Date: Tue, 5 Nov 2024 21:07:52 +0000 Subject: [PATCH 16/23] 8331008: Implement JEP 478: Key Derivation Function API (Preview) Co-authored-by: Rajan Halade Co-authored-by: Weijun Wang Co-authored-by: Valerie Peng Reviewed-by: weijun, valeriep --- .../crypto/provider/HKDFKeyDerivation.java | 414 +++++++++++ .../com/sun/crypto/provider/SunJCE.java | 10 + .../share/classes/java/security/Provider.java | 2 + .../share/classes/javax/crypto/KDF.java | 681 ++++++++++++++++++ .../classes/javax/crypto/KDFParameters.java | 50 ++ .../share/classes/javax/crypto/KDFSpi.java | 157 ++++ .../javax/crypto/spec/HKDFParameterSpec.java | 510 +++++++++++++ .../jdk/internal/javac/PreviewFeature.java | 2 + .../classes/sun/security/util/Debug.java | 2 +- .../provider/KDF/HKDFBasicFunctionsTest.java | 80 ++ .../provider/KDF/HKDFExhaustiveTest.java | 556 ++++++++++++++ .../provider/KDF/HKDFKnownAnswerTests.java | 282 ++++++++ .../crypto/provider/KDF/HKDFSaltIKMTest.java | 92 +++ .../KDF/KDFDelayedProviderSyncTest.java | 73 ++ .../crypto/KDF/KDFDelayedProviderTest.java | 180 +++++ .../KDF/KDFDelayedProviderThreadingTest.java | 130 ++++ .../javax/crypto/ProviderVerifier.java | 101 +++ 17 files changed, 3321 insertions(+), 1 deletion(-) create mode 100644 src/java.base/share/classes/com/sun/crypto/provider/HKDFKeyDerivation.java create mode 100644 src/java.base/share/classes/javax/crypto/KDF.java create mode 100644 src/java.base/share/classes/javax/crypto/KDFParameters.java create mode 100644 src/java.base/share/classes/javax/crypto/KDFSpi.java create mode 100644 src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.java create mode 100644 test/jdk/com/sun/crypto/provider/KDF/HKDFBasicFunctionsTest.java create mode 100644 test/jdk/com/sun/crypto/provider/KDF/HKDFExhaustiveTest.java create mode 100644 test/jdk/com/sun/crypto/provider/KDF/HKDFKnownAnswerTests.java create mode 100644 test/jdk/com/sun/crypto/provider/KDF/HKDFSaltIKMTest.java create mode 100644 test/jdk/javax/crypto/KDF/KDFDelayedProviderSyncTest.java create mode 100644 test/jdk/javax/crypto/KDF/KDFDelayedProviderTest.java create mode 100644 test/jdk/javax/crypto/KDF/KDFDelayedProviderThreadingTest.java create mode 100644 test/jdk/security/unsignedjce/java.base/javax/crypto/ProviderVerifier.java diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HKDFKeyDerivation.java b/src/java.base/share/classes/com/sun/crypto/provider/HKDFKeyDerivation.java new file mode 100644 index 00000000000..a9988bbc115 --- /dev/null +++ b/src/java.base/share/classes/com/sun/crypto/provider/HKDFKeyDerivation.java @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.crypto.provider; + +import javax.crypto.KDFSpi; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.HKDFParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import javax.crypto.KDFParameters; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.spec.AlgorithmParameterSpec; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * KDF implementation for the HKDF function. + *

+ * This class implements the HKDF-Extract and HKDF-Expand functions from RFC + * 5869. This implementation provides the complete Extract-then-Expand HKDF + * function as well as Extract-only and Expand-only variants. + * + * @spec https://www.rfc-editor.org/info/rfc5869 + * RFC 5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF) + */ +abstract class HKDFKeyDerivation extends KDFSpi { + + private final int hmacLen; + private final String hmacAlgName; + + private enum SupportedHmac { + SHA256("HmacSHA256", 32), + SHA384("HmacSHA384", 48), + SHA512("HmacSHA512", 64); + + private final String hmacAlg; + private final int hmacLen; + SupportedHmac(String hmacAlg, int hmacLen) { + this.hmacAlg = hmacAlg; + this.hmacLen = hmacLen; + } + }; + + /** + * The sole constructor. + * + * @param kdfParameters + * the initialization parameters (may be {@code null}) + * + * @throws InvalidAlgorithmParameterException + * if the initialization parameters are inappropriate for this + * {@code KDFSpi} + */ + private HKDFKeyDerivation(SupportedHmac supportedHmac, + KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException { + super(kdfParameters); + if (kdfParameters != null) { + throw new InvalidAlgorithmParameterException( + supportedHmac.hmacAlg + " does not support parameters"); + } + this.hmacAlgName = supportedHmac.hmacAlg; + this.hmacLen = supportedHmac.hmacLen; + } + + /** + * Derive a key, returned as a {@code SecretKey} object. + * + * @return a derived {@code SecretKey} object of the specified algorithm + * + * @throws InvalidAlgorithmParameterException + * if the information contained within the {@code derivationSpec} is + * invalid or if the combination of {@code alg} and the + * {@code derivationSpec} results in something invalid + * @throws NoSuchAlgorithmException + * if {@code alg} is empty + * @throws NullPointerException + * if {@code alg} is {@code null} + */ + @Override + protected SecretKey engineDeriveKey(String alg, + AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException, + NoSuchAlgorithmException { + + if (alg == null) { + throw new NullPointerException( + "the algorithm for the SecretKey return value must not be" + + " null"); + } + if (alg.isEmpty()) { + throw new NoSuchAlgorithmException( + "the algorithm for the SecretKey return value must not be " + + "empty"); + } + + return new SecretKeySpec(engineDeriveData(derivationSpec), alg); + + } + + /** + * Obtain raw data from a key derivation function. + * + * @return a derived {@code byte[]} + * + * @throws InvalidAlgorithmParameterException + * if the information contained within the {@code KDFParameterSpec} + * is invalid or incorrect for the type of key to be derived + * @throws UnsupportedOperationException + * if the derived keying material is not extractable + */ + @Override + protected byte[] engineDeriveData(AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException { + List ikms, salts; + byte[] inputKeyMaterial, salt, pseudoRandomKey, info; + int length; + if (derivationSpec instanceof HKDFParameterSpec.Extract anExtract) { + ikms = anExtract.ikms(); + salts = anExtract.salts(); + // we should be able to combine both of the above Lists of key + // segments into one SecretKey object each, unless we were passed + // something bogus or an unexportable P11 key + inputKeyMaterial = null; + salt = null; + try { + inputKeyMaterial = consolidateKeyMaterial(ikms); + salt = consolidateKeyMaterial(salts); + + // perform extract + return hkdfExtract(inputKeyMaterial, salt); + } catch (InvalidKeyException ike) { + throw new InvalidAlgorithmParameterException( + "an HKDF Extract could not be initialized with the " + + "given key or salt material", ike); + } catch (NoSuchAlgorithmException nsae) { + // This is bubbling up from the getInstance of the Mac/Hmac. + // Since we're defining these values internally, it is unlikely. + throw new ProviderException( + "could not instantiate a Mac with the provided " + + "algorithm", + nsae); + } finally { + if (inputKeyMaterial != null) { + Arrays.fill(inputKeyMaterial, (byte) 0x00); + } + if (salt != null) { + Arrays.fill(salt, (byte) 0x00); + } + } + } else if (derivationSpec instanceof HKDFParameterSpec.Expand anExpand) { + // set this value in the "if" + if ((pseudoRandomKey = anExpand.prk().getEncoded()) == null) { + throw new AssertionError( + "PRK is required for HKDFParameterSpec.Expand"); + } + // set this value in the "if" + if ((info = anExpand.info()) == null) { + info = new byte[0]; + } + length = anExpand.length(); + if (length > (hmacLen * 255)) { + throw new InvalidAlgorithmParameterException( + "Requested length exceeds maximum allowed length"); + } + // perform expand + try { + return hkdfExpand(pseudoRandomKey, info, length); + } catch (InvalidKeyException ike) { + throw new InvalidAlgorithmParameterException( + "an HKDF Expand could not be initialized with the " + + "given keying material", ike); + } catch (NoSuchAlgorithmException nsae) { + // This is bubbling up from the getInstance of the Mac/Hmac. + // Since we're defining these values internally, it is unlikely. + throw new ProviderException( + "could not instantiate a Mac with the provided " + + "algorithm", + nsae); + } finally { + Arrays.fill(pseudoRandomKey, (byte) 0x00); + } + } else if (derivationSpec instanceof HKDFParameterSpec.ExtractThenExpand anExtractThenExpand) { + ikms = anExtractThenExpand.ikms(); + salts = anExtractThenExpand.salts(); + // we should be able to combine both of the above Lists of key + // segments into one SecretKey object each, unless we were passed + // something bogus or an unexportable P11 key + inputKeyMaterial = null; + salt = null; + pseudoRandomKey = null; + try { + inputKeyMaterial = consolidateKeyMaterial(ikms); + salt = consolidateKeyMaterial(salts); + + // set this value in the "if" + if ((info = anExtractThenExpand.info()) == null) { + info = new byte[0]; + } + length = anExtractThenExpand.length(); + if (length > (hmacLen * 255)) { + throw new InvalidAlgorithmParameterException( + "Requested length exceeds maximum allowed length"); + } + + // perform extract and then expand + pseudoRandomKey = hkdfExtract(inputKeyMaterial, salt); + return hkdfExpand(pseudoRandomKey, info, length); + } catch (InvalidKeyException ike) { + throw new InvalidAlgorithmParameterException( + "an HKDF ExtractThenExpand could not be initialized " + + "with the given key or salt material", ike); + } catch (NoSuchAlgorithmException nsae) { + // This is bubbling up from the getInstance of the Mac/HMAC. + // Since we're defining these values internally, it is unlikely. + throw new ProviderException( + "could not instantiate a Mac with the provided " + + "algorithm", + nsae); + } finally { + if (inputKeyMaterial != null) { + Arrays.fill(inputKeyMaterial, (byte) 0x00); + } + if (salt != null) { + Arrays.fill(salt, (byte) 0x00); + } + if (pseudoRandomKey != null) { + Arrays.fill(pseudoRandomKey, (byte) 0x00); + } + } + } + throw new InvalidAlgorithmParameterException( + "an HKDF derivation requires a valid HKDFParameterSpec"); + } + + // throws an InvalidKeyException if any key is unextractable + private byte[] consolidateKeyMaterial(List keys) + throws InvalidKeyException { + if (keys != null && !keys.isEmpty()) { + ArrayList localKeys = new ArrayList<>(keys); + if (localKeys.size() == 1) { + // return this element + SecretKey checkIt = localKeys.get(0); + return CipherCore.getKeyBytes(checkIt); + } else { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (SecretKey workItem : localKeys) { + os.writeBytes(CipherCore.getKeyBytes(workItem)); + } + // deliberately omitting os.flush(), since we are writing to + // memory, and toByteArray() reads like there isn't an explicit + // need for this call + return os.toByteArray(); + } + } else if (keys != null) { + return new byte[0]; + } else { + throw new InvalidKeyException( + "List of key segments could not be consolidated"); + } + } + + /** + * Perform the HKDF-Extract operation. + * + * @param inputKeyMaterial + * the input keying material used for the HKDF-Extract operation. + * @param salt + * the salt value used for HKDF-Extract + * + * @return a byte array containing the pseudorandom key (PRK) + * + * @throws InvalidKeyException + * if an invalid salt was provided through the + * {@code HKDFParameterSpec} + */ + private byte[] hkdfExtract(byte[] inputKeyMaterial, byte[] salt) + throws InvalidKeyException, NoSuchAlgorithmException { + + // salt will not be null + if (salt.length == 0) { + salt = new byte[hmacLen]; + } + Mac hmacObj = Mac.getInstance(hmacAlgName); + hmacObj.init(new SecretKeySpec(salt, hmacAlgName)); + + // inputKeyMaterial will not be null + return hmacObj.doFinal(inputKeyMaterial); + } + + /** + * Perform the HKDF-Expand operation. + * + * @param prk + * the pseudorandom key used for HKDF-Expand + * @param info + * optional context and application specific information or + * {@code null} if no info data is provided. + * @param outLen + * the length in bytes of the required output + * + * @return a byte array containing the complete {@code KDF} output. This + * will be at least as long as the requested length in the + * {@code outLen} parameter, but will be rounded up to the nearest + * multiple of the HMAC output length. + * + * @throws InvalidKeyException + * if an invalid PRK was provided through the + * {@code HKDFParameterSpec} or derived during the extract phase. + */ + private byte[] hkdfExpand(byte[] prk, byte[] info, int outLen) + throws InvalidKeyException, NoSuchAlgorithmException { + byte[] kdfOutput; + + if (prk == null || prk.length < hmacLen) { + throw new InvalidKeyException( + "prk must be at least " + hmacLen + " bytes"); + } + + SecretKey pseudoRandomKey = new SecretKeySpec(prk, hmacAlgName); + + Mac hmacObj = Mac.getInstance(hmacAlgName); + + // Calculate the number of rounds of HMAC that are needed to + // meet the requested data. Then set up the buffers we will need. + hmacObj.init(pseudoRandomKey); + int rounds = (outLen + hmacLen - 1) / hmacLen; + kdfOutput = new byte[outLen]; + int i = 0; + int offset = 0; + try { + while (i < rounds) { + if (i > 0) { + hmacObj.update(kdfOutput, offset - hmacLen, + hmacLen); // add T(i-1) + } + hmacObj.update(info); // Add info + hmacObj.update((byte) ++i); // Add round number + if (i == rounds && (outLen - offset < hmacLen)) { + // special handling for last chunk + byte[] tmp = hmacObj.doFinal(); + System.arraycopy(tmp, 0, kdfOutput, offset, + outLen - offset); + Arrays.fill(tmp, (byte) 0x00); + offset = outLen; + } else { + hmacObj.doFinal(kdfOutput, offset); + offset += hmacLen; + } + } + } catch (ShortBufferException sbe) { + // This really shouldn't happen given that we've + // sized the buffers to their largest possible size up-front, + // but just in case... + throw new ProviderException(sbe); + } + return kdfOutput; + } + + protected KDFParameters engineGetParameters() { + return null; + } + + public static final class HKDFSHA256 extends HKDFKeyDerivation { + public HKDFSHA256(KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException { + super(SupportedHmac.SHA256, kdfParameters); + } + } + + public static final class HKDFSHA384 extends HKDFKeyDerivation { + public HKDFSHA384(KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException { + super(SupportedHmac.SHA384, kdfParameters); + } + } + + public static final class HKDFSHA512 extends HKDFKeyDerivation { + public HKDFSHA512(KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException { + super(SupportedHmac.SHA512, kdfParameters); + } + } + +} \ No newline at end of file diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java index 9bb1fa7ff82..c0766077ba9 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java @@ -457,6 +457,16 @@ void putEntries() { "com.sun.crypto.provider.DHKeyAgreement", attrs); + /* + * Key Derivation engines + */ + ps("KDF", "HKDF-SHA256", + "com.sun.crypto.provider.HKDFKeyDerivation$HKDFSHA256"); + ps("KDF", "HKDF-SHA384", + "com.sun.crypto.provider.HKDFKeyDerivation$HKDFSHA384"); + ps("KDF", "HKDF-SHA512", + "com.sun.crypto.provider.HKDFKeyDerivation$HKDFSHA512"); + /* * Algorithm Parameter engines */ diff --git a/src/java.base/share/classes/java/security/Provider.java b/src/java.base/share/classes/java/security/Provider.java index adfbd9a5957..c4dac74c680 100644 --- a/src/java.base/share/classes/java/security/Provider.java +++ b/src/java.base/share/classes/java/security/Provider.java @@ -27,6 +27,7 @@ import jdk.internal.event.SecurityProviderServiceEvent; +import javax.crypto.KDFParameters; import javax.security.auth.login.Configuration; import java.io.*; import java.security.cert.CertStoreParameters; @@ -1604,6 +1605,7 @@ private static void addEngine(String name, boolean sp, Class constructorParam addEngine("KeyGenerator", false, null); addEngine("SecretKeyFactory", false, null); addEngine("KEM", true, null); + addEngine("KDF", false, KDFParameters.class); // JSSE addEngine("KeyManagerFactory", false, null); addEngine("SSLContext", false, null); diff --git a/src/java.base/share/classes/javax/crypto/KDF.java b/src/java.base/share/classes/javax/crypto/KDF.java new file mode 100644 index 00000000000..ea2a0375813 --- /dev/null +++ b/src/java.base/share/classes/javax/crypto/KDF.java @@ -0,0 +1,681 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.crypto; + +import jdk.internal.javac.PreviewFeature; +import sun.security.jca.GetInstance; +import sun.security.jca.GetInstance.Instance; +import sun.security.util.Debug; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.Provider; +import java.security.Provider.Service; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Iterator; +import java.util.Objects; + +/** + * This class provides the functionality of a Key Derivation Function (KDF), + * which is a cryptographic algorithm for deriving additional keys from input + * keying material (IKM) and (optionally) other data. + *

+ * {@code KDF} objects are instantiated with the {@code getInstance} family of + * methods. + *

+ * The class has two derive methods, {@code deriveKey} and {@code deriveData}. + * The {@code deriveKey} method accepts an algorithm name and returns a + * {@code SecretKey} object with the specified algorithm. The {@code deriveData} + * method returns a byte array of raw data. + *

+ * API Usage Example: + * {@snippet lang = java: + * KDF kdfHkdf = KDF.getInstance("HKDF-SHA256"); + * + * AlgorithmParameterSpec derivationSpec = + * HKDFParameterSpec.ofExtract() + * .addIKM(ikm) + * .addSalt(salt).thenExpand(info, 32); + * + * SecretKey sKey = kdfHkdf.deriveKey("AES", derivationSpec); + *} + *
+ *

Concurrent Access

+ * Unless otherwise documented by an implementation, the methods defined in this + * class are not thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and provide the + * necessary locking. Multiple threads each manipulating separate objects need + * not synchronize. + *
+ *

Delayed Provider Selection

+ * If a provider is not specified when calling one of the {@code getInstance} + * methods, the implementation delays the selection of the provider until the + * {@code deriveKey} or {@code deriveData} method is called. This is called + * delayed provider selection. The primary reason this is done is to + * ensure that the selected provider can handle the key material that is passed + * to those methods - for example, the key material may reside on a hardware + * device that only a specific {@code KDF} provider can utilize. The {@code + * getInstance} method returns a {@code KDF} object as long as there exists + * at least one registered security provider that implements the algorithm + * and supports the optional parameters. The delayed provider selection + * process traverses the list of registered security providers, starting with + * the most preferred {@code Provider}. The first provider that supports the + * specified algorithm, optional parameters, and key material is selected. + *

+ * If the {@code getProviderName} or {@code getParameters} method is called + * before the {@code deriveKey} or {@code deriveData} methods, the first + * provider supporting the {@code KDF} algorithm and optional + * {@code KDFParameters} is chosen. This provider may not support the key + * material that is subsequently passed to the {@code deriveKey} or + * {@code deriveData} methods. Therefore, it is recommended not to call the + * {@code getProviderName} or {@code getParameters} methods until after a key + * derivation operation. Once a provider is selected, it cannot be changed. + * + * @see KDFParameters + * @see SecretKey + * @since 24 + */ +@PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) +public final class KDF { + + private static final Debug pdebug = Debug.getInstance("provider", + "Provider"); + private static final boolean skipDebug = Debug.isOn("engine=") + && !Debug.isOn("kdf"); + + private record Delegate(KDFSpi spi, Provider provider) {} + + //guarded by 'lock' + private Delegate theOne; + //guarded by 'lock' + private final Delegate candidate; + + // The name of the KDF algorithm. + private final String algorithm; + + // Additional KDF configuration parameters + private final KDFParameters kdfParameters; + + // remaining services to try in provider selection + // null once provider is selected + private final Iterator serviceIterator; + + // This lock provides mutual exclusion, preventing multiple threads from + // concurrently initializing the same instance (delayed provider selection) + // in a way which would corrupt the internal state. + private final Object lock = new Object(); + + + // Instantiates a {@code KDF} object. This constructor is called when a + // provider is supplied to {@code getInstance}. + // + // @param delegate the delegate + // @param algorithm the algorithm + // @param kdfParameters the parameters + private KDF(Delegate delegate, String algorithm) { + this.theOne = delegate; + this.algorithm = algorithm; + // note that the parameters are being passed to the impl in getInstance + this.kdfParameters = null; + this.candidate = null; + serviceIterator = null; + } + + // Instantiates a {@code KDF} object. This constructor is called when a + // provider is not supplied to {@code getInstance}. + // + // @param firstPairOfSpiAndProv the delegate + // @param t the service iterator + // @param algorithm the algorithm + // @param kdfParameters the algorithm parameters + private KDF(Delegate firstPairOfSpiAndProv, Iterator t, + String algorithm, + KDFParameters kdfParameters) { + this.candidate = firstPairOfSpiAndProv; + serviceIterator = t; + this.algorithm = algorithm; + this.kdfParameters = kdfParameters; + } + + /** + * Returns the algorithm name of this {@code KDF} object. + * + * @return the algorithm name of this {@code KDF} object + */ + public String getAlgorithm() { + return this.algorithm; + } + + /** + * Returns the name of the provider. + * + * @return the name of the provider + * + * @see Delayed Provider + * Selection + */ + public String getProviderName() { + useFirstSpi(); + return theOne.provider().getName(); + } + + /** + * Returns the {@code KDFParameters} used with this {@code KDF} object. + *

+ * The returned parameters may be the same that were used to initialize + * this {@code KDF} object, or may contain additional default or + * random parameter values used by the underlying KDF algorithm. + * If the required parameters were not supplied and can be generated by + * the {@code KDF} object, the generated parameters are returned; + * otherwise {@code null} is returned. + * + * @return the parameters used with this {@code KDF} object, or + * {@code null} + * + * @see Delayed Provider + * Selection + */ + public KDFParameters getParameters() { + useFirstSpi(); + return theOne.spi().engineGetParameters(); + } + + /** + * Returns a {@code KDF} object that implements the specified algorithm. + * + * @implNote The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property to + * determine the preferred provider order for the specified + * algorithm. This may be different than the order of providers + * returned by + * {@link Security#getProviders() Security.getProviders()}. + * + * @param algorithm + * the key derivation algorithm to use. See the {@code KDF} section + * in the + * Java Security Standard Algorithm Names Specification for + * information about standard KDF algorithm names. + * + * @return a {@code KDF} object + * + * @throws NoSuchAlgorithmException + * if no {@code Provider} supports a {@code KDF} implementation for + * the specified algorithm + * @throws NullPointerException + * if {@code algorithm} is {@code null} + * @see Delayed Provider + * Selection + */ + public static KDF getInstance(String algorithm) + throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "algorithm must not be null"); + try { + return getInstance(algorithm, (KDFParameters) null); + } catch (InvalidAlgorithmParameterException e) { + throw new NoSuchAlgorithmException( + "No implementation found using null KDFParameters", e); + } + } + + /** + * Returns a {@code KDF} object that implements the specified algorithm from + * the specified security provider. The specified provider must be + * registered in the security provider list. + * + * @param algorithm + * the key derivation algorithm to use. See the {@code KDF} section + * in the + * Java Security Standard Algorithm Names Specification for + * information about standard KDF algorithm names. + * @param provider + * the provider to use for this key derivation + * + * @return a {@code KDF} object + * + * @throws NoSuchAlgorithmException + * if the specified provider does not support the specified + * {@code KDF} algorithm + * @throws NoSuchProviderException + * if the specified provider is not registered in the security + * provider list + * @throws NullPointerException + * if {@code algorithm} or {@code provider} is {@code null} + */ + public static KDF getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "algorithm must not be null"); + Objects.requireNonNull(provider, "provider must not be null"); + try { + return getInstance(algorithm, null, provider); + } catch (InvalidAlgorithmParameterException e) { + throw new NoSuchAlgorithmException( + "No implementation found using null KDFParameters", e); + } + } + + /** + * Returns a {@code KDF} object that implements the specified algorithm from + * the specified security provider. + * + * @param algorithm + * the key derivation algorithm to use. See the {@code KDF} section + * in the + * Java Security Standard Algorithm Names Specification for + * information about standard KDF algorithm names. + * @param provider + * the provider to use for this key derivation + * + * @return a {@code KDF} object + * + * @throws NoSuchAlgorithmException + * if the specified provider does not support the specified + * {@code KDF} algorithm + * @throws NullPointerException + * if {@code algorithm} or {@code provider} is {@code null} + */ + public static KDF getInstance(String algorithm, Provider provider) + throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "algorithm must not be null"); + Objects.requireNonNull(provider, "provider must not be null"); + try { + return getInstance(algorithm, null, provider); + } catch (InvalidAlgorithmParameterException e) { + throw new NoSuchAlgorithmException( + "No implementation found using null KDFParameters", e); + } + } + + /** + * Returns a {@code KDF} object that implements the specified algorithm and + * is initialized with the specified parameters. + * + * @implNote The JDK Reference Implementation additionally uses the + * {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property to + * determine the preferred provider order for the specified + * algorithm. This may be different than the order of providers + * returned by + * {@link Security#getProviders() Security.getProviders()}. + * + * @param algorithm + * the key derivation algorithm to use. See the {@code KDF} section + * in the + * Java Security Standard Algorithm Names Specification for + * information about standard KDF algorithm names. + * @param kdfParameters + * the {@code KDFParameters} used to configure the derivation + * algorithm or {@code null} if no parameters are provided + * + * @return a {@code KDF} object + * + * @throws NoSuchAlgorithmException + * if no {@code Provider} supports a {@code KDF} implementation for + * the specified algorithm + * @throws InvalidAlgorithmParameterException + * if at least one {@code Provider} supports a {@code KDF} + * implementation for the specified algorithm but none of them + * support the specified parameters + * @throws NullPointerException + * if {@code algorithm} is {@code null} + * @see Delayed Provider + * Selection + */ + public static KDF getInstance(String algorithm, + KDFParameters kdfParameters) + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + Objects.requireNonNull(algorithm, "algorithm must not be null"); + // make sure there is at least one service from a signed provider + Iterator t = GetInstance.getServices("KDF", algorithm); + + Delegate d = getNext(t, kdfParameters); + return (t.hasNext() ? + new KDF(d, t, algorithm, kdfParameters) : + new KDF(d, algorithm)); + } + + /** + * Returns a {@code KDF} object that implements the specified algorithm from + * the specified provider and is initialized with the specified parameters. + * The specified provider must be registered in the security provider list. + * + * @param algorithm + * the key derivation algorithm to use. See the {@code KDF} section + * in the + * Java Security Standard Algorithm Names Specification for + * information about standard KDF algorithm names. + * @param kdfParameters + * the {@code KDFParameters} used to configure the derivation + * algorithm or {@code null} if no parameters are provided + * @param provider + * the provider to use for this key derivation + * + * @return a {@code KDF} object + * + * @throws NoSuchAlgorithmException + * if the specified provider does not support the specified + * {@code KDF} algorithm + * @throws NoSuchProviderException + * if the specified provider is not registered in the security + * provider list + * @throws InvalidAlgorithmParameterException + * if the specified provider supports the specified {@code KDF} + * algorithm but does not support the specified parameters + * @throws NullPointerException + * if {@code algorithm} or {@code provider} is {@code null} + */ + public static KDF getInstance(String algorithm, + KDFParameters kdfParameters, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidAlgorithmParameterException { + Objects.requireNonNull(algorithm, "algorithm must not be null"); + Objects.requireNonNull(provider, "provider must not be null"); + + Instance instance = GetInstance.getInstance("KDF", KDFSpi.class, + algorithm, + kdfParameters, + provider); + if (!JceSecurity.canUseProvider(instance.provider)) { + String msg = "JCE cannot authenticate the provider " + + instance.provider.getName(); + throw new NoSuchProviderException(msg); + } + return new KDF(new Delegate((KDFSpi) instance.impl, + instance.provider), algorithm + ); + } + + /** + * Returns a {@code KDF} object that implements the specified algorithm from + * the specified provider and is initialized with the specified parameters. + * + * @param algorithm + * the key derivation algorithm to use. See the {@code KDF} section + * in the + * Java Security Standard Algorithm Names Specification for + * information about standard KDF algorithm names. + * @param kdfParameters + * the {@code KDFParameters} used to configure the derivation + * algorithm or {@code null} if no parameters are provided + * @param provider + * the provider to use for this key derivation + * + * @return a {@code KDF} object + * + * @throws NoSuchAlgorithmException + * if the specified provider does not support the specified + * {@code KDF} algorithm + * @throws InvalidAlgorithmParameterException + * if the specified provider supports the specified {@code KDF} + * algorithm but does not support the specified parameters + * @throws NullPointerException + * if {@code algorithm} or {@code provider} is {@code null} + */ + public static KDF getInstance(String algorithm, + KDFParameters kdfParameters, + Provider provider) + throws NoSuchAlgorithmException, + InvalidAlgorithmParameterException { + Objects.requireNonNull(algorithm, "algorithm must not be null"); + Objects.requireNonNull(provider, "provider must not be null"); + Instance instance = GetInstance.getInstance("KDF", KDFSpi.class, + algorithm, + kdfParameters, + provider); + if (!JceSecurity.canUseProvider(instance.provider)) { + String msg = "JCE cannot authenticate the provider " + + instance.provider.getName(); + throw new SecurityException(msg); + } + return new KDF(new Delegate((KDFSpi) instance.impl, + instance.provider), algorithm + ); + } + + /** + * Derives a key, returned as a {@code SecretKey} object. + * + * @param alg + * the algorithm of the resultant {@code SecretKey} object + * @param derivationSpec + * the object describing the inputs to the derivation function + * + * @return the derived key + * + * @throws InvalidAlgorithmParameterException + * if the information contained within the {@code derivationSpec} is + * invalid or if the combination of {@code alg} and the + * {@code derivationSpec} results in something invalid + * @throws NoSuchAlgorithmException + * if {@code alg} is empty or invalid + * @throws NullPointerException + * if {@code alg} or {@code derivationSpec} is null + * + * @see Delayed Provider + * Selection + * + */ + public SecretKey deriveKey(String alg, + AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException, + NoSuchAlgorithmException { + if (alg == null) { + throw new NullPointerException( + "the algorithm for the SecretKey return value must not be" + + " null"); + } + if (alg.isEmpty()) { + throw new NoSuchAlgorithmException( + "the algorithm for the SecretKey return value must not be " + + "empty"); + } + Objects.requireNonNull(derivationSpec); + if (checkSpiNonNull(theOne)) { + return theOne.spi().engineDeriveKey(alg, derivationSpec); + } else { + return (SecretKey) chooseProvider(alg, derivationSpec); + } + } + + /** + * Derives a key, returns raw data as a byte array. + * + * @param derivationSpec + * the object describing the inputs to the derivation function + * + * @return the derived key in its raw bytes + * + * @throws InvalidAlgorithmParameterException + * if the information contained within the {@code derivationSpec} is + * invalid + * @throws UnsupportedOperationException + * if the derived keying material is not extractable + * @throws NullPointerException + * if {@code derivationSpec} is null + * + * @see Delayed Provider + * Selection + * + */ + public byte[] deriveData(AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException { + + Objects.requireNonNull(derivationSpec); + if (checkSpiNonNull(theOne)) { + return theOne.spi().engineDeriveData(derivationSpec); + } else { + try { + return (byte[]) chooseProvider(null, derivationSpec); + } catch (NoSuchAlgorithmException e) { + // this will never be thrown in the deriveData case + throw new AssertionError(e); + } + } + } + + /** + * Use the firstSpi as the chosen KDFSpi and set the fields accordingly + */ + private void useFirstSpi() { + if (checkSpiNonNull(theOne)) return; + + synchronized (lock) { + if (!checkSpiNonNull(theOne)) { + theOne = candidate; + } + } + } + + /** + * Selects the provider which supports the passed {@code algorithm} and + * {@code derivationSpec} values, and assigns the global spi and provider + * variables if they have not been assigned yet. + *

+ * If the spi has already been set, it will just return the result. + */ + private Object chooseProvider(String algorithm, + AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException, + NoSuchAlgorithmException { + + boolean isDeriveData = (algorithm == null); + + synchronized (lock) { + if (checkSpiNonNull(theOne)) { + return (isDeriveData) ? + theOne.spi().engineDeriveData(derivationSpec) : + theOne.spi().engineDeriveKey(algorithm, derivationSpec); + } + + Exception lastException = null; + if (!checkSpiNonNull(candidate)) { + throw new AssertionError("Unexpected Error: candidate is null!"); + } + Delegate currOne = candidate; + try { + while (true) { + try { + Object result = (isDeriveData) ? + currOne.spi().engineDeriveData(derivationSpec) : + currOne.spi().engineDeriveKey(algorithm, + derivationSpec); + // found a working KDFSpi + this.theOne = currOne; + return result; + } catch (Exception e) { + if (!skipDebug && pdebug != null) { + pdebug.println("A " + this.getAlgorithm() + + " derivation cannot be performed " + + "using the supplied derivation " + + "inputs, using " + + currOne.provider().getName() + + ". Another Provider will be " + + "attempted."); + e.printStackTrace(pdebug.getPrintStream()); + } + if (lastException == null) { + lastException = e; + } + // try next one if available + assert serviceIterator != null : "serviceIterator was null"; + currOne = getNext(serviceIterator, kdfParameters); + } + } + } catch (InvalidAlgorithmParameterException e) { + throw e; // getNext reached end and have seen IAPE + } catch (NoSuchAlgorithmException e) { + if (!skipDebug && pdebug != null) { + pdebug.println( + "All available Providers have been examined " + + "without a match for performing the " + + this.getAlgorithm() + + " derivation using the supplied derivation " + + "inputs. Therefore, the caught " + + "NoSuchAlgorithmException will be logged, and " + + "an InvalidAlgorithmParameterException will " + + "then be thrown with the last known Exception."); + e.printStackTrace(pdebug.getPrintStream()); + } + // getNext reached end without finding an implementation + throw new InvalidAlgorithmParameterException(lastException); + } + } + } + + private static Delegate getNext(Iterator serviceIter, + KDFParameters kdfParameters) + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + // fetch next one if available + boolean hasOne = false; + while (serviceIter.hasNext()) { + Service s = serviceIter.next(); + Provider prov = s.getProvider(); + if (!JceSecurity.canUseProvider(prov)) { + // continue to next iteration + continue; + } + hasOne = true; + try { + Object obj = s.newInstance(kdfParameters); + if (!(obj instanceof KDFSpi)) { + if (!skipDebug && pdebug != null) { + pdebug.println( + "obj was not an instance of KDFSpi (should not " + + "happen)"); + } + continue; + } + return new Delegate((KDFSpi) obj, prov); + } catch (NoSuchAlgorithmException nsae) { + // continue to the next provider + if (!skipDebug && pdebug != null) { + pdebug.println("A derivation cannot be performed " + + "using the supplied KDFParameters, using " + + prov.getName() + + ". Another Provider will be attempted."); + nsae.printStackTrace(pdebug.getPrintStream()); + } + } + } + if (!skipDebug && pdebug != null) { + pdebug.println( + "No provider can be found that supports the " + + "specified algorithm and parameters"); + } + if (hasOne) throw new InvalidAlgorithmParameterException( + "The KDFParameters supplied could not be used in combination " + + "with the supplied algorithm for the selected Provider"); + else throw new NoSuchAlgorithmException(); + } + + private static boolean checkSpiNonNull(Delegate d) { + // d.spi() cannot be null if d != null + return (d != null); + } +} diff --git a/src/java.base/share/classes/javax/crypto/KDFParameters.java b/src/java.base/share/classes/javax/crypto/KDFParameters.java new file mode 100644 index 00000000000..5f83204f3c4 --- /dev/null +++ b/src/java.base/share/classes/javax/crypto/KDFParameters.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.crypto; + +import jdk.internal.javac.PreviewFeature; + +/** + * A specification of Key Derivation Function ({@link KDF}) parameters. + *

+ * The purpose of this interface is to group (and provide type safety for) all + * {@code KDF} parameter specifications. All {@code KDF} parameter + * specifications must implement this interface. + *

+ * When supplied, the + * {@link KDF#getInstance(String, KDFParameters) KDF.getInstance} methods return + * a {@code KDF} that is initialized with the specified parameters. + *

+ * The {@code KDFParameters} used for initialization are returned by + * {@link KDF#getParameters()} and may contain additional default or random + * parameter values used by the underlying KDF implementation. + * + * @see KDF#getInstance(String, KDFParameters) + * @see KDF#getParameters() + * @see KDF + * @since 24 + */ +@PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) +public interface KDFParameters {} diff --git a/src/java.base/share/classes/javax/crypto/KDFSpi.java b/src/java.base/share/classes/javax/crypto/KDFSpi.java new file mode 100644 index 00000000000..dcd2029c0c0 --- /dev/null +++ b/src/java.base/share/classes/javax/crypto/KDFSpi.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.crypto; + +import jdk.internal.javac.PreviewFeature; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class defines the Service Provider Interface (SPI) for the + * Key Derivation Function ({@link KDF}) class. + *

+ * All the abstract methods in this class must be implemented by each + * cryptographic service provider who wishes to supply the implementation of a + * particular key derivation function algorithm. + *

+ * Implementations must provide a public constructor which accepts a {@code + * KDFParameters} object if they depend on the default implementation of + * {@code Provider.Service.newInstance} to construct {@code KDFSpi} instances. + * The constructor must call {@code super(params)} passing the parameters + * supplied. The constructor must also throw an + * {@code InvalidAlgorithmParameterException} if the supplied parameters are + * inappropriate. If a {@code KDF} object is instantiated with one of the + * {@code getInstance} methods that contains a {@code KDFParameters} parameter, + * the user-provided {@code KDFParameters} object will be passed to the + * constructor of the {@code KDFSpi} implementation. Otherwise, if it is + * instantiated with one of the {@code getInstance} methods without a + * {@code KDFParameters} parameter, a {@code null} value will be passed to the + * constructor. + *

+ * Implementations which do not support {@code KDFParameters} must require + * {@code null} to be passed, otherwise an + * {@code InvalidAlgorithmParameterException} will be thrown. On the other hand, + * implementations which require {@code KDFParameters} should throw an + * {@code InvalidAlgorithmParameterException} upon receiving a {@code null} + * value if default parameters cannot be generated or upon receiving {@code + * KDFParameters} which are not supported by the implementation. + *

+ * To aid the caller, implementations may return parameters with additional + * default values or supply random values as used by the underlying {@code KDF} + * algorithm. See {@link KDFSpi#engineGetParameters()} for more details. + * + * @see KDF + * @see KDFParameters + * @see KDF#getParameters() + * @see SecretKey + * @since 24 + */ +@PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) +public abstract class KDFSpi { + + /** + * The sole constructor. + *

+ * A {@code KDFParameters} object may be specified for KDF algorithms that + * support initialization parameters. + * + * @param kdfParameters + * the initialization parameters for the {@code KDF} algorithm (may + * be {@code null}) + * + * @throws InvalidAlgorithmParameterException + * if the initialization parameters are inappropriate for this + * {@code KDFSpi} + * @see KDF#getParameters() + */ + protected KDFSpi(KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException {} + + /** + * Returns the {@code KDFParameters} used with this {@code KDF} object. + *

+ * The returned parameters may be the same that were used to initialize + * this {@code KDF} object, or may contain additional default or + * random parameter values used by the underlying KDF algorithm. + * If the required parameters were not supplied and can be generated by + * the {@code KDF} object, the generated parameters are returned; + * otherwise {@code null} is returned. + * + * @return the parameters used with this {@code KDF} object, or + * {@code null} + */ + protected abstract KDFParameters engineGetParameters(); + + /** + * Derives a key, returned as a {@code SecretKey} object. + * + * @implNote If the resultant key is extractable, then its + * {@code getEncoded} value should have the same content as the + * result of {@code deriveData}. + * + * @param alg + * the algorithm of the resultant {@code SecretKey} object + * @param derivationSpec + * derivation parameters + * + * @return the derived key. + * + * @throws InvalidAlgorithmParameterException + * if the information contained within the {@code derivationSpec} is + * invalid or if the combination of {@code alg} and the + * {@code derivationSpec} results in something invalid + * @throws NoSuchAlgorithmException + * if {@code alg} is empty or invalid + * @throws NullPointerException + * if {@code alg} or {@code derivationSpec} is null + */ + protected abstract SecretKey engineDeriveKey(String alg, + AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException; + + /** + * Derives a key, returns raw data as a byte array. + * + * @param derivationSpec + * derivation parameters + * + * @return the derived key in its raw bytes. + * + * @throws InvalidAlgorithmParameterException + * if the information contained within the {@code derivationSpec} is + * invalid + * @throws UnsupportedOperationException + * if the derived keying material is not extractable + * @throws NullPointerException + * if {@code derivationSpec} is null + */ + protected abstract byte[] engineDeriveData( + AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException; + +} \ No newline at end of file diff --git a/src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.java new file mode 100644 index 00000000000..8f697d12e60 --- /dev/null +++ b/src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.crypto.spec; + +import jdk.internal.javac.PreviewFeature; + +import javax.crypto.SecretKey; +import java.security.spec.AlgorithmParameterSpec; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Parameters for the combined Extract, Expand, or Extract-then-Expand + * operations of the HMAC-based Key Derivation Function (HKDF). The HKDF + * function is defined in RFC + * 5869. + *

+ * In the Extract and Extract-then-Expand cases, users may call the {@code + * addIKM} and/or {@code addSalt} methods repeatedly (and chain these calls). + * This provides for use-cases where a portion of the input keying material + * (IKM) resides in a non-extractable {@code SecretKey} and the whole IKM + * cannot be provided as a single object. The same feature is available for + * salts. + *

+ * The above feature is particularly useful for "labeled" HKDF Extract used in + * TLS 1.3 and HPKE, where the IKM consists of concatenated components, which + * may include both byte arrays and (possibly non-extractable) secret keys. + *

+ * Examples: + * {@snippet lang = java: + * // this usage depicts the initialization of an HKDF-Extract AlgorithmParameterSpec + * AlgorithmParameterSpec derivationSpec = + * HKDFParameterSpec.ofExtract() + * .addIKM(label) + * .addIKM(ikm) + * .addSalt(salt).extractOnly(); + *} + * {@snippet lang = java: + * // this usage depicts the initialization of an HKDF-Expand AlgorithmParameterSpec + * AlgorithmParameterSpec derivationSpec = + * HKDFParameterSpec.expandOnly(prk, info, 32); + *} + * {@snippet lang = java: + * // this usage depicts the initialization of an HKDF-ExtractExpand AlgorithmParameterSpec + * AlgorithmParameterSpec derivationSpec = + * HKDFParameterSpec.ofExtract() + * .addIKM(ikm) + * .addSalt(salt).thenExpand(info, 32); + *} + * + * @spec https://www.rfc-editor.org/info/rfc5869 + * RFC 5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF) + * @see javax.crypto.KDF + * @since 24 + */ +@PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) +public interface HKDFParameterSpec extends AlgorithmParameterSpec { + + /** + * This {@code Builder} builds {@code Extract} and {@code ExtractThenExpand} + * objects. + *

+ * The {@code Builder} is initialized via the {@code ofExtract} method of + * {@code HKDFParameterSpec}. As stated in the class description, + * {@code addIKM} and/or {@code addSalt} may be called as needed. Finally, + * an object is "built" by calling either {@code extractOnly} or + * {@code thenExpand} for {@code Extract} and {@code ExtractThenExpand} + * use-cases respectively. Note that the {@code Builder} is not + * thread-safe. + */ + @PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) + final class Builder { + + private List ikms = new ArrayList<>(); + private List salts = new ArrayList<>(); + + private Builder() {} + + /** + * Builds an {@code Extract} object from the current state of the + * {@code Builder}. + * + * @return an immutable {@code Extract} object + */ + public Extract extractOnly() { + return new Extract(ikms, salts); + } + + /** + * Builds an {@code ExtractThenExpand} object from the current state of + * the {@code Builder}. + * + * @implNote HKDF implementations will enforce that the length + * is not greater than 255 * HMAC length. HKDF implementations + * will also enforce that a {code null} info value is treated as + * zero-length byte array. + * + * @param info + * the optional context and application specific information + * (may be {@code null}); the byte array is cloned to prevent + * subsequent modification + * @param length + * the length of the output keying material (must be greater + * than 0) + * + * @return an immutable {@code ExtractThenExpand} object + * + * @throws IllegalArgumentException + * if {@code length} is not greater than 0 + */ + public ExtractThenExpand thenExpand(byte[] info, int length) { + return new ExtractThenExpand( + extractOnly(), info, + length); + } + + /** + * Adds input keying material (IKM) to the builder. + *

+ * Users may call {@code addIKM} multiple times when the input keying + * material value is to be assembled piece-meal or if part of the IKM is + * to be supplied by a hardware crypto device. The {@code ikms()} + * method of the {@code Extract} or {@code ExtractThenExpand} object + * that is subsequently built returns the assembled input keying + * material as a list of {@code SecretKey} objects. + * + * @param ikm + * the input keying material (IKM) value + * + * @return this builder + * + * @throws NullPointerException + * if the {@code ikm} argument is null + */ + public Builder addIKM(SecretKey ikm) { + Objects.requireNonNull(ikm, "ikm must not be null"); + ikms.add(ikm); + return this; + } + + /** + * Adds input keying material (IKM) to the builder. Note that an + * {@code ikm} byte array of length zero will be discarded. + *

+ * Users may call {@code addIKM} multiple times when the input keying + * material value is to be assembled piece-meal or if part of the IKM is + * to be supplied by a hardware crypto device. The {@code ikms()} + * method of the {@code Extract} or {@code ExtractThenExpand} object + * that is subsequently built returns the assembled input keying + * material as a list of {@code SecretKey} objects. + * + * @param ikm + * the input keying material (IKM) value; the {@code ikm} + * byte array will be converted to a {@code SecretKeySpec}, + * which means that the byte array will be cloned inside the + * {@code SecretKeySpec} constructor + * + * @return this builder + * + * @throws NullPointerException + * if the {@code ikm} argument is null + */ + public Builder addIKM(byte[] ikm) { + Objects.requireNonNull(ikm, "ikm must not be null"); + if (ikm.length != 0) { + return addIKM(new SecretKeySpec(ikm, "Generic")); + } else { + return this; + } + } + + /** + * Adds a salt to the builder. + *

+ * Users may call {@code addSalt} multiple times when the salt value is + * to be assembled piece-meal or if part of the salt is to be supplied + * by a hardware crypto device. The {@code salts()} method of the + * {@code Extract} or {@code ExtractThenExpand} object that is + * subsequently built returns the assembled salt as a list of + * {@code SecretKey} objects. + * + * @param salt + * the salt value + * + * @return this builder + * + * @throws NullPointerException + * if the {@code salt} is null + */ + public Builder addSalt(SecretKey salt) { + Objects.requireNonNull(salt, "salt must not be null"); + salts.add(salt); + return this; + } + + /** + * Adds a salt to the builder. Note that a {@code salt} byte array of + * length zero will be discarded. + *

+ * Users may call {@code addSalt} multiple times when the salt value is + * to be assembled piece-meal or if part of the salt is to be supplied + * by a hardware crypto device. The {@code salts()} method of the + * {@code Extract} or {@code ExtractThenExpand} object that is + * subsequently built returns the assembled salt as a list of + * {@code SecretKey} objects. + * + * @param salt + * the salt value; the {@code salt} byte array will be + * converted to a {@code SecretKeySpec}, which means that the + * byte array will be cloned inside the {@code SecretKeySpec} + * constructor + * + * @return this builder + * + * @throws NullPointerException + * if the {@code salt} is null + */ + public Builder addSalt(byte[] salt) { + Objects.requireNonNull(salt, "salt must not be null"); + if (salt.length != 0) { + return addSalt(new SecretKeySpec(salt, "Generic")); + } else { + return this; + } + } + } + + /** + * Returns a {@code Builder} for building {@code Extract} and + * {@code ExtractThenExpand} objects. + * + * @return a new {@code Builder} + */ + static Builder ofExtract() { + return new Builder(); + } + + /** + * Creates an {@code Expand} object. + * + * @implNote HKDF implementations will enforce that the length is + * not greater than 255 * HMAC length. Implementations will also + * enforce that the prk argument is at least as many bytes as the + * HMAC length. Implementations will also enforce that a {code null} + * info value is treated as zero-length byte array. + * + * @param prk + * the pseudorandom key (PRK); must not be {@code null} + * @param info + * the optional context and application specific information (may be + * {@code null}); the byte array is cloned to prevent subsequent + * modification + * @param length + * the length of the output keying material (must be greater than + * 0) + * + * @return an {@code Expand} object + * + * @throws NullPointerException + * if the {@code prk} argument is {@code null} + * @throws IllegalArgumentException + * if {@code length} is not greater than 0 + */ + static Expand expandOnly(SecretKey prk, byte[] info, int length) { + if (prk == null) { + throw new NullPointerException("prk must not be null"); + } + return new Expand(prk, info, length); + } + + /** + * Defines the input parameters of an Extract operation as defined in RFC 5869. + */ + @PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) + final class Extract implements HKDFParameterSpec { + + // HKDF-Extract(salt, IKM) -> PRK + private final List ikms; + private final List salts; + + private Extract(List ikms, List salts) { + this.ikms = List.copyOf(ikms); + this.salts = List.copyOf(salts); + } + + /** + * Returns an unmodifiable {@code List} of input keying material values + * in the order they were added. Returns an empty list if there are no + * input keying material values. + *

+ * Input keying material values added by {@link Builder#addIKM(byte[])} + * are converted to a {@code SecretKeySpec} object. Empty arrays are + * discarded. + * + * @implNote An HKDF implementation should concatenate the input + * keying materials into a single value to be used in + * HKDF-Extract. + * + * @return the unmodifiable {@code List} of input keying material + * values + */ + public List ikms() { + return ikms; + } + + /** + * Returns an unmodifiable {@code List} of salt values in the order they + * were added. Returns an empty list if there are no salt values. + *

+ * Salt values added by {@link Builder#addSalt(byte[])} are converted to + * a {@code SecretKeySpec} object. Empty arrays are discarded. + * + * @implNote An HKDF implementation should concatenate the salts + * into a single value to be used in HKDF-Extract. + * + * @return the unmodifiable {@code List} of salt values + */ + public List salts() { + return salts; + } + + } + + /** + * Defines the input parameters of an Expand operation as defined in RFC 5869. + */ + @PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) + final class Expand implements HKDFParameterSpec { + + // HKDF-Expand(PRK, info, L) -> OKM + private final SecretKey prk; + private final byte[] info; + private final int length; + + /** + * Constructor that may be used to initialize an {@code Expand} object + * + * @param prk + * the pseudorandom key (PRK); in the case of + * {@code ExtractThenExpand}, the {@code prk} argument may be + * {@null} since the output of extract phase is used + * @param info + * the optional context and application specific information + * (may be {@code null}); the byte array is cloned to prevent + * subsequent modification + * @param length + * the length of the output keying material + * + * @throws IllegalArgumentException + * if {@code length} not greater than 0 + */ + private Expand(SecretKey prk, byte[] info, int length) { + // a null prk argument could be indicative of ExtractThenExpand + this.prk = prk; + this.info = (info == null) ? null : info.clone(); + if (!(length > 0)) { + throw new IllegalArgumentException("length must be > 0"); + } + this.length = length; + } + + /** + * Returns the pseudorandom key (PRK). + * + * @return the pseudorandom key + */ + public SecretKey prk() { + return prk; + } + + /** + * Returns the optional context and application specific information. + * + * @return a clone of the optional context and application specific + * information, or {@code null} if not specified + */ + public byte[] info() { + return (info == null) ? null : info.clone(); + } + + /** + * Returns the length of the output keying material. + * + * @return the length of the output keying material + */ + public int length() { + return length; + } + + } + + /** + * Defines the input parameters of an Extract-then-Expand operation as + * defined in RFC 5869. + */ + @PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) + final class ExtractThenExpand implements HKDFParameterSpec { + private final Extract ext; + private final Expand exp; + + /** + * Constructor that may be used to initialize an + * {@code ExtractThenExpand} object + * + * @param ext + * a pre-generated {@code Extract} + * @param info + * the optional context and application specific information + * (may be {@code null}); the byte array is cloned to prevent + * subsequent modification + * @param length + * the length of the output keying material + * + * @throws IllegalArgumentException + * if {@code length} is not greater than 0 + */ + private ExtractThenExpand(Extract ext, byte[] info, int length) { + Objects.requireNonNull(ext, "Extract object must not be null"); + this.ext = ext; + // - null prk argument is ok here (it's a signal) + // - {@code Expand} constructor can deal with a null info + // - length is checked in {@code Expand} constructor + this.exp = new Expand(null, info, length); + } + + /** + * Returns an unmodifiable {@code List} of input keying material values + * in the order they were added. Returns an empty list if there are no + * input keying material values. + *

+ * Input keying material values added by {@link Builder#addIKM(byte[])} + * are converted to a {@code SecretKeySpec} object. Empty arrays are + * discarded. + * + * @implNote An HKDF implementation should concatenate the input + * keying materials into a single value to be used in the + * HKDF-Extract phase. + * + * @return the unmodifiable {@code List} of input keying material + * values + */ + public List ikms() { + return ext.ikms(); + } + + /** + * Returns an unmodifiable {@code List} of salt values in the order they + * were added. Returns an empty list if there are no salt values. + *

+ * Salt values added by {@link Builder#addSalt(byte[])} are converted to + * a {@code SecretKeySpec} object. Empty arrays are discarded. + * + * @implNote An HKDF implementation should concatenate the salts + * into a single value to be used in the HKDF-Extract phase. + * + * @return the unmodifiable {@code List} of salt values + * + */ + public List salts() { + return ext.salts(); + } + + /** + * Returns the optional context and application specific information. + * + * @return a clone of the optional context and application specific + * information, or {@code null} if not specified + */ + public byte[] info() { + return exp.info(); + } + + /** + * Returns the length of the output keying material. + * + * @return the length of the output keying material + */ + public int length() { + return exp.length(); + } + + } + +} diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index 6ac3bfd8bce..483093e66eb 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -80,6 +80,8 @@ public enum Feature { STREAM_GATHERERS, @JEP(number=476, title="Module Import Declarations", status="Preview") MODULE_IMPORTS, + @JEP(number=478, title="Key Derivation Function API", status="Preview") + KEY_DERIVATION, LANGUAGE_MODEL, /** * A key for testing. diff --git a/src/java.base/share/classes/sun/security/util/Debug.java b/src/java.base/share/classes/sun/security/util/Debug.java index f1484145f5c..65e121421b8 100644 --- a/src/java.base/share/classes/sun/security/util/Debug.java +++ b/src/java.base/share/classes/sun/security/util/Debug.java @@ -139,7 +139,7 @@ public static void Help() { System.err.println("engine="); System.err.println(" only dump output for the specified list"); System.err.println(" of JCA engines. Supported values:"); - System.err.println(" Cipher, KeyAgreement, KeyGenerator,"); + System.err.println(" Cipher, KDF, KeyAgreement, KeyGenerator,"); System.err.println(" KeyPairGenerator, KeyStore, Mac,"); System.err.println(" MessageDigest, SecureRandom, Signature."); System.err.println(); diff --git a/test/jdk/com/sun/crypto/provider/KDF/HKDFBasicFunctionsTest.java b/test/jdk/com/sun/crypto/provider/KDF/HKDFBasicFunctionsTest.java new file mode 100644 index 00000000000..2697ba57641 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/KDF/HKDFBasicFunctionsTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8331008 + * @summary basic HKDF operations + * @library /test/lib + * @enablePreview + */ + +import java.util.HexFormat; +import javax.crypto.KDF; +import javax.crypto.spec.HKDFParameterSpec; +import jdk.test.lib.Asserts; + +public class HKDFBasicFunctionsTest { + public static void main(String[] args) throws Exception { + var ikm = HexFormat.of().parseHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + var salt = HexFormat.of().parseHex("000102030405060708090a0b0c"); + var info = HexFormat.of().parseHex("f0f1f2f3f4f5f6f7f8f9"); + var len = 42; + + var kdf = KDF.getInstance("HKDF-SHA256"); + var expectedPrk = HexFormat.of().parseHex("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"); + var expectedOkm = HexFormat.of().parseHex("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"); + + var extractOnly = HKDFParameterSpec.ofExtract().addIKM(ikm).addSalt(salt).extractOnly(); + var prk = kdf.deriveKey("PRK", extractOnly); + var expandOnly = HKDFParameterSpec.expandOnly(prk, info, len); + var okm1 = kdf.deriveKey("OKM", expandOnly); + var extractAndExpand = HKDFParameterSpec.ofExtract().addIKM(ikm).addSalt(salt).thenExpand(info, len); + var okm2 = kdf.deriveKey("OKM", extractAndExpand); + + Asserts.assertEqualsByteArray(prk.getEncoded(), expectedPrk, + "the PRK must match the expected value"); + + Asserts.assertEqualsByteArray(okm1.getEncoded(), expectedOkm, + "the OKM must match the expected value " + + "(expand)"); + + Asserts.assertEqualsByteArray(okm2.getEncoded(), expectedOkm, + "the OKM must match the expected value " + + "(extract expand)"); + + // test empty extract + test(HKDFParameterSpec.ofExtract().extractOnly()); + // test expand with empty info + test(HKDFParameterSpec.ofExtract().thenExpand(new byte[0], 32)); + // test expand with null info + test(HKDFParameterSpec.ofExtract().thenExpand(null, 32)); + // test extract with zero-length salt + test(HKDFParameterSpec.ofExtract().addIKM(ikm).addSalt(new byte[0]).extractOnly()); + } + + static void test(HKDFParameterSpec p) throws Exception { + var kdf = KDF.getInstance("HKDF-SHA256"); + System.out.println(HexFormat.of().formatHex(kdf.deriveData(p))); + } +} diff --git a/test/jdk/com/sun/crypto/provider/KDF/HKDFExhaustiveTest.java b/test/jdk/com/sun/crypto/provider/KDF/HKDFExhaustiveTest.java new file mode 100644 index 00000000000..0088fe54a80 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/KDF/HKDFExhaustiveTest.java @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8331008 + * @summary KDF API tests + * @library /test/lib + * @run main/othervm -Djava.security.egd=file:/dev/urandom -Djava.security.debug=provider,engine=kdf HKDFExhaustiveTest + * @enablePreview + */ + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.ArrayList; +import java.util.List; +import javax.crypto.KDF; +import javax.crypto.KDFParameters; +import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class HKDFExhaustiveTest { + + private static final String JDK_HKDF_SHA256 = "HKDF-SHA256"; + private static final String JDK_HKDF_SHA384 = "HKDF-SHA384"; + private static final String JDK_HKDF_SHA512 = "HKDF-SHA512"; + private static final String[] KDF_ALGORITHMS = { + JDK_HKDF_SHA256, JDK_HKDF_SHA384, JDK_HKDF_SHA512 + }; + private static final String SUNJCE = "SunJCE"; + + // SECRET_KEY_SPEC_KEYS and RAW_DATA holds valid values for IKM and SALTS + private static final List SECRET_KEY_SPEC_KEYS = + List.of( + new SecretKeySpec(new byte[] {0}, "HKDF-IKM"), + new SecretKeySpec("IKM".getBytes(), "HKDF-IKM")); + private static final List RAW_DATA = List.of(new byte[] {0}, "RAW".getBytes()); + + private static final byte[] EMPTY = new byte[0]; + private static final int SHORT_LENGTH = 42; + private static final int LARGE_LENGTH = 1000; + private static final int NEGATIVE_LENGTH = -1; + + private static final KdfVerifier KdfGetInstanceVerifier = + (a, p, s) -> { + + // Test KDF getInstance methods, all should have same algo and provider + KDF k1 = KDF.getInstance(a); + KDF k2 = KDF.getInstance(a, p); + KDF k3 = KDF.getInstance(a, Security.getProvider(p)); + Asserts.assertEquals(k1.getAlgorithm(), k2.getAlgorithm()); + Asserts.assertEquals(k2.getAlgorithm(), k3.getAlgorithm()); + Asserts.assertEquals(k1.getProviderName(), k2.getProviderName()); + Asserts.assertEquals(k2.getProviderName(), k3.getProviderName()); + Asserts.assertEquals(k1.getParameters(), k2.getParameters()); + Asserts.assertEquals(k2.getParameters(), k3.getParameters()); + + // Test KDF getInstance methods with parameters + KDFParameters spec = (KDFParameters) s; + k1 = KDF.getInstance(a, spec); + k2 = KDF.getInstance(a, spec, p); + k3 = KDF.getInstance(a, spec, Security.getProvider(p)); + Asserts.assertEquals(k1.getAlgorithm(), k2.getAlgorithm()); + Asserts.assertEquals(k2.getAlgorithm(), k3.getAlgorithm()); + Asserts.assertEquals(k1.getProviderName(), k2.getProviderName()); + Asserts.assertEquals(k2.getProviderName(), k3.getProviderName()); + Asserts.assertEquals(k1.getParameters(), k2.getParameters()); + Asserts.assertEquals(k2.getParameters(), k3.getParameters()); + }; + + private static final KdfExtractVerifier KdfExtractVerifierImpl = + (ikm, salt) -> { + // ofExtract + HKDFParameterSpec.Builder hkdfParameterSpecBuilder = HKDFParameterSpec.ofExtract(); + addIkmAndSalt(hkdfParameterSpecBuilder, ikm, salt); + + // extractOnly - it is possible to have empty key param so skip when length is 0 + HKDFParameterSpec.Extract parameterSpec = hkdfParameterSpecBuilder.extractOnly(); + checkIKMSaltPresence(ikm, salt, parameterSpec); + + return parameterSpec; + }; + + private static final KdfExpandVerifier KdfExpandVerifierImpl = + (prk, info, len) -> { + // Expand + HKDFParameterSpec.Expand parameterSpec = HKDFParameterSpec.expandOnly(prk, info, len); + + Asserts.assertEqualsByteArray(prk.getEncoded(), parameterSpec.prk().getEncoded()); + Asserts.assertEqualsByteArray(info, parameterSpec.info()); + Asserts.assertEquals(len, parameterSpec.length()); + + return parameterSpec; + }; + + private static final KdfExtThenExpVerifier + KdfExtThenExpVerifierImpl = + (ikm, salt, info, len) -> { + // ofExtract + HKDFParameterSpec.Builder hkdfParameterSpecBuilder = HKDFParameterSpec.ofExtract(); + addIkmAndSalt(hkdfParameterSpecBuilder, ikm, salt); + + // thenExpand + HKDFParameterSpec.ExtractThenExpand parameterSpec = + hkdfParameterSpecBuilder.thenExpand(info, len); + checkIKMSaltPresence(ikm, salt, parameterSpec); + + // Validate info and length + Asserts.assertEqualsByteArray(info, parameterSpec.info()); + Asserts.assertEquals(len, parameterSpec.length()); + + return parameterSpec; + }; + private static final DeriveComparator< + KDF, HKDFParameterSpec, HKDFParameterSpec, String, SecretKey, Integer> + deriveComparatorImpl = + (hk, lhs, rhs, t, s, len) -> { + // deriveKey using two passed in HKDFParameterSpec and compare + byte[] skUsingLhs = hk.deriveKey(t, lhs).getEncoded(); + byte[] skUsingRhs = hk.deriveKey(t, rhs).getEncoded(); + + // compare deriveData and keys using same HKDFParameterSpec are equal + Asserts.assertEqualsByteArray(skUsingLhs, skUsingRhs); + Asserts.assertEqualsByteArray(hk.deriveData(lhs), skUsingLhs); + Asserts.assertEqualsByteArray(hk.deriveData(lhs), skUsingRhs); + Asserts.assertEqualsByteArray(hk.deriveData(lhs), hk.deriveData(rhs)); + + // if 'len < 0' then deriveKey()/deriveData() length check is not required + if (len >= 0) { + Asserts.assertEquals(skUsingLhs.length, len); + } + + // Compare with if SecretKey is passed in parameter + if (s != null) { + Asserts.assertEqualsByteArray(skUsingLhs, s.getEncoded()); + } + }; + // Passed in HKDFParameterSpec returned from different methods and algorithms a1, a2. + // Keys and data derived should be equal. + private static final DeriveVerifier + deriveVerifierImpl = + (hk, lhs, rhs, a1, a2) -> { + SecretKey sk1 = hk.deriveKey(a1, lhs); + SecretKey sk2 = hk.deriveKey(a2, rhs); + Asserts.assertEqualsByteArray(sk1.getEncoded(), sk2.getEncoded()); + + byte[] bk1 = hk.deriveData(lhs); + Asserts.assertEqualsByteArray(bk1, sk1.getEncoded()); + }; + + private static void checkIKMSaltPresence( + Object ikm, Object salt, HKDFParameterSpec parameterSpec) { + final List ikms; + final List salts; + if (parameterSpec instanceof HKDFParameterSpec.Extract) { + ikms = ((HKDFParameterSpec.Extract) parameterSpec).ikms(); + salts = ((HKDFParameterSpec.Extract) parameterSpec).salts(); + } else { // must be HKDFParameterSpec.ExtractThenExpand + ikms = ((HKDFParameterSpec.ExtractThenExpand) parameterSpec).ikms(); + salts = ((HKDFParameterSpec.ExtractThenExpand) parameterSpec).salts(); + } + if ((ikm instanceof SecretKey) || ((byte[]) ikm).length != 0) { + Asserts.assertTrue(ikms.contains(getSecretKey(ikm))); + } + + if ((salt instanceof SecretKey) || ((byte[]) salt).length != 0) { + Asserts.assertTrue(salts.contains(getSecretKey(salt))); + } + } + + private static SecretKey getSecretKey(Object data) { + return (data instanceof SecretKey) + ? (SecretKey) data + : new SecretKeySpec((byte[]) data, "Generic"); + } + + private static void addIkmAndSalt( + HKDFParameterSpec.Builder hkdfParameterSpecBuilder, Object ikm, Object salt) { + if (ikm instanceof SecretKey) { + hkdfParameterSpecBuilder.addIKM((SecretKey) ikm); + } else { + hkdfParameterSpecBuilder.addIKM((byte[]) ikm); + } + + if (salt instanceof SecretKey) { + hkdfParameterSpecBuilder.addSalt((SecretKey) salt); + } else { + hkdfParameterSpecBuilder.addSalt((byte[]) salt); + } + } + + public static void main(String[] args) throws Exception { + System.out.println("Starting Test '" + HKDFExhaustiveTest.class.getName() + "'"); + + // Test KDF.getInstance methods + System.out.println("Testing getInstance methods"); + testGetInstanceMethods(); + testGetInstanceNegative(); + + /* Executing following test cases with one supported algorithm is sufficient */ + KDF hk = KDF.getInstance(KDF_ALGORITHMS[0]); + + // Test extract + System.out.println("Testing extract method"); + testExtractMethod(hk); + + System.out.println("Testing deriveKey and deriveData with extract method"); + testDeriveKeyDataWithExtract(hk); + + // Test expand + System.out.println("Testing expand method"); + testExpandMethod(hk); + + System.out.println("Testing deriveKey and deriveData with expand method"); + testDeriveKeyDataWithExpand(hk); + + // Test ExtractThenExpand + System.out.println("Testing extractThenExpand method"); + testExtractExpandMethod(hk); + + System.out.println("Testing deriveKey and deriveData with extExpand method"); + testDeriveKeyDataWithExtExpand(hk); + + System.out.println("Test executed successfully."); + } + + private static void testGetInstanceMethods() + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException { + // POSITIVE TestCase: KDF getInstance methods test + for (String algo : KDF_ALGORITHMS) { + KdfGetInstanceVerifier.test(algo, SUNJCE, null); + } + } + + private static void testGetInstanceNegative() { + final String INVALID_STRING = "INVALID"; + final Provider SUNJCE_PROVIDER = Security.getProvider(SUNJCE); + + // getInstance(String algorithm) + Utils.runAndCheckException(() -> KDF.getInstance(null), NullPointerException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(INVALID_STRING), NoSuchAlgorithmException.class); + + // getInstance(String algorithm, String provider) + Utils.runAndCheckException(() -> KDF.getInstance(null, SUNJCE), NullPointerException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(INVALID_STRING, SUNJCE), NoSuchAlgorithmException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(KDF_ALGORITHMS[0], (String) null), NullPointerException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(KDF_ALGORITHMS[0], INVALID_STRING), NoSuchProviderException.class); + + // getInstance(String algorithm, Provider provider) + Utils.runAndCheckException( + () -> KDF.getInstance(null, SUNJCE_PROVIDER), NullPointerException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(INVALID_STRING, SUNJCE_PROVIDER), NoSuchAlgorithmException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(KDF_ALGORITHMS[0], (Provider) null), NullPointerException.class); + + // getInstance(String algorithm, KDFParameters kdfParameters) + // null spec is a valid case but different class is not + Utils.runAndCheckException( + () -> KDF.getInstance(null, (KDFParameters) null), NullPointerException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(INVALID_STRING, (KDFParameters) null), + NoSuchAlgorithmException.class); + + // getInstance(String algorithm, KDFParameters kdfParameters, String provider) + Utils.runAndCheckException( + () -> KDF.getInstance(null, null, SUNJCE), NullPointerException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(INVALID_STRING, null, SUNJCE), NoSuchAlgorithmException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(KDF_ALGORITHMS[0], null, (String) null), NullPointerException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(KDF_ALGORITHMS[0], null, INVALID_STRING), + NoSuchProviderException.class); + + // getInstance(String algorithm, KDFParameters kdfParameters, Provider provider) + Utils.runAndCheckException( + () -> KDF.getInstance(null, null, SUNJCE_PROVIDER), NullPointerException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(INVALID_STRING, null, SUNJCE_PROVIDER), + NoSuchAlgorithmException.class); + Utils.runAndCheckException( + () -> KDF.getInstance(KDF_ALGORITHMS[0], null, (Provider) null), + NullPointerException.class); + } + + private static void testExtractMethod(KDF hk) + throws InvalidAlgorithmParameterException, + InvalidParameterSpecException, + NoSuchAlgorithmException { + List ikmSaltTestData = new ArrayList<>(); + ikmSaltTestData.add(null); + ikmSaltTestData.add(EMPTY); + ikmSaltTestData.add(RAW_DATA.getFirst()); + ikmSaltTestData.add(SECRET_KEY_SPEC_KEYS.getFirst()); + + for (Object ikm : ikmSaltTestData) { + for (Object salt : ikmSaltTestData) { + // NEGATIVE Testcase: expects NullPointerException + if (ikm == null || salt == null) { + Utils.runAndCheckException( + () -> KdfExtractVerifierImpl.extract(ikm, salt), NullPointerException.class); + } else { + // POSITIVE Testcase: Extract - Empty bytes for IKM/SALT + HKDFParameterSpec ext1 = KdfExtractVerifierImpl.extract(ikm, salt); + HKDFParameterSpec ext2 = KdfExtractVerifierImpl.extract(ikm, salt); + deriveComparatorImpl.deriveAndCompare(hk, ext1, ext2, "PRK", null, NEGATIVE_LENGTH); + } + } + } + } + + private static void testDeriveKeyDataWithExtract(KDF hk) + throws InvalidAlgorithmParameterException, + InvalidParameterSpecException, + NoSuchAlgorithmException { + // POSITIVE TestCase: Extract - Derive keys/data with unknown algorithm name + deriveVerifierImpl.derive( + hk, + KdfExtractVerifierImpl.extract(SECRET_KEY_SPEC_KEYS.getFirst(), RAW_DATA.getFirst()), + KdfExtractVerifierImpl.extract(SECRET_KEY_SPEC_KEYS.getFirst(), RAW_DATA.getFirst()), + "XYZ", + "ABC"); + + // NEGATIVE TestCase: Extract - {null, ""} algo to derive key + Utils.runAndCheckException( + () -> + hk.deriveKey( + null, + KdfExtractVerifierImpl.extract( + SECRET_KEY_SPEC_KEYS.getFirst(), RAW_DATA.getFirst())), + NullPointerException.class); + Utils.runAndCheckException( + () -> + hk.deriveKey( + "", + KdfExtractVerifierImpl.extract( + SECRET_KEY_SPEC_KEYS.getFirst(), RAW_DATA.getFirst())), + NoSuchAlgorithmException.class); + } + + private static void testExpandMethod(KDF hk) + throws InvalidAlgorithmParameterException, + InvalidParameterSpecException, + NoSuchAlgorithmException { + SecretKey prk = + hk.deriveKey( + "PRK", + KdfExtractVerifierImpl.extract(SECRET_KEY_SPEC_KEYS.get(1), RAW_DATA.getFirst())); + + // Test extExp with {null, EMPTY} info and {SHORT_LENGTH, LARGE_LENGTH} length + for (byte[] info : new byte[][] {null, EMPTY}) { + for (int length : new Integer[] {SHORT_LENGTH, LARGE_LENGTH}) { + HKDFParameterSpec exp1 = KdfExpandVerifierImpl.expand(prk, info, length); + HKDFParameterSpec exp2 = KdfExpandVerifierImpl.expand(prk, info, length); + deriveComparatorImpl.deriveAndCompare(hk, exp1, exp2, "OKM", null, length); + } + } + + // NEGATIVE TestCase: Expand - PRK=null + Utils.runAndCheckException( + () -> KdfExpandVerifierImpl.expand(null, RAW_DATA.getFirst(), SHORT_LENGTH), + NullPointerException.class); + + // NEGATIVE TestCase: Expand - Derive keys/data of negative length + Utils.runAndCheckException( + () -> + KdfExpandVerifierImpl.expand( + SECRET_KEY_SPEC_KEYS.getFirst(), RAW_DATA.getFirst(), NEGATIVE_LENGTH), + IllegalArgumentException.class); + + // NEGATIVE TestCase: Expand - PRK value too short + Utils.runAndCheckException( + () -> + hk.deriveKey( + "OKM", + KdfExpandVerifierImpl.expand( + new SecretKeySpec(new byte[] {0x00}, "PRK"), null, 32)), + InvalidAlgorithmParameterException.class); + + // NEGATIVE TestCase: Expand - length greater than 255 > hmacLen + Utils.runAndCheckException( + () -> hk.deriveKey("OKM", KdfExpandVerifierImpl.expand(prk, null, 8162)), + InvalidAlgorithmParameterException.class); + } + + private static void testDeriveKeyDataWithExpand(KDF hk) + throws InvalidAlgorithmParameterException, + NoSuchAlgorithmException, + InvalidParameterSpecException { + SecretKey prk = + hk.deriveKey( + "PRK", + KdfExtractVerifierImpl.extract(SECRET_KEY_SPEC_KEYS.get(1), RAW_DATA.getFirst())); + + // POSITIVE TestCase: Expand - Derive keys/data with unknown algorithm name + deriveVerifierImpl.derive( + hk, + KdfExpandVerifierImpl.expand(prk, RAW_DATA.getFirst(), SHORT_LENGTH), + KdfExpandVerifierImpl.expand(prk, RAW_DATA.getFirst(), SHORT_LENGTH), + "XYZ", + "ABC"); + + // NEGATIVE TestCase: Expand - PRK is not derived + Utils.runAndCheckException( + () -> + hk.deriveKey( + "PRK", + KdfExpandVerifierImpl.expand( + SECRET_KEY_SPEC_KEYS.get(1), RAW_DATA.getFirst(), SHORT_LENGTH)), + InvalidAlgorithmParameterException.class); + } + + private static void testExtractExpandMethod(KDF hk) + throws InvalidAlgorithmParameterException, + InvalidParameterSpecException, + NoSuchAlgorithmException { + // Test extExp with {null, EMPTY} info and {SHORT_LENGTH, LARGE_LENGTH} length + for (byte[] info : new byte[][] {null, EMPTY}) { + for (int length : new Integer[] {SHORT_LENGTH, LARGE_LENGTH}) { + HKDFParameterSpec extractExpand1 = + KdfExtThenExpVerifierImpl.extExp( + RAW_DATA.getFirst(), RAW_DATA.getFirst(), info, length); + HKDFParameterSpec extractExpand2 = + KdfExtThenExpVerifierImpl.extExp( + RAW_DATA.getFirst(), RAW_DATA.getFirst(), info, length); + deriveComparatorImpl.deriveAndCompare( + hk, extractExpand1, extractExpand2, "OKM", null, length); + } + } + + // NEGATIVE TestCases: ExtractExpand + List ikmSaltTestData = new ArrayList<>(); + ikmSaltTestData.add(null); + ikmSaltTestData.add(RAW_DATA.getFirst()); + ikmSaltTestData.add(SECRET_KEY_SPEC_KEYS.getFirst()); + + for (Object ikm : ikmSaltTestData) { + for (Object salt : ikmSaltTestData) { + if (ikm == null || salt == null) { + // ikm and/or salt are null, expect NullPointerException + Utils.runAndCheckException( + () -> KdfExtThenExpVerifierImpl.extExp(ikm, salt, RAW_DATA.getFirst(), SHORT_LENGTH), + NullPointerException.class); + } else { + // ikm and salt are not null, test with negative length + Utils.runAndCheckException( + () -> + KdfExtThenExpVerifierImpl.extExp(ikm, salt, RAW_DATA.getFirst(), NEGATIVE_LENGTH), + IllegalArgumentException.class); + } + } + } + + // NEGATIVE TestCase: ExtractThenExpand - length greater than 255 > hmacLen + Utils.runAndCheckException( + () -> hk.deriveKey("OKM", HKDFParameterSpec.ofExtract().thenExpand(null, 8162)), + InvalidAlgorithmParameterException.class); + } + + private static void testDeriveKeyDataWithExtExpand(KDF hk) + throws InvalidAlgorithmParameterException, + InvalidParameterSpecException, + NoSuchAlgorithmException { + // POSITIVE TestCase: ExtractExpand - Derive keys/data with unknown algorithm names + deriveVerifierImpl.derive( + hk, + KdfExtThenExpVerifierImpl.extExp( + SECRET_KEY_SPEC_KEYS.getFirst(), + RAW_DATA.getFirst(), + RAW_DATA.getFirst(), + SHORT_LENGTH), + KdfExtThenExpVerifierImpl.extExp( + SECRET_KEY_SPEC_KEYS.getFirst(), + RAW_DATA.getFirst(), + RAW_DATA.getFirst(), + SHORT_LENGTH), + "XYZ", + "ABC"); + } + + @FunctionalInterface + private interface KdfVerifier { + void test(A a, P p, S s) + throws NoSuchAlgorithmException, + NoSuchProviderException, + InvalidAlgorithmParameterException; + } + + @FunctionalInterface + private interface KdfExtractVerifier { + HKDFParameterSpec extract(K k, S s); + } + + @FunctionalInterface + private interface KdfExpandVerifier { + HKDFParameterSpec expand(P p, I i, L l); + } + + @FunctionalInterface + private interface KdfExtThenExpVerifier { + HKDFParameterSpec extExp(K k, S s, I i, L l); + } + + @FunctionalInterface + private interface DeriveComparator { + void deriveAndCompare(HK hk, L lh, R rh, T t, S s, LN l) + throws InvalidParameterSpecException, + InvalidAlgorithmParameterException, + NoSuchAlgorithmException; + } + + @FunctionalInterface + private interface DeriveVerifier { + void derive(HK hk, L lh, R rh, A1 a1, A2 a2) + throws InvalidParameterSpecException, + InvalidAlgorithmParameterException, + NoSuchAlgorithmException; + } + + private static class KDFAlgorithmParameterSpec implements AlgorithmParameterSpec { + public KDFAlgorithmParameterSpec() {} + } +} diff --git a/test/jdk/com/sun/crypto/provider/KDF/HKDFKnownAnswerTests.java b/test/jdk/com/sun/crypto/provider/KDF/HKDFKnownAnswerTests.java new file mode 100644 index 00000000000..358ffa794fd --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/KDF/HKDFKnownAnswerTests.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8331008 + * @run main HKDFKnownAnswerTests + * @summary Tests for HKDF Expand and Extract Key Derivation Functions + * @enablePreview + */ + +import javax.crypto.KDF; +import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +public class HKDFKnownAnswerTests { + public static class TestData { + public TestData(String name, String algStr, String ikmStr, + String saltStr, String infoStr, int oLen, + String expPrkStr, + String expOkmStr) { + testName = Objects.requireNonNull(name); + algName = Objects.requireNonNull(algStr); + ikm = HexFormat.of().parseHex(Objects.requireNonNull(ikmStr)); + if ((outLen = oLen) <= 0) { + throw new IllegalArgumentException( + "Output length must be greater than 0"); + } + expectedPRK = HexFormat.of().parseHex(Objects.requireNonNull(expPrkStr)); + expectedOKM = HexFormat.of().parseHex(Objects.requireNonNull(expOkmStr)); + + // Non-mandatory fields - may be null + salt = (saltStr != null) ? HexFormat.of().parseHex(saltStr) : new byte[0]; + info = (infoStr != null) ? HexFormat.of().parseHex(infoStr) : null; + } + + public final String testName; + public final String algName; + public final byte[] ikm; + public final byte[] salt; + public final byte[] info; + public final int outLen; + public final byte[] expectedPRK; + public final byte[] expectedOKM; + } + + public static final List testList = new LinkedList() {{ + add(new TestData("RFC 5869 Test Case 1", "HKDF-SHA256", + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "000102030405060708090a0b0c", + "f0f1f2f3f4f5f6f7f8f9", + 42, + "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5", + "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf" + + "34007208d5b887185865")); + add(new TestData("RFC 5869 Test Case 2", "HKDF-SHA256", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" + + "404142434445464748494a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" + + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef" + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + 82, + "06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244", + "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c" + + "59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71" + + "cc30c58179ec3e87c14c01d5c1f3434f1d87")); + add(new TestData("RFC 5869 Test Case 3", "HKDF-SHA256", + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + new String(new byte[0]), null, 42, + "19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04", + "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d" + + "9d201395faa4b61a96c8")); + }}; + + public static void main(String args[]) throws Exception { + int testsPassed = 0; + + int testNo = 0; + for (TestData test : testList) { + System.out.println("*** Test " + ++testNo + ": " + + test.testName); + if (runVector(test)) { + testsPassed++; + } + } + + System.out.println("Total tests: " + testList.size() + + ", Passed: " + testsPassed + ", Failed: " + + (testList.size() - testsPassed)); + if (testsPassed != testList.size()) { + throw new RuntimeException("One or more tests failed. " + + "Check output for details"); + } + } + + private static boolean runVector(TestData testData) + throws InvalidParameterSpecException, + InvalidAlgorithmParameterException, + NoSuchAlgorithmException { + String kdfName, prfName; + KDF kdfHkdf, kdfExtract, kdfExpand; + boolean result = true; + SecretKey actualPRK; + SecretKey actualOKM; + byte[] deriveData; + + try { + kdfHkdf = KDF.getInstance(testData.algName); + kdfExtract = KDF.getInstance(testData.algName); + kdfExpand = KDF.getInstance(testData.algName); + } catch (NoSuchAlgorithmException nsae) { + InvalidParameterSpecException exc = + new InvalidParameterSpecException(); + exc.initCause(nsae); + throw exc; + } + + // Set up the input keying material + SecretKey ikmKey = new SecretKeySpec(testData.ikm, "HKDF-IKM"); + + // *** HKDF-Extract-only testing + // Create KDFParameterSpec for the Extract-only operation + AlgorithmParameterSpec derivationSpecExtract = + HKDFParameterSpec.ofExtract().addIKM(ikmKey) + .addSalt(testData.salt) + .extractOnly(); + actualPRK = kdfExtract.deriveKey("Generic", derivationSpecExtract); + + // Re-run the KDF to give us raw output data + deriveData = kdfExtract.deriveData(derivationSpecExtract); + + System.out.println("* HKDF-Extract-Only:"); + result &= compareKeyAndData(actualPRK, deriveData, + testData.expectedPRK); + + // *** HKDF Expand-Only testing + // For these tests, we'll use the actualPRK as the input key + // Create KDFParameterSpec for key output and raw byte output + AlgorithmParameterSpec derivationSpecExpand = HKDFParameterSpec.expandOnly( + actualPRK, testData.info, + testData.outLen); + actualOKM = kdfExpand.deriveKey("Generic", derivationSpecExpand); + + // Re-run the KDF to give us raw output data + deriveData = kdfExpand.deriveData(derivationSpecExpand); + + System.out.println("* HKDF-Expand-Only:"); + result &= compareKeyAndData(actualOKM, deriveData, + testData.expectedOKM); + + // *** HKDF Extract-then-Expand testing + // We can reuse the KDFParameterSpec from the Expand-only test + + // Use the KDF to make us a key + AlgorithmParameterSpec derivationSpecExtractExpand = + HKDFParameterSpec.ofExtract().addIKM(ikmKey) + .addSalt(testData.salt) + .thenExpand(testData.info, + testData.outLen); + actualOKM = kdfHkdf.deriveKey("Generic", derivationSpecExtractExpand); + + // Re-run the KDF to give us raw output data + deriveData = kdfHkdf.deriveData(derivationSpecExtractExpand); + + System.out.println("* HKDF-Extract-then-Expand:"); + result &= compareKeyAndData(actualOKM, deriveData, + testData.expectedOKM); + + return result; + } + + /** + * Compare key-based and data-based productions from the KDF against an + * expected output value. + * + * @param outKey + * the KDF output in key form + * @param outData + * the KDF output as raw bytes + * @param expectedOut + * the expected value + * + * @return true if the underlying data for outKey, outData and expectedOut + * are the same. + */ + private static boolean compareKeyAndData(Key outKey, byte[] outData, + byte[] expectedOut) { + boolean result = true; + + if (Arrays.equals(outKey.getEncoded(), expectedOut)) { + System.out.println("\t* Key output: Pass"); + } else { + result = false; + System.out.println("\t* Key output: FAIL"); + System.out.println("Expected:\n" + + dumpHexBytes(expectedOut, 16, "\n", " ")); + System.out.println("Actual:\n" + + dumpHexBytes(outKey.getEncoded(), 16, "\n", + " ")); + System.out.println(); + } + + if (Arrays.equals(outData, expectedOut)) { + System.out.println("\t* Data output: Pass"); + } else { + result = false; + System.out.println("\t* Data output: FAIL"); + System.out.println("Expected:\n" + + dumpHexBytes(expectedOut, 16, "\n", " ")); + System.out.println("Actual:\n" + + dumpHexBytes(outData, 16, "\n", " ")); + System.out.println(); + } + + return result; + } + + /** + * Dump the hex bytes of a buffer into string form. + * + * @param data + * The array of bytes to dump to stdout. + * @param itemsPerLine + * The number of bytes to display per line if the {@code lineDelim} + * character is blank then all bytes will be printed on a single line. + * @param lineDelim + * The delimiter between lines + * @param itemDelim + * The delimiter between bytes + * + * @return The hexdump of the byte array + */ + private static String dumpHexBytes(byte[] data, int itemsPerLine, + String lineDelim, String itemDelim) { + StringBuilder sb = new StringBuilder(); + if (data != null) { + for (int i = 0; i < data.length; i++) { + if (i % itemsPerLine == 0 && i != 0) { + sb.append(lineDelim); + } + sb.append(String.format("%02X", data[i])).append(itemDelim); + } + } + + return sb.toString(); + } +} diff --git a/test/jdk/com/sun/crypto/provider/KDF/HKDFSaltIKMTest.java b/test/jdk/com/sun/crypto/provider/KDF/HKDFSaltIKMTest.java new file mode 100644 index 00000000000..1cd0feab614 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/KDF/HKDFSaltIKMTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8331008 + * @summary addIKM and addSalt consistency checks + * @library /test/lib + * @enablePreview + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.security.SeededSecureRandom; + +import javax.crypto.KDF; +import javax.crypto.spec.HKDFParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.util.Arrays; + +public class HKDFSaltIKMTest { + static String[] NAMES = {"HKDF-SHA256", "HKDF-SHA384", "HKDF-SHA512"}; + public static void main(String[] args) throws Exception { + var r = SeededSecureRandom.one(); + var atlast = 0; + KDF kdf = null; + var alg = ""; + for (var i = 0; i < 1_000_000; i++) { + if (kdf == null || r.nextBoolean()) { + alg = NAMES[r.nextInt(3)]; + kdf = KDF.getInstance(alg); // randomly recreate KDF object + } + var b = HKDFParameterSpec.ofExtract(); + var salts = new ByteArrayOutputStream(); // accumulate salt fragments + var ikms = new ByteArrayOutputStream(); // accumulate ikm fragments + while (r.nextBoolean()) { + if (r.nextBoolean()) { + var ikm = r.nBytes(r.nextInt(10)); + if (r.nextBoolean() && ikm.length > 0) { + b.addIKM(new SecretKeySpec(ikm, "X")); + } else { + b.addIKM(ikm); + } + ikms.writeBytes(ikm); + } else { + var salt = r.nBytes(r.nextInt(10)); + if (r.nextBoolean() && salt.length > 0) { + b.addSalt(new SecretKeySpec(salt, "X")); + } else { + b.addSalt(salt); + } + salts.writeBytes(salt); + } + } + var info = r.nextBoolean() ? null : r.nBytes(r.nextInt(100)); + var l = r.nextInt(200) + 1; + var kdf2 = r.nextBoolean() ? kdf : KDF.getInstance(alg); + var k1 = kdf2.deriveData(HKDFParameterSpec.ofExtract().addIKM(ikms.toByteArray()) + .addSalt(salts.toByteArray()).thenExpand(info, l)); + atlast = Arrays.hashCode(k1) + 17 * atlast; + if (r.nextBoolean()) { + var k2 = kdf.deriveData(b.thenExpand(info, l)); + Asserts.assertEqualsByteArray(k1, k2); + } else { + var prk = kdf.deriveKey("PRK", b.extractOnly()); + var k2 = kdf.deriveData(HKDFParameterSpec.expandOnly(prk, info, l)); + Asserts.assertEqualsByteArray(k1, k2); + } + } + System.out.println(atlast); + } +} \ No newline at end of file diff --git a/test/jdk/javax/crypto/KDF/KDFDelayedProviderSyncTest.java b/test/jdk/javax/crypto/KDF/KDFDelayedProviderSyncTest.java new file mode 100644 index 00000000000..9a9da43b544 --- /dev/null +++ b/test/jdk/javax/crypto/KDF/KDFDelayedProviderSyncTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8331008 + * @library /test/lib + * @run testng KDFDelayedProviderSyncTest + * @summary multi-threading test for KDF + * @enablePreview + */ + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import javax.crypto.KDF; +import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HexFormat; + +public class KDFDelayedProviderSyncTest { + KDF kdfUnderTest; + byte[] ikm = new BigInteger("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + 16).toByteArray(); + byte[] salt = new BigInteger("000102030405060708090a0b0c", + 16).toByteArray(); + byte[] info = new BigInteger("f0f1f2f3f4f5f6f7f8f9", 16).toByteArray(); + AlgorithmParameterSpec derivationSpec = + HKDFParameterSpec.ofExtract().addIKM(ikm).addSalt(salt).thenExpand( + info, 42); + String expectedResult = + "666b33562ebc5e2f041774192e0534efca06f82a5fca17ec8c6ae1b9f5466adba1d77d06480567ddd2d1"; + + @BeforeClass + public void setUp() throws NoSuchAlgorithmException { + kdfUnderTest = KDF.getInstance("HKDF-SHA256"); + } + + @Test(threadPoolSize = 50, invocationCount = 100, timeOut = 150) + public void testDerive() + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { + SecretKey result = kdfUnderTest.deriveKey("Generic", derivationSpec); + assert (HexFormat.of().formatHex(result.getEncoded()).equals( + expectedResult)); + + byte[] resultData = kdfUnderTest.deriveData(derivationSpec); + assert (HexFormat.of().formatHex(resultData).equals(expectedResult)); + } +} diff --git a/test/jdk/javax/crypto/KDF/KDFDelayedProviderTest.java b/test/jdk/javax/crypto/KDF/KDFDelayedProviderTest.java new file mode 100644 index 00000000000..edebae217f2 --- /dev/null +++ b/test/jdk/javax/crypto/KDF/KDFDelayedProviderTest.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8331008 + * @library /test/lib /test/jdk/security/unsignedjce + * @build java.base/javax.crypto.ProviderVerifier + * @run main/othervm KDFDelayedProviderTest + * @summary delayed provider selection + * @enablePreview + */ + +import jdk.test.lib.Asserts; + +import javax.crypto.KDF; +import javax.crypto.KDFSpi; +import javax.crypto.SecretKey; +import java.security.InvalidAlgorithmParameterException; +import javax.crypto.KDFParameters; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Objects; + +public class KDFDelayedProviderTest { + public static void main(String[] args) throws Exception { + Security.addProvider(new Provider1()); + Security.addProvider(new Provider2()); + Security.addProvider(new Provider3()); + KDF kdf; + + kdf = KDF.getInstance("X", new KDFParameters() {}); + kdf.deriveData(new AlgorithmParameterSpec() {}); + Asserts.assertEquals(kdf.getProviderName(), "P1"); + + kdf = KDF.getInstance("X"); + kdf.deriveData(new MyDerivationSpec() {}); + Asserts.assertEquals(kdf.getProviderName(), "P2"); + + kdf = KDF.getInstance("X"); + kdf.deriveData(new AlgorithmParameterSpec() {}); + Asserts.assertEquals(kdf.getProviderName(), "P3"); + + boolean thrown = true; + try { + kdf = KDF.getInstance("Y"); + thrown = false; + } catch(Exception nsae) { + // Expected exception + Asserts.assertTrue(nsae instanceof NoSuchAlgorithmException); + System.out.println("Expected NoSuchAlgorithmException"); + } + Asserts.assertTrue(thrown); + + thrown = true; + try { + kdf = KDF.getInstance("HKDF-SHA256", new MyKDFParameters()); + thrown = false; + } catch (Exception iape) { + // Expected exception + Asserts.assertTrue(iape instanceof InvalidAlgorithmParameterException); + System.out.println("Expected InvalidAlgorithmParameterException"); + } + Asserts.assertTrue(thrown); + + thrown = true; + try { + kdf = KDF.getInstance("HKDF-SHA256"); + kdf.deriveData(new MyDerivationSpec()); + thrown = false; + } catch (Exception iape) { + // Expected exception + Asserts.assertTrue(iape instanceof InvalidAlgorithmParameterException); + System.out.println("Expected InvalidAlgorithmParameterException"); + } + Asserts.assertTrue(thrown); + } + + public static class Provider1 extends Provider { + public Provider1() { + super("P1", "1", "1"); + put("KDF.X", KDF1.class.getName()); + } + } + + // KDF1 requires a params at getInstance() + public static class KDF1 extends KDF0 { + public KDF1(KDFParameters e) throws InvalidAlgorithmParameterException { + super(Objects.requireNonNull(e)); + } + } + + public static class Provider2 extends Provider { + public Provider2() { + super("P2", "1", "1"); + put("KDF.X", KDF2.class.getName()); + } + } + + // KDF2 requires input to be a specific type + public static class KDF2 extends KDF0 { + public KDF2(KDFParameters e) + throws InvalidAlgorithmParameterException { + super(null); + } + + @Override + protected byte[] engineDeriveData( + AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException { + if (derivationSpec instanceof MyDerivationSpec) { + return null; + } else { + throw new InvalidAlgorithmParameterException(); + } + } + } + + public static class Provider3 extends Provider { + public Provider3() { + super("P3", "1", "1"); + put("KDF.X", KDF3.class.getName()); + } + } + + // KDF3 doesn't care about anything + public static class KDF3 extends KDF0 { + public KDF3(KDFParameters e) throws InvalidAlgorithmParameterException { + super(null); + } + } + + public abstract static class KDF0 extends KDFSpi { + public KDF0(KDFParameters a) throws InvalidAlgorithmParameterException { + super(a); + } + + protected SecretKey engineDeriveKey(String alg, + AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException { + return null; + } + + protected byte[] engineDeriveData( + AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException { + return new byte[0]; + } + + protected KDFParameters engineGetParameters(){ + return null; + } + } + + static class MyDerivationSpec implements AlgorithmParameterSpec {} + + static class MyKDFParameters implements KDFParameters {} +} diff --git a/test/jdk/javax/crypto/KDF/KDFDelayedProviderThreadingTest.java b/test/jdk/javax/crypto/KDF/KDFDelayedProviderThreadingTest.java new file mode 100644 index 00000000000..7b91badef95 --- /dev/null +++ b/test/jdk/javax/crypto/KDF/KDFDelayedProviderThreadingTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8331008 + * @library /test/lib /test/jdk/security/unsignedjce + * @build java.base/javax.crypto.ProviderVerifier + * @run main/othervm KDFDelayedProviderThreadingTest + * @summary delayed provider selection threading test + * @enablePreview + */ + +import jdk.test.lib.Asserts; + +import javax.crypto.KDF; +import javax.crypto.KDFParameters; +import javax.crypto.KDFSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.Provider; +import java.security.Security; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; + +public class KDFDelayedProviderThreadingTest { + /// This number of iterations is enough to see a case where the threads + /// arrange themselves such that both `deriveData` attempts cause "ERROR", + /// which is still a passing case. + static final int ITERATIONS = 10000; + static int threadOrderReversalCounter = 0; + static final String ERROR = "ERROR"; + static volatile String out; + static final HKDFParameterSpec input + = HKDFParameterSpec.ofExtract().extractOnly(); + + static String derive(KDF kdf) { + try { + return Arrays.toString(kdf.deriveData(input)); + } catch (Exception e) { + return ERROR; + } + } + + public static void main(String[] args) throws Exception { + Security.insertProviderAt(new P(), 1); + for (int i = 0; i < ITERATIONS; i++) { + test(); + } + + // If the value of threadOrderReversalCounter is consistently zero, + // then this test may need to be adjusted for newer hardware to ensure + // a thorough test. This didn't seem fitting for a check, such as + // `Asserts.assertTrue(threadOrderReversalCounter > 0);`, since we + // may not want to start failing the test right away when running on + // better hardware someday. + System.out.println("Also tested atypical threading condition " + + threadOrderReversalCounter + "/" + ITERATIONS + + " iterations (depends on hardware specs/utilization)."); + } + + static void test() throws Exception { + var k = KDF.getInstance("HKDF-SHA256"); + var t1 = new Thread(() -> out = derive(k)); + var t2 = new Thread(() -> k.getProviderName()); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + String out2 = derive(k); + Asserts.assertEquals(out, out2); + if (out.length() < 10) { // "error" + threadOrderReversalCounter++; + } + } + + public static class P extends Provider { + public P() { + super("ME", "1", "ME"); + put("KDF.HKDF-SHA256", K.class.getName()); + } + } + + public static class K extends KDFSpi { + + public K(KDFParameters p) throws InvalidAlgorithmParameterException { + super(p); + } + + @Override + protected KDFParameters engineGetParameters() { + return null; + } + + @Override + protected SecretKey engineDeriveKey(String alg, + AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException { + throw new InvalidAlgorithmParameterException(); + } + + @Override + protected byte[] engineDeriveData(AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException { + throw new InvalidAlgorithmParameterException(); + } + } +} \ No newline at end of file diff --git a/test/jdk/security/unsignedjce/java.base/javax/crypto/ProviderVerifier.java b/test/jdk/security/unsignedjce/java.base/javax/crypto/ProviderVerifier.java new file mode 100644 index 00000000000..03e3e9904cc --- /dev/null +++ b/test/jdk/security/unsignedjce/java.base/javax/crypto/ProviderVerifier.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.crypto; + +import java.io.IOException; +import java.net.URL; +import java.security.Provider; + +/** + * This class is included here to enable testing of Delayed Provider Selection + * by certain KDF tests. It only stubs out the necessary methods. + * + * @since 24 + */ +final class ProviderVerifier { + + private final CryptoPermissions appPerms = null; + + /** + * Creates a {@code ProviderVerifier} object to verify the given URL. + * + * @param jarURL the JAR file to be verified. + * @param savePerms if {@code true}, save the permissions allowed by the + * exemption mechanism + */ + ProviderVerifier(URL jarURL, boolean savePerms) { + this(jarURL, null, savePerms); + } + + /** + * Creates a {@code ProviderVerifier} object to verify the given URL. + * + * @param jarURL the JAR file to be verified + * @param provider the corresponding provider. + * @param savePerms if {@code true}, save the permissions allowed by the + * exemption mechanism + */ + ProviderVerifier(URL jarURL, Provider provider, boolean savePerms) { + // The URL for the JAR file we want to verify. + } + + /** + * Only a stub is needed for the Delayed Provider Selection test. + */ + void verify() throws IOException { return; } + + /** + * Verify that the provided certs include the + * framework signing certificate. + * + * @param certs the list of certs to be checked. + * @throws Exception if the list of certs did not contain + * the framework signing certificate + */ + static void verifyPolicySigned(java.security.cert.Certificate[] certs) + throws Exception { + } + + /** + * Returns {@code true} if the given provider is JDK trusted crypto provider + * if the implementation supports fast-path verification. + */ + static boolean isTrustedCryptoProvider(Provider provider) { + return false; + } + + /** + * Returns the permissions which are bundled with the JAR file, + * aka the "cryptoperms" file. + *

+ * NOTE: if this {@code ProviderVerifier} instance is constructed + * with "savePerms" equal to {@code false}, then this method would always + * return {@code null}. + */ + CryptoPermissions getPermissions() { + return appPerms; + } +} From d4d9831c9075c1a157d8375e6902bfc6c731389a Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Tue, 5 Nov 2024 21:19:31 +0000 Subject: [PATCH 17/23] 8340454: C2 EA asserts with "previous reducible Phi is no longer reducible before SUT" Reviewed-by: thartmann, kvn --- src/hotspot/share/opto/escape.cpp | 43 +++++++++- src/hotspot/share/opto/escape.hpp | 5 +- ...estReduceAllocationAndNonReduciblePhi.java | 79 +++++++++++++++++++ 3 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndNonReduciblePhi.java diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index e5f6d68ba14..f8a0209d9ad 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -317,7 +317,7 @@ bool ConnectionGraph::compute_escape() { // Propagate NSR (Not Scalar Replaceable) state. if (found_nsr_alloc) { - find_scalar_replaceable_allocs(jobj_worklist); + find_scalar_replaceable_allocs(jobj_worklist, reducible_merges); } // alloc_worklist will be processed in reverse push order. @@ -3051,8 +3051,43 @@ bool ConnectionGraph::has_non_reducible_merge(FieldNode* field, Unique_Node_List return false; } +void ConnectionGraph::revisit_reducible_phi_status(JavaObjectNode* jobj, Unique_Node_List& reducible_merges) { + assert(jobj != nullptr && !jobj->scalar_replaceable(), "jobj should be set as NSR before calling this function."); + + // Look for 'phis' that refer to 'jobj' as the last + // remaining scalar replaceable input. + uint reducible_merges_cnt = reducible_merges.size(); + for (uint i = 0; i < reducible_merges_cnt; i++) { + Node* phi = reducible_merges.at(i); + + // This 'Phi' will be a 'good' if it still points to + // at least one scalar replaceable object. Note that 'obj' + // was/should be marked as NSR before calling this function. + bool good_phi = false; + + for (uint j = 1; j < phi->req(); j++) { + JavaObjectNode* phi_in_obj = unique_java_object(phi->in(j)); + if (phi_in_obj != nullptr && phi_in_obj->scalar_replaceable()) { + good_phi = true; + break; + } + } + + if (!good_phi) { + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Phi %d became non-reducible after node %d became NSR.", phi->_idx, jobj->ideal_node()->_idx);) + reducible_merges.remove(i); + + // Decrement the index because the 'remove' call above actually + // moves the last entry of the list to position 'i'. + i--; + + reducible_merges_cnt--; + } + } +} + // Propagate NSR (Not scalar replaceable) state. -void ConnectionGraph::find_scalar_replaceable_allocs(GrowableArray& jobj_worklist) { +void ConnectionGraph::find_scalar_replaceable_allocs(GrowableArray& jobj_worklist, Unique_Node_List &reducible_merges) { int jobj_length = jobj_worklist.length(); bool found_nsr_alloc = true; while (found_nsr_alloc) { @@ -3071,6 +3106,10 @@ void ConnectionGraph::find_scalar_replaceable_allocs(GrowableArrayscalar_replaceable()) { set_not_scalar_replaceable(jobj NOT_PRODUCT(COMMA "is stored into field with NSR base")); + // Any merge that had only 'jobj' as scalar-replaceable will now be non-reducible, + // because there is no point in reducing a Phi that won't improve the number of SR + // objects. + revisit_reducible_phi_status(jobj, reducible_merges); found_nsr_alloc = true; break; } diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp index 32e70be219a..0b8cd3aa138 100644 --- a/src/hotspot/share/opto/escape.hpp +++ b/src/hotspot/share/opto/escape.hpp @@ -472,8 +472,11 @@ class ConnectionGraph: public ArenaObj { // Adjust scalar_replaceable state after Connection Graph is built. void adjust_scalar_replaceable_state(JavaObjectNode* jobj, Unique_Node_List &reducible_merges); + // Reevaluate Phis reducible status after 'obj' became NSR. + void revisit_reducible_phi_status(JavaObjectNode* jobj, Unique_Node_List& reducible_merges); + // Propagate NSR (Not scalar replaceable) state. - void find_scalar_replaceable_allocs(GrowableArray& jobj_worklist); + void find_scalar_replaceable_allocs(GrowableArray& jobj_worklist, Unique_Node_List &reducible_merges); // Optimize ideal graph. void optimize_ideal_graph(GrowableArray& ptr_cmp_worklist, diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndNonReduciblePhi.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndNonReduciblePhi.java new file mode 100644 index 00000000000..d5593a3af41 --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndNonReduciblePhi.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8340454 + * @summary Check that Reduce Allocation Merges doesn't crash when + * a reducible Phi becomes irreducible after the last of + * its SR inputs is flagged as NSR. + * @run main/othervm -XX:CompileCommand=dontinline,*TestReduceAllocationAndNonReduciblePhi*::test + * -XX:CompileCommand=compileonly,*TestReduceAllocationAndNonReduciblePhi*::test + * -XX:CompileCommand=compileonly,*Picture*::* + * -XX:CompileCommand=compileonly,*Point*::* + * -XX:CompileCommand=inline,*Picture*::* + * -XX:CompileCommand=inline,*Point*::* + * -XX:CompileCommand=exclude,*::dummy* + * -Xbatch + * -server + * compiler.escapeAnalysis.TestReduceAllocationAndNonReduciblePhi + * + * @run main compiler.escapeAnalysis.TestReduceAllocationAndNonReduciblePhi + */ + +package compiler.escapeAnalysis; + +public class TestReduceAllocationAndNonReduciblePhi { + public static void main(String args[]) { + int result = 0; + + for (int i = 0; i < 20000; i++) { + result += test(i % 2 == 0, i % 3); + } + + System.out.println("Result is = " + result); + } + + public static int test(boolean flag1, int pos) { + Point p0 = new Point(); + Point p1 = flag1 ? null : p0; + + Picture pic = new Picture(); + pic.p = p0; + + Picture[] ps = new Picture[5]; + ps[pos] = pic; + + return p1 != null ? dummy1() : dummy2(); + } + + public static int dummy1() { return 1; } + + public static int dummy2() { return 2; } + + private static class Picture { + public Point p; + } + + private static class Point { } +} From 69bc0887741a7dd7eda234f5b3252c3c5e46d87e Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Tue, 5 Nov 2024 21:43:11 +0000 Subject: [PATCH 18/23] 8343071: Broken anchors to restricted method page and some redundant ids 8332747: Broken links in StructuredTaskScope Reviewed-by: mcimadamore, iris --- src/java.base/share/classes/java/lang/Class.java | 2 +- src/java.base/share/classes/java/lang/Module.java | 2 +- .../share/classes/java/lang/foreign/MemorySegment.java | 2 +- .../classes/java/util/concurrent/StructuredTaskScope.java | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 93a675c83a4..2edf0a9169e 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -151,7 +151,7 @@ *

Some methods of class {@code Class} expose whether the declaration of * a class or interface in Java source code was enclosed within * another declaration. Other methods describe how a class or interface - * is situated in a {@index "nest"}. A nest is a set of + * is situated in a {@index "nest"}. A nest is a set of * classes and interfaces, in the same run-time package, that * allow mutual access to their {@code private} members. * The classes and interfaces are known as {@index "nestmates"} diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java index e4cf4a3a6c3..4d4593b3197 100644 --- a/src/java.base/share/classes/java/lang/Module.java +++ b/src/java.base/share/classes/java/lang/Module.java @@ -263,7 +263,7 @@ Module implAddEnableNativeAccess() { /** * Returns {@code true} if this module can access - * restricted methods. + * restricted methods. * * @return {@code true} if this module can access restricted methods. * @since 22 diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 74658a5bbf6..7ecbe2504f3 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -501,7 +501,7 @@ * All the methods that can be used to manipulate zero-length memory segments * ({@link #reinterpret(long)}, {@link #reinterpret(Arena, Consumer)}, {@link #reinterpret(long, Arena, Consumer)} and * {@link AddressLayout#withTargetLayout(MemoryLayout)}) are - * restricted methods, and should + * restricted methods, and should * be used with caution: assigning a segment incorrect spatial and/or temporal bounds * could result in a VM crash when attempting to access the memory segment. * diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java index 94dac686943..17448e9bf3d 100644 --- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java @@ -1007,9 +1007,9 @@ public static final class ShutdownOnSuccess extends StructuredTaskScope { * *

Construction captures the current thread's {@linkplain ScopedValue scoped * value} bindings for inheritance by threads started in the task scope. The - * Tree Structure section in the class description - * details how parent-child relations are established implicitly for the purpose - * of inheritance of scoped value bindings. + * {@linkplain StructuredTaskScope##TreeStructure Tree Structure} section + * in the class description details how parent-child relations are established + * implicitly for the purpose of inheritance of scoped value bindings. * * @param name the name of the task scope, can be null * @param factory the thread factory @@ -1187,7 +1187,7 @@ public static final class ShutdownOnFailure extends StructuredTaskScope * *

Construction captures the current thread's {@linkplain ScopedValue scoped * value} bindings for inheritance by threads started in the task scope. The - * Tree Structure section in the class description + * {@linkplain StructuredTaskScope##TreeStructure Tree Structure} section in the class description * details how parent-child relations are established implicitly for the purpose * of inheritance of scoped value bindings. * From 471f112bca715d04304cbe35c6ed63df8c7b7fee Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Tue, 5 Nov 2024 22:39:00 +0000 Subject: [PATCH 19/23] 8342577: Clean up JVMTI breakpoint support 8210637: Race in JvmtiCurrentBreakpoints::get_jvmti_breakpoints Reviewed-by: cjplummer, sspitsyn --- src/hotspot/share/prims/jvmtiImpl.cpp | 191 +++++------------------- src/hotspot/share/prims/jvmtiImpl.hpp | 202 ++++---------------------- 2 files changed, 68 insertions(+), 325 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiImpl.cpp b/src/hotspot/share/prims/jvmtiImpl.cpp index ac7143e02b8..8ab7f098542 100644 --- a/src/hotspot/share/prims/jvmtiImpl.cpp +++ b/src/hotspot/share/prims/jvmtiImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiImpl.hpp" #include "prims/jvmtiRedefineClasses.hpp" +#include "runtime/atomic.hpp" #include "runtime/continuation.hpp" #include "runtime/deoptimization.hpp" #include "runtime/frame.inline.hpp" @@ -89,103 +90,6 @@ JvmtiAgentThread::call_start_function() { _start_fn(_env->jvmti_external(), jni_environment(), (void*)_start_arg); } - -// -// class GrowableCache - private methods -// - -void GrowableCache::recache() { - int len = _elements->length(); - - FREE_C_HEAP_ARRAY(address, _cache); - _cache = NEW_C_HEAP_ARRAY(address,len+1, mtInternal); - - for (int i=0; iat(i)->getCacheValue(); - // - // The cache entry has gone bad. Without a valid frame pointer - // value, the entry is useless so we simply delete it in product - // mode. The call to remove() will rebuild the cache again - // without the bad entry. - // - if (_cache[i] == nullptr) { - assert(false, "cannot recache null elements"); - remove(i); - return; - } - } - _cache[len] = nullptr; - - _listener_fun(_this_obj,_cache); -} - -// -// class GrowableCache - public methods -// - -GrowableCache::GrowableCache() { - _this_obj = nullptr; - _listener_fun = nullptr; - _elements = nullptr; - _cache = nullptr; -} - -GrowableCache::~GrowableCache() { - clear(); - delete _elements; - FREE_C_HEAP_ARRAY(address, _cache); -} - -void GrowableCache::initialize(void *this_obj, void listener_fun(void *, address*) ) { - _this_obj = this_obj; - _listener_fun = listener_fun; - _elements = new (mtServiceability) GrowableArray(5, mtServiceability); - recache(); -} - -// number of elements in the collection -int GrowableCache::length() { - return _elements->length(); -} - -// get the value of the index element in the collection -GrowableElement* GrowableCache::at(int index) { - GrowableElement *e = (GrowableElement *) _elements->at(index); - assert(e != nullptr, "e != nullptr"); - return e; -} - -int GrowableCache::find(const GrowableElement* e) const { - return _elements->find_if([&](const GrowableElement* other_e) { return e->equals(other_e); }); -} - -// append a copy of the element to the end of the collection -void GrowableCache::append(GrowableElement* e) { - GrowableElement *new_e = e->clone(); - _elements->append(new_e); - recache(); -} - -// remove the element at index -void GrowableCache::remove (int index) { - GrowableElement *e = _elements->at(index); - assert(e != nullptr, "e != nullptr"); - _elements->remove(e); - delete e; - recache(); -} - -// clear out all elements, release all heap space and -// let our listener know that things have changed. -void GrowableCache::clear() { - int len = _elements->length(); - for (int i=0; iat(i); - } - _elements->clear(); - recache(); -} - // // class JvmtiBreakpoint // @@ -194,18 +98,17 @@ JvmtiBreakpoint::JvmtiBreakpoint(Method* m_method, jlocation location) : _method(m_method), _bci((int)location) { assert(_method != nullptr, "No method for breakpoint."); assert(_bci >= 0, "Negative bci for breakpoint."); - oop class_holder_oop = _method->method_holder()->klass_holder(); + oop class_holder_oop = _method->method_holder()->klass_holder(); _class_holder = OopHandle(JvmtiExport::jvmti_oop_storage(), class_holder_oop); } -JvmtiBreakpoint::~JvmtiBreakpoint() { - _class_holder.release(JvmtiExport::jvmti_oop_storage()); +JvmtiBreakpoint::JvmtiBreakpoint(const JvmtiBreakpoint& bp) + : _method(bp._method), _bci(bp._bci) { + _class_holder = OopHandle(JvmtiExport::jvmti_oop_storage(), bp._class_holder.resolve()); } -void JvmtiBreakpoint::copy(JvmtiBreakpoint& bp) { - _method = bp._method; - _bci = bp._bci; - _class_holder = OopHandle(JvmtiExport::jvmti_oop_storage(), bp._class_holder.resolve()); +JvmtiBreakpoint::~JvmtiBreakpoint() { + _class_holder.release(JvmtiExport::jvmti_oop_storage()); } bool JvmtiBreakpoint::equals(const JvmtiBreakpoint& bp) const { @@ -301,8 +204,8 @@ void VM_ChangeBreakpoints::doit() { // a JVMTI internal collection of JvmtiBreakpoint // -JvmtiBreakpoints::JvmtiBreakpoints(void listener_fun(void *,address *)) { - _bps.initialize(this,listener_fun); +JvmtiBreakpoints::JvmtiBreakpoints() + : _elements(5, mtServiceability) { } JvmtiBreakpoints:: ~JvmtiBreakpoints() {} @@ -312,9 +215,9 @@ void JvmtiBreakpoints::print() { LogTarget(Trace, jvmti) log; LogStream log_stream(log); - int n = _bps.length(); - for (int i=0; imethod_holder() == klass) { - bp.clear(); - _bps.remove(i); - // This changed 'i' so we have to start over. - changed = true; - break; - } + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + + // Go backwards because this removes entries that are freed. + for (int i = length() - 1; i >= 0; i--) { + JvmtiBreakpoint& bp = at(i); + if (bp.method()->method_holder() == klass) { + bp.clear(); + remove(i); } } } @@ -395,25 +283,18 @@ void JvmtiBreakpoints::clearall_in_class_at_safepoint(Klass* klass) { // JvmtiBreakpoints *JvmtiCurrentBreakpoints::_jvmti_breakpoints = nullptr; -address * JvmtiCurrentBreakpoints::_breakpoint_list = nullptr; - JvmtiBreakpoints& JvmtiCurrentBreakpoints::get_jvmti_breakpoints() { - if (_jvmti_breakpoints != nullptr) return (*_jvmti_breakpoints); - _jvmti_breakpoints = new JvmtiBreakpoints(listener_fun); - assert(_jvmti_breakpoints != nullptr, "_jvmti_breakpoints != nullptr"); + if (_jvmti_breakpoints == nullptr) { + JvmtiBreakpoints* breakpoints = new JvmtiBreakpoints(); + if (!Atomic::replace_if_null(&_jvmti_breakpoints, breakpoints)) { + // already created concurently + delete breakpoints; + } + } return (*_jvmti_breakpoints); } -void JvmtiCurrentBreakpoints::listener_fun(void *this_obj, address *cache) { - JvmtiBreakpoints *this_jvmti = (JvmtiBreakpoints *) this_obj; - assert(this_jvmti != nullptr, "this_jvmti != nullptr"); - - debug_only(int n = this_jvmti->length();); - assert(cache[n] == nullptr, "cache must be null terminated"); - - set_breakpoint_list(cache); -} /////////////////////////////////////////////////////////////// // diff --git a/src/hotspot/share/prims/jvmtiImpl.hpp b/src/hotspot/share/prims/jvmtiImpl.hpp index 5977e000621..3a103cc8237 100644 --- a/src/hotspot/share/prims/jvmtiImpl.hpp +++ b/src/hotspot/share/prims/jvmtiImpl.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,240 +36,102 @@ #include "runtime/vmOperations.hpp" #include "utilities/ostream.hpp" -// -// Forward Declarations -// - -class JvmtiBreakpoint; -class JvmtiBreakpoints; - - -/////////////////////////////////////////////////////////////// -// -// class GrowableCache, GrowableElement -// Used by : JvmtiBreakpointCache -// Used by JVMTI methods: none directly. -// -// GrowableCache is a permanent CHeap growable array of -// -// In addition, the GrowableCache maintains a null terminated cache array of type address -// that's created from the element array using the function: -// address GrowableElement::getCacheValue(). -// -// Whenever the GrowableArray changes size, the cache array gets recomputed into a new C_HEAP allocated -// block of memory. Additionally, every time the cache changes its position in memory, the -// void (*_listener_fun)(void *this_obj, address* cache) -// gets called with the cache's new address. This gives the user of the GrowableCache a callback -// to update its pointer to the address cache. -// - -class GrowableElement : public CHeapObj { -public: - virtual ~GrowableElement() {} - virtual address getCacheValue() =0; - virtual bool equals(const GrowableElement* e) const =0; - virtual GrowableElement* clone() =0; -}; - -class GrowableCache { - -private: - // Object pointer passed into cache & listener functions. - void *_this_obj; - - // Array of elements in the collection - GrowableArray *_elements; - - // Parallel array of cached values - address *_cache; - - // Listener for changes to the _cache field. - // Called whenever the _cache field has it's value changed - // (but NOT when cached elements are recomputed). - void (*_listener_fun)(void *, address*); - - // recache all elements after size change, notify listener - void recache(); - -public: - GrowableCache(); - ~GrowableCache(); - - void initialize(void *this_obj, void listener_fun(void *, address*) ); - - // number of elements in the collection - int length(); - // get the value of the index element in the collection - GrowableElement* at(int index); - // find the index of the element, -1 if it doesn't exist - int find(const GrowableElement* e) const; - // append a copy of the element to the end of the collection, notify listener - void append(GrowableElement* e); - // remove the element at index, notify listener - void remove (int index); - // clear out all elements and release all heap space, notify listener - void clear(); -}; - - -/////////////////////////////////////////////////////////////// -// -// class JvmtiBreakpointCache -// Used by : JvmtiBreakpoints -// Used by JVMTI methods: none directly. -// Note : typesafe wrapper for GrowableCache of JvmtiBreakpoint -// - -class JvmtiBreakpointCache : public CHeapObj { - -private: - GrowableCache _cache; - -public: - JvmtiBreakpointCache() {} - ~JvmtiBreakpointCache() {} - - void initialize(void *this_obj, void listener_fun(void *, address*) ) { - _cache.initialize(this_obj, listener_fun); - } - - int length() { return _cache.length(); } - JvmtiBreakpoint& at(int index) { return (JvmtiBreakpoint&) *(_cache.at(index)); } - int find(JvmtiBreakpoint& e) { return _cache.find((GrowableElement *) &e); } - void append(JvmtiBreakpoint& e) { _cache.append((GrowableElement *) &e); } - void remove (int index) { _cache.remove(index); } -}; - /////////////////////////////////////////////////////////////// // // class JvmtiBreakpoint -// Used by : JvmtiBreakpoints -// Used by JVMTI methods: SetBreakpoint, ClearBreakpoint, ClearAllBreakpoints -// Note: Extends GrowableElement for use in a GrowableCache // // A JvmtiBreakpoint describes a location (class, method, bci) to break at. // typedef void (Method::*method_action)(int _bci); -class JvmtiBreakpoint : public GrowableElement { +class JvmtiBreakpoint : public CHeapObj { private: Method* _method; int _bci; OopHandle _class_holder; // keeps _method memory from being deallocated public: - JvmtiBreakpoint() : _method(nullptr), _bci(0) {} JvmtiBreakpoint(Method* m_method, jlocation location); + JvmtiBreakpoint(const JvmtiBreakpoint& bp); virtual ~JvmtiBreakpoint(); bool equals(const JvmtiBreakpoint& bp) const; - void copy(JvmtiBreakpoint& bp); address getBcp() const; void each_method_version_do(method_action meth_act); void set(); void clear(); void print_on(outputStream* out) const; - Method* method() { return _method; } - - // GrowableElement implementation - address getCacheValue() { return getBcp(); } - bool equals(const GrowableElement* e) const { return equals((const JvmtiBreakpoint&) *e); } - - GrowableElement *clone() { - JvmtiBreakpoint *bp = new JvmtiBreakpoint(); - bp->copy(*this); - return bp; - } + Method* method() const { return _method; } }; - /////////////////////////////////////////////////////////////// // // class JvmtiBreakpoints -// Used by : JvmtiCurrentBreakpoints -// Used by JVMTI methods: none directly -// Note: A Helper class -// -// JvmtiBreakpoints is a GrowableCache of JvmtiBreakpoint. -// All changes to the GrowableCache occur at a safepoint using VM_ChangeBreakpoints. -// -// Because _bps is only modified at safepoints, its possible to always use the -// cached byte code pointers from _bps without doing any synchronization (see JvmtiCurrentBreakpoints). // -// It would be possible to make JvmtiBreakpoints a static class, but I've made it -// CHeap allocated to emphasize its similarity to JvmtiFramePops. +// Contains growable array of JvmtiBreakpoint. +// All changes to the array occur at a safepoint. // class JvmtiBreakpoints : public CHeapObj { private: + GrowableArray _elements; - JvmtiBreakpointCache _bps; + int length() { return _elements.length(); } + JvmtiBreakpoint& at(int index) { return *_elements.at(index); } + int find(JvmtiBreakpoint& e) { + return _elements.find_if([&](const JvmtiBreakpoint * other_e) { return e.equals(*other_e); }); + } + void append(JvmtiBreakpoint& e) { + JvmtiBreakpoint* new_e = new JvmtiBreakpoint(e); + _elements.append(new_e); + } + void remove(int index) { + JvmtiBreakpoint* e = _elements.at(index); + assert(e != nullptr, "e != nullptr"); + _elements.remove_at(index); + delete e; + } - // These should only be used by VM_ChangeBreakpoints - // to insure they only occur at safepoints. - // Todo: add checks for safepoint - friend class VM_ChangeBreakpoints; - void set_at_safepoint(JvmtiBreakpoint& bp); - void clear_at_safepoint(JvmtiBreakpoint& bp); + friend class JvmtiCurrentBreakpoints; + JvmtiBreakpoints(); // accessible only for JvmtiCurrentBreakpoints public: - JvmtiBreakpoints(void listener_fun(void *, address *)); ~JvmtiBreakpoints(); - int length(); void print(); int set(JvmtiBreakpoint& bp); int clear(JvmtiBreakpoint& bp); + + // used by VM_ChangeBreakpoints + void set_at_safepoint(JvmtiBreakpoint& bp); + void clear_at_safepoint(JvmtiBreakpoint& bp); + // used by VM_RedefineClasses void clearall_in_class_at_safepoint(Klass* klass); }; - /////////////////////////////////////////////////////////////// // // class JvmtiCurrentBreakpoints // -// A static wrapper class for the JvmtiBreakpoints that provides: -// 1. a fast inlined function to check if a byte code pointer is a breakpoint (is_breakpoint). -// 2. a function for lazily creating the JvmtiBreakpoints class (this is not strictly necessary, -// but I'm copying the code from JvmtiThreadState which needs to lazily initialize -// JvmtiFramePops). -// 3. An oops_do entry point for GC'ing the breakpoint array. +// A static wrapper class for the JvmtiBreakpoints that provides +// a function for lazily creating the JvmtiBreakpoints class. // class JvmtiCurrentBreakpoints : public AllStatic { - private: - // Current breakpoints, lazily initialized by get_jvmti_breakpoints(); static JvmtiBreakpoints *_jvmti_breakpoints; - // null terminated cache of byte-code pointers corresponding to current breakpoints. - // Updated only at safepoints (with listener_fun) when the cache is moved. - // It exists only to make is_breakpoint fast. - static address *_breakpoint_list; - static inline void set_breakpoint_list(address *breakpoint_list) { _breakpoint_list = breakpoint_list; } - - // Listener for the GrowableCache in _jvmti_breakpoints, updates _breakpoint_list. - static void listener_fun(void *this_obj, address *cache); - public: - static void initialize(); - static void destroy(); - - // lazily create _jvmti_breakpoints and _breakpoint_list + // lazily create _jvmti_breakpoints static JvmtiBreakpoints& get_jvmti_breakpoints(); }; /////////////////////////////////////////////////////////////// // -// class VM_ChangeBreakpoints -// Used by : JvmtiBreakpoints -// Used by JVMTI methods: none directly. -// Note: A Helper class. -// // VM_ChangeBreakpoints implements a VM_Operation for ALL modifications to the JvmtiBreakpoints class. // From 1b0281dc77f41fc5df323c7f7b25a4138b1ffb9e Mon Sep 17 00:00:00 2001 From: KIRIYAMA Takuya Date: Wed, 6 Nov 2024 05:38:46 +0000 Subject: [PATCH 20/23] 8333427: langtools/tools/javac/newlines/NewLineTest.java is failing on Japanese Windows Reviewed-by: jjg --- test/langtools/tools/javac/newlines/NewLineTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/langtools/tools/javac/newlines/NewLineTest.java b/test/langtools/tools/javac/newlines/NewLineTest.java index b1567d363b0..35c60e59653 100644 --- a/test/langtools/tools/javac/newlines/NewLineTest.java +++ b/test/langtools/tools/javac/newlines/NewLineTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,8 +58,9 @@ public static void main(String args[]) throws Exception { .options("-J-Dline.separator='@'") .run(Task.Expect.FAIL); - List lines = Files.readAllLines(javacOutput.toPath(), - Charset.defaultCharset()); + String encoding = System.getProperty("native.encoding"); + Charset cs = (encoding != null) ? Charset.forName(encoding) : Charset.defaultCharset(); + List lines = Files.readAllLines(javacOutput.toPath(), cs); if (lines.size() != 1) { throw new AssertionError("The compiler output should have one line only"); } From 4431852a880b06241231d346311170331c20ab2d Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 6 Nov 2024 06:10:01 +0000 Subject: [PATCH 21/23] 8342943: Replace predicate walking and cloning code for main/post loops with a predicate visitor Reviewed-by: roland, kvn --- src/hotspot/share/opto/loopPredicate.cpp | 1 - src/hotspot/share/opto/loopTransform.cpp | 200 +++++------------------ src/hotspot/share/opto/loopnode.hpp | 25 +-- src/hotspot/share/opto/predicates.cpp | 36 +++- src/hotspot/share/opto/predicates.hpp | 30 +++- 5 files changed, 111 insertions(+), 181 deletions(-) diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index d1de9c98101..9a639b1f9a1 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -24,7 +24,6 @@ #include "precompiled.hpp" #include "memory/allocation.hpp" -#include "opto/loopnode.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/castnode.hpp" diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index f5a7ffcf92a..0ad60c80c2d 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -762,7 +762,7 @@ void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) { // Step 1: Clone the loop body. The clone becomes the peeled iteration. // The pre-loop illegally has 2 control users (old & new loops). - const uint first_node_index_in_cloned_loop_body = Compile::current()->unique(); + const uint first_node_index_in_post_loop_body = Compile::current()->unique(); LoopNode* outer_loop_head = head->skip_strip_mined(); clone_loop(loop, old_new, dom_depth(outer_loop_head), ControlAroundStripMined); @@ -816,7 +816,7 @@ void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) { // Step 5: Assertion Predicates initialization if (counted_loop && UseLoopPredicate) { initialize_assertion_predicates_for_peeled_loop(new_head->as_CountedLoop(), head->as_CountedLoop(), - first_node_index_in_cloned_loop_body, old_new); + first_node_index_in_post_loop_body, old_new); } // Now force out all loop-invariant dominating tests. The optimizer @@ -1313,83 +1313,6 @@ void PhaseIdealLoop::ensure_zero_trip_guard_proj(Node* node, bool is_main_loop) } #endif -// Make two copies of each Template Assertion Predicate before the pre-loop and add them to the main-loop. One remains -// a template while the other one is initialized with the initial value of the loop induction variable. The Initialized -// Assertion Predicates ensures that the main-loop is removed if some type ranges of Cast or Convert nodes become -// impossible and are replaced by top (i.e. a sign that the main-loop is dead). -void PhaseIdealLoop::copy_assertion_predicates_to_main_loop_helper(const PredicateBlock* predicate_block, Node* init, - Node* stride, IdealLoopTree* outer_loop, - LoopNode* outer_main_head, const uint dd_main_head, - const uint idx_before_pre_post, - const uint idx_after_post_before_pre, - Node* zero_trip_guard_proj_main, - Node* zero_trip_guard_proj_post, - const Node_List &old_new) { - if (predicate_block->has_parse_predicate()) { -#ifdef ASSERT - ensure_zero_trip_guard_proj(zero_trip_guard_proj_main, true); - ensure_zero_trip_guard_proj(zero_trip_guard_proj_post, false); -#endif - Node* predicate_proj = predicate_block->parse_predicate_success_proj(); - IfNode* iff = predicate_proj->in(0)->as_If(); - ProjNode* uncommon_proj = iff->proj_out(1 - predicate_proj->as_Proj()->_con); - Node* rgn = uncommon_proj->unique_ctrl_out(); - assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); - predicate_proj = iff->in(0); - Node* current_proj = outer_main_head->in(LoopNode::EntryControl); - Node* prev_proj = current_proj; - Node* opaque_init = new OpaqueLoopInitNode(C, init); - register_new_node(opaque_init, outer_main_head->in(LoopNode::EntryControl)); - Node* opaque_stride = new OpaqueLoopStrideNode(C, stride); - register_new_node(opaque_stride, outer_main_head->in(LoopNode::EntryControl)); - - while (predicate_proj != nullptr && predicate_proj->is_Proj() && predicate_proj->in(0)->is_If()) { - iff = predicate_proj->in(0)->as_If(); - uncommon_proj = iff->proj_out(1 - predicate_proj->as_Proj()->_con); - if (uncommon_proj->unique_ctrl_out() != rgn) - break; - Node* bol = iff->in(1); - assert(!bol->is_OpaqueInitializedAssertionPredicate(), "should not find an Initialized Assertion Predicate"); - if (bol->is_OpaqueTemplateAssertionPredicate()) { - // Clone the Assertion Predicate twice and initialize one with the initial - // value of the loop induction variable. Leave the other predicate - // to be initialized when increasing the stride during loop unrolling. - prev_proj = clone_template_assertion_predicate(iff, opaque_init, predicate_proj, uncommon_proj, - current_proj, outer_loop, prev_proj); - prev_proj = create_initialized_assertion_predicate(iff, init, stride, prev_proj); - - // Rewire any control inputs from the cloned Assertion Predicates down to the main and post loop for data nodes - // that are part of the main loop (and were cloned to the pre and post loop). - for (DUIterator i = predicate_proj->outs(); predicate_proj->has_out(i); i++) { - Node* loop_node = predicate_proj->out(i); - Node* pre_loop_node = old_new[loop_node->_idx]; - // Change the control if 'loop_node' is part of the main loop. If there is an old->new mapping and the index of - // 'pre_loop_node' is greater than idx_before_pre_post, then we know that 'loop_node' was cloned and is part of - // the main loop (and 'pre_loop_node' is part of the pre loop). - if (!loop_node->is_CFG() && (pre_loop_node != nullptr && pre_loop_node->_idx > idx_after_post_before_pre)) { - // 'loop_node' is a data node and part of the main loop. Rewire the control to the projection of the zero-trip guard if node - // of the main loop that is immediately preceding the cloned predicates. - _igvn.replace_input_of(loop_node, 0, zero_trip_guard_proj_main); - --i; - } else if (loop_node->_idx > idx_before_pre_post && loop_node->_idx < idx_after_post_before_pre) { - // 'loop_node' is a data node and part of the post loop. Rewire the control to the projection of the zero-trip guard if node - // of the post loop that is immediately preceding the post loop header node (there are no cloned predicates for the post loop). - assert(pre_loop_node == nullptr, "a node belonging to the post loop should not have an old_new mapping at this stage"); - _igvn.replace_input_of(loop_node, 0, zero_trip_guard_proj_post); - --i; - } - } - - // Remove the Assertion Predicate from the pre-loop - _igvn.replace_input_of(iff, 1, _igvn.intcon(1)); - } - predicate_proj = predicate_proj->in(0)->in(0); - } - _igvn.replace_input_of(outer_main_head, LoopNode::EntryControl, prev_proj); - set_idom(outer_main_head, prev_proj, dd_main_head); - } -} - #ifdef ASSERT bool PhaseIdealLoop::assertion_predicate_has_loop_opaque_node(IfNode* iff) { uint init; @@ -1464,47 +1387,6 @@ IfTrueNode* PhaseIdealLoop::create_initialized_assertion_predicate(IfNode* templ return success_proj; } -// Clone the Template Assertion Predicate and set a new OpaqueLoopInitNode to create a new Template Assertion Predicate. -// This is done when creating a new Template Assertion Predicate for the main loop which requires a new init node. -// We keep the OpaqueTemplateAssertionPredicate node since it's still a template. Since the templates are eventually -// removed after loop opts, these are never executed. We therefore insert a Halt node instead of an uncommon trap. -Node* PhaseIdealLoop::clone_template_assertion_predicate(IfNode* iff, Node* new_init, Node* predicate, Node* uncommon_proj, - Node* control, IdealLoopTree* outer_loop, Node* new_control) { - assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes for Template Assertion Predicate"); - TemplateAssertionExpression template_assertion_expression(iff->in(1)->as_OpaqueTemplateAssertionPredicate()); - assert(new_init->is_OpaqueLoopInit(), "only for creating new Template Assertion Predicates"); - OpaqueTemplateAssertionPredicateNode* new_opaque_node = - template_assertion_expression.clone_and_replace_init(new_init, control, this); - AssertionPredicateIfCreator assertion_predicate_if_creator(this); - IfTrueNode* success_proj = - assertion_predicate_if_creator.create_for_template(new_control, iff->Opcode(), new_opaque_node - NOT_PRODUCT(COMMA iff->assertion_predicate_type())); - assert(assertion_predicate_has_loop_opaque_node(success_proj->in(0)->as_If()), - "Template Assertion Predicates must have OpaqueLoop* nodes in the bool expression"); - return success_proj; -} - -void PhaseIdealLoop::copy_assertion_predicates_to_main_loop(CountedLoopNode* pre_head, Node* init, Node* stride, - IdealLoopTree* outer_loop, LoopNode* outer_main_head, - const uint dd_main_head, const uint idx_before_pre_post, - const uint idx_after_post_before_pre, - Node* zero_trip_guard_proj_main, - Node* zero_trip_guard_proj_post, - const Node_List &old_new) { - if (UseLoopPredicate) { - Node* entry = pre_head->in(LoopNode::EntryControl); - const Predicates predicates(entry); - copy_assertion_predicates_to_main_loop_helper(predicates.loop_predicate_block(), init, stride, outer_loop, - outer_main_head, dd_main_head, idx_before_pre_post, - idx_after_post_before_pre, zero_trip_guard_proj_main, - zero_trip_guard_proj_post, old_new); - copy_assertion_predicates_to_main_loop_helper(predicates.profiled_loop_predicate_block(), init, stride, - outer_loop, outer_main_head, dd_main_head, idx_before_pre_post, - idx_after_post_before_pre, zero_trip_guard_proj_main, - zero_trip_guard_proj_post, old_new); - } -} - //------------------------------insert_pre_post_loops-------------------------- // Insert pre and post loops. If peel_only is set, the pre-loop can not have // more iterations added. It acts as a 'peel' only, no lower-bound RCE, no @@ -1553,11 +1435,9 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n } // Add the post loop - const uint idx_before_pre_post = Compile::current()->unique(); CountedLoopNode *post_head = nullptr; Node* post_incr = incr; Node* main_exit = insert_post_loop(loop, old_new, main_head, main_end, post_incr, limit, post_head); - const uint idx_after_post_before_pre = Compile::current()->unique(); //------------------------------ // Step B: Create Pre-Loop. @@ -1572,6 +1452,8 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n outer_loop = loop->_parent; assert(outer_loop->_head == outer_main_head, "broken loop tree"); } + + const uint first_node_index_in_pre_loop_body = Compile::current()->unique(); uint dd_main_head = dom_depth(outer_main_head); clone_loop(loop, old_new, dd_main_head, ControlAroundStripMined); CountedLoopNode* pre_head = old_new[main_head->_idx]->as_CountedLoop(); @@ -1650,10 +1532,10 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n // dependencies. assert(post_head->in(1)->is_IfProj(), "must be zero-trip guard If node projection of the post loop"); - copy_assertion_predicates_to_main_loop(pre_head, pre_incr, stride, outer_loop, outer_main_head, dd_main_head, - idx_before_pre_post, idx_after_post_before_pre, min_taken, post_head->in(1), - old_new); - copy_assertion_predicates_to_post_loop(outer_main_head, post_head, stride); + DEBUG_ONLY(ensure_zero_trip_guard_proj(outer_main_head->in(LoopNode::EntryControl), true);) + if (UseLoopPredicate) { + initialize_assertion_predicates_for_main_loop(pre_head, main_head, first_node_index_in_pre_loop_body, old_new); + } // Step B4: Shorten the pre-loop to run only 1 iteration (for now). // RCE and alignment may change this later. @@ -1778,7 +1660,6 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old // In this case we throw away the result as we are not using it to connect anything else. CountedLoopNode *post_head = nullptr; insert_post_loop(loop, old_new, main_head, main_end, incr, limit, post_head); - copy_assertion_predicates_to_post_loop(main_head->skip_strip_mined(), post_head, main_head->stride()); // It's difficult to be precise about the trip-counts // for post loops. They are usually very short, @@ -1813,6 +1694,7 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, // Step A1: Clone the loop body of main. The clone becomes the post-loop. // The main loop pre-header illegally has 2 control users (old & new loops). + const uint first_node_index_in_cloned_loop_body = C->unique(); clone_loop(loop, old_new, dd_main_exit, ControlAroundStripMined); assert(old_new[main_end->_idx]->Opcode() == Op_CountedLoopEnd, ""); post_head = old_new[main_head->_idx]->as_CountedLoop(); @@ -1881,6 +1763,10 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, } } + DEBUG_ONLY(ensure_zero_trip_guard_proj(post_head->in(LoopNode::EntryControl), false);) + if (UseLoopPredicate) { + initialize_assertion_predicates_for_post_loop(main_head, post_head, first_node_index_in_cloned_loop_body); + } return new_main_exit; } @@ -1937,53 +1823,45 @@ void PhaseIdealLoop::update_main_loop_assertion_predicates(Node* ctrl, CountedLo } } -// Go over the Assertion Predicates of the main loop and make a copy for the post loop with its initial iv value and -// stride as inputs. -void PhaseIdealLoop::copy_assertion_predicates_to_post_loop(LoopNode* main_loop_head, CountedLoopNode* post_loop_head, - Node* stride) { - Node* opaq = post_loop_head->is_canonical_loop_entry(); - Node* init = opaq->in(1); - Node* post_loop_entry = post_loop_head->in(LoopNode::EntryControl); - Node* main_loop_entry = main_loop_head->in(LoopNode::EntryControl); - IdealLoopTree* post_loop = get_loop(post_loop_head); - - Node* ctrl = main_loop_entry; - Node* prev_proj = post_loop_entry; - while (ctrl != nullptr && ctrl->is_Proj() && ctrl->in(0)->is_If()) { - IfNode* iff = ctrl->in(0)->as_If(); - ProjNode* proj = iff->proj_out(1 - ctrl->as_Proj()->_con); - if (!proj->unique_ctrl_out()->is_Halt()) { - break; - } - if (iff->in(1)->is_OpaqueTemplateAssertionPredicate()) { - // Initialize from Template Assertion Predicate. - prev_proj = create_initialized_assertion_predicate(iff, init, stride, prev_proj); - } - ctrl = ctrl->in(0)->in(0); - } - if (prev_proj != post_loop_entry) { - _igvn.replace_input_of(post_loop_head, LoopNode::EntryControl, prev_proj); - set_idom(post_loop_head, prev_proj, dom_depth(post_loop_head)); - } -} - +// Source Loop: Cloned - peeled_loop_head +// Target Loop: Original - remaining_loop_head void PhaseIdealLoop::initialize_assertion_predicates_for_peeled_loop(CountedLoopNode* peeled_loop_head, CountedLoopNode* remaining_loop_head, const uint first_node_index_in_cloned_loop_body, const Node_List& old_new) { const NodeInOriginalLoopBody node_in_original_loop_body(first_node_index_in_cloned_loop_body, old_new); - create_assertion_predicates_at_loop(peeled_loop_head, remaining_loop_head, node_in_original_loop_body); + create_assertion_predicates_at_loop(peeled_loop_head, remaining_loop_head, node_in_original_loop_body, false); +} + +// Source Loop: Cloned - pre_loop_head +// Target Loop: Original - main_loop_head +void PhaseIdealLoop::initialize_assertion_predicates_for_main_loop(CountedLoopNode* pre_loop_head, + CountedLoopNode* main_loop_head, + const uint first_node_index_in_cloned_loop_body, + const Node_List& old_new) { + const NodeInOriginalLoopBody node_in_original_loop_body(first_node_index_in_cloned_loop_body, old_new); + create_assertion_predicates_at_loop(pre_loop_head, main_loop_head, node_in_original_loop_body, true); +} + +// Source Loop: Original - main_loop_head +// Target Loop: Cloned - post_loop_head +void PhaseIdealLoop::initialize_assertion_predicates_for_post_loop(CountedLoopNode* main_loop_head, + CountedLoopNode* post_loop_head, + const uint first_node_index_in_cloned_loop_body) { + const NodeInClonedLoopBody node_in_cloned_loop_body(first_node_index_in_cloned_loop_body); + create_assertion_predicates_at_loop(main_loop_head, post_loop_head, node_in_cloned_loop_body, false); } void PhaseIdealLoop::create_assertion_predicates_at_loop(CountedLoopNode* source_loop_head, - CountedLoopNode* target_loop_head, - const NodeInLoopBody& _node_in_loop_body) { + CountedLoopNode* target_loop_head, + const NodeInLoopBody& _node_in_loop_body, + const bool clone_template) { Node* init = target_loop_head->init_trip(); Node* stride = target_loop_head->stride(); LoopNode* target_outer_loop_head = target_loop_head->skip_strip_mined(); Node* target_loop_entry = target_outer_loop_head->in(LoopNode::EntryControl); CreateAssertionPredicatesVisitor create_assertion_predicates_visitor(init, stride, target_loop_entry, this, - _node_in_loop_body); + _node_in_loop_body, clone_template); Node* source_loop_entry = source_loop_head->skip_strip_mined()->in(LoopNode::EntryControl); PredicateIterator predicate_iterator(source_loop_entry); predicate_iterator.for_each(create_assertion_predicates_visitor); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index fc0f1b4d53c..487c4473280 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -939,35 +939,28 @@ class PhaseIdealLoop : public PhaseTransform { } #ifdef ASSERT - void ensure_zero_trip_guard_proj(Node* node, bool is_main_loop); + static void ensure_zero_trip_guard_proj(Node* node, bool is_main_loop); #endif - void copy_assertion_predicates_to_main_loop_helper(const PredicateBlock* predicate_block, Node* init, Node* stride, - IdealLoopTree* outer_loop, LoopNode* outer_main_head, - uint dd_main_head, uint idx_before_pre_post, - uint idx_after_post_before_pre, Node* zero_trip_guard_proj_main, - Node* zero_trip_guard_proj_post, const Node_List &old_new); - void copy_assertion_predicates_to_main_loop(CountedLoopNode* pre_head, Node* init, Node* stride, IdealLoopTree* outer_loop, - LoopNode* outer_main_head, uint dd_main_head, uint idx_before_pre_post, - uint idx_after_post_before_pre, Node* zero_trip_guard_proj_main, - Node* zero_trip_guard_proj_post, const Node_List& old_new); - Node* clone_template_assertion_predicate(IfNode* iff, Node* new_init, Node* predicate, Node* uncommon_proj, Node* control, - IdealLoopTree* outer_loop, Node* new_control); public: IfTrueNode* create_initialized_assertion_predicate(IfNode* template_assertion_predicate, Node* new_init, Node* new_stride, Node* control); + DEBUG_ONLY(static bool assertion_predicate_has_loop_opaque_node(IfNode* iff);) private: DEBUG_ONLY(static void count_opaque_loop_nodes(Node* n, uint& init, uint& stride);) - DEBUG_ONLY(static bool assertion_predicate_has_loop_opaque_node(IfNode* iff);) static void get_assertion_predicates(Node* predicate, Unique_Node_List& list, bool get_opaque = false); void update_main_loop_assertion_predicates(Node* ctrl, CountedLoopNode* loop_head, Node* init, int stride_con); - void copy_assertion_predicates_to_post_loop(LoopNode* main_loop_head, CountedLoopNode* post_loop_head, - Node* stride); void initialize_assertion_predicates_for_peeled_loop(CountedLoopNode* peeled_loop_head, CountedLoopNode* remaining_loop_head, uint first_node_index_in_cloned_loop_body, const Node_List& old_new); + void initialize_assertion_predicates_for_main_loop(CountedLoopNode* pre_loop_head, + CountedLoopNode* main_loop_head, + uint first_node_index_in_cloned_loop_body, + const Node_List& old_new); + void initialize_assertion_predicates_for_post_loop(CountedLoopNode* main_loop_head, CountedLoopNode* post_loop_head, + uint first_node_index_in_cloned_loop_body); void create_assertion_predicates_at_loop(CountedLoopNode* source_loop_head, CountedLoopNode* target_loop_head, - const NodeInLoopBody& _node_in_loop_body); + const NodeInLoopBody& _node_in_loop_body, bool clone_template); void insert_loop_limit_check_predicate(ParsePredicateSuccessProj* loop_limit_check_parse_proj, Node* cmp_limit, Node* bol); void log_loop_tree(); diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 54a17376f18..ee218063567 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -162,6 +162,23 @@ bool TemplateAssertionPredicate::is_predicate(Node* node) { return if_node->in(1)->is_OpaqueTemplateAssertionPredicate(); } +// Clone this Template Assertion Predicate and replace the OpaqueLoopInitNode with the provided 'new_opaque_init' node. +IfTrueNode* TemplateAssertionPredicate::clone_and_replace_init(Node* new_control, OpaqueLoopInitNode* new_opaque_init, + PhaseIdealLoop* phase) const { + assert(PhaseIdealLoop::assertion_predicate_has_loop_opaque_node(_if_node), + "must find OpaqueLoop* nodes for Template Assertion Predicate"); + TemplateAssertionExpression template_assertion_expression(opaque_node()); + OpaqueTemplateAssertionPredicateNode* new_opaque_node = + template_assertion_expression.clone_and_replace_init(new_opaque_init, new_control, phase); + AssertionPredicateIfCreator assertion_predicate_if_creator(phase); + IfTrueNode* success_proj = assertion_predicate_if_creator.create_for_template(new_control, _if_node->Opcode(), + new_opaque_node NOT_PRODUCT(COMMA + _if_node->assertion_predicate_type())); + assert(PhaseIdealLoop::assertion_predicate_has_loop_opaque_node(success_proj->in(0)->as_If()), + "Template Assertion Predicates must have OpaqueLoop* nodes in the bool expression"); + return success_proj; +} + // Initialized Assertion Predicates always have the dedicated OpaqueInitiailizedAssertionPredicate node to identify // them. bool InitializedAssertionPredicate::is_predicate(Node* node) { @@ -743,9 +760,26 @@ void CreateAssertionPredicatesVisitor::visit(const TemplateAssertionPredicate& t // Only process if we are in the correct Predicate Block. return; } + if (_clone_template) { + _new_control = clone_template_and_replace_init_input(template_assertion_predicate); + } + _new_control = initialize_from_template(template_assertion_predicate); +} + +// Create an Initialized Assertion Predicate from the provided Template Assertion Predicate. +IfTrueNode* CreateAssertionPredicatesVisitor::initialize_from_template( +const TemplateAssertionPredicate& template_assertion_predicate) const { IfNode* template_head = template_assertion_predicate.head(); IfTrueNode* initialized_predicate = _phase->create_initialized_assertion_predicate(template_head, _init, _stride, _new_control); template_assertion_predicate.rewire_loop_data_dependencies(initialized_predicate, _node_in_loop_body, _phase); - _new_control = initialized_predicate; + return initialized_predicate; +} + +// Clone the provided 'template_assertion_predicate' and set '_init' as new input for the OpaqueLoopInitNode. +IfTrueNode* CreateAssertionPredicatesVisitor::clone_template_and_replace_init_input( + const TemplateAssertionPredicate& template_assertion_predicate) { + OpaqueLoopInitNode* opaque_init = new OpaqueLoopInitNode(_phase->C, _init); + _phase->register_new_node(opaque_init, _new_control); + return template_assertion_predicate.clone_and_replace_init(_new_control, opaque_init, _phase); } diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index 5eb0cfc9b35..f57948f8ab9 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -391,6 +391,10 @@ class TemplateAssertionPredicate : public Predicate { return _if_node->in(0); } + OpaqueTemplateAssertionPredicateNode* opaque_node() const { + return _if_node->in(1)->as_OpaqueTemplateAssertionPredicate(); + } + IfNode* head() const override { return _if_node; } @@ -399,6 +403,7 @@ class TemplateAssertionPredicate : public Predicate { return _success_proj; } + IfTrueNode* clone_and_replace_init(Node* new_control, OpaqueLoopInitNode* new_opaque_init, PhaseIdealLoop* phase) const; void rewire_loop_data_dependencies(IfTrueNode* target_predicate, const NodeInLoopBody& data_in_loop_body, PhaseIdealLoop* phase) const; static bool is_predicate(Node* node); @@ -941,6 +946,22 @@ class NodeInOriginalLoopBody : public NodeInLoopBody { } }; +// This class checks whether a node is in the cloned loop body and not the original one from which the loop was cloned. +class NodeInClonedLoopBody : public NodeInLoopBody { + const uint _first_node_index_in_cloned_loop_body; + + public: + explicit NodeInClonedLoopBody(const uint first_node_index_in_cloned_loop_body) + : _first_node_index_in_cloned_loop_body(first_node_index_in_cloned_loop_body) {} + NONCOPYABLE(NodeInClonedLoopBody); + + // Check if 'node' is a clone. This can easily be achieved by comparing its node index to the first node index + // inside the cloned loop body (all of them are clones). + bool check(Node* node) const override { + return node->_idx >= _first_node_index_in_cloned_loop_body; + } +}; + // Visitor to create Initialized Assertion Predicates at a target loop from Template Assertion Predicates from a source // loop. This visitor can be used in combination with a PredicateIterator. class CreateAssertionPredicatesVisitor : public PredicateVisitor { @@ -951,17 +972,22 @@ class CreateAssertionPredicatesVisitor : public PredicateVisitor { PhaseIdealLoop* const _phase; bool _has_hoisted_check_parse_predicates; const NodeInLoopBody& _node_in_loop_body; + const bool _clone_template; + + IfTrueNode* clone_template_and_replace_init_input(const TemplateAssertionPredicate& template_assertion_predicate); + IfTrueNode* initialize_from_template(const TemplateAssertionPredicate& template_assertion_predicate) const; public: CreateAssertionPredicatesVisitor(Node* init, Node* stride, Node* new_control, PhaseIdealLoop* phase, - const NodeInLoopBody& node_in_loop_body) + const NodeInLoopBody& node_in_loop_body, const bool clone_template) : _init(init), _stride(stride), _old_target_loop_entry(new_control), _new_control(new_control), _phase(phase), _has_hoisted_check_parse_predicates(false), - _node_in_loop_body(node_in_loop_body) {} + _node_in_loop_body(node_in_loop_body), + _clone_template(clone_template) {} NONCOPYABLE(CreateAssertionPredicatesVisitor); using PredicateVisitor::visit; From bdd68163df4d9b63694bfc0900e4b5ddb2475834 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Wed, 6 Nov 2024 06:36:49 +0000 Subject: [PATCH 22/23] 8343502: RISC-V: SIGBUS in updateBytesCRC32 after JDK-8339738 Reviewed-by: mli, fjiang --- .../cpu/riscv/macroAssembler_riscv.cpp | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 0c16934289d..3bb478dbe05 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1567,7 +1567,7 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Label L_vector_entry, L_unroll_loop, L_by4_loop_entry, L_by4_loop, - L_by1_loop, L_exit; + L_by1_loop, L_exit, L_skip1, L_skip2; const int64_t single_table_size = 256; const int64_t unroll = 16; @@ -1581,6 +1581,27 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, add(table2, table0, 2*single_table_size*sizeof(juint), tmp1); add(table3, table2, 1*single_table_size*sizeof(juint), tmp1); + // Ensure basic 4-byte alignment of input byte buffer + mv(tmp1, 4); + blt(len, tmp1, L_by1_loop); + test_bit(tmp1, buf, 0); + beqz(tmp1, L_skip1); + subw(len, len, 1); + lbu(tmp1, Address(buf)); + add(buf, buf, 1); + update_byte_crc32(crc, tmp1, table0); + bind(L_skip1); + test_bit(tmp1, buf, 1); + beqz(tmp1, L_skip2); + subw(len, len, 2); + lhu(tmp1, Address(buf)); + add(buf, buf, 2); + andi(tmp2, tmp1, right_8_bits); + update_byte_crc32(crc, tmp2, table0); + srli(tmp2, tmp1, 8); + update_byte_crc32(crc, tmp2, table0); + bind(L_skip2); + #ifdef COMPILER2 if (UseRVV) { const int64_t tmp_limit = MaxVectorSize >= 32 ? unroll_words*3 : unroll_words*5; @@ -1625,21 +1646,18 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, beqz(len, L_exit); subw(len, len, 1); - lwu(tmp1, Address(buf)); - andi(tmp2, tmp1, right_8_bits); - update_byte_crc32(crc, tmp2, table0); + lbu(tmp1, Address(buf)); + update_byte_crc32(crc, tmp1, table0); beqz(len, L_exit); subw(len, len, 1); - srli(tmp2, tmp1, 8); - andi(tmp2, tmp2, right_8_bits); - update_byte_crc32(crc, tmp2, table0); + lbu(tmp1, Address(buf, 1)); + update_byte_crc32(crc, tmp1, table0); beqz(len, L_exit); subw(len, len, 1); - srli(tmp2, tmp1, 16); - andi(tmp2, tmp2, right_8_bits); - update_byte_crc32(crc, tmp2, table0); + lbu(tmp1, Address(buf, 2)); + update_byte_crc32(crc, tmp1, table0); #ifdef COMPILER2 // put vector code here, otherwise "offset is too large" error occurs. From 06d8216a4ef6b883119459da7e52b37d16cd2f03 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 6 Nov 2024 08:03:26 +0000 Subject: [PATCH 23/23] 8318442: java/net/httpclient/ManyRequests2.java fails intermittently on Linux Reviewed-by: mdoerr, lucy, dfuchs --- test/jdk/java/net/httpclient/ManyRequests2.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/net/httpclient/ManyRequests2.java b/test/jdk/java/net/httpclient/ManyRequests2.java index b0d17fe9bca..69ce475eca2 100644 --- a/test/jdk/java/net/httpclient/ManyRequests2.java +++ b/test/jdk/java/net/httpclient/ManyRequests2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,16 +33,16 @@ * @compile ../../../com/sun/net/httpserver/EchoHandler.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java * @build ManyRequests ManyRequests2 - * @run main/othervm/timeout=40 -Dtest.XFixed=true + * @run main/othervm/timeout=400 -Dsun.net.httpserver.idleInterval=400 -Dtest.XFixed=true * -Djdk.tracePinnedThreads=full * -Djdk.httpclient.HttpClient.log=channel ManyRequests2 - * @run main/othervm/timeout=40 -Dtest.XFixed=true -Dtest.insertDelay=true + * @run main/othervm/timeout=400 -Dsun.net.httpserver.idleInterval=400 -Dtest.XFixed=true -Dtest.insertDelay=true * -Djdk.tracePinnedThreads=full * -Djdk.httpclient.HttpClient.log=channel ManyRequests2 - * @run main/othervm/timeout=40 -Dtest.XFixed=true -Dtest.chunkSize=64 + * @run main/othervm/timeout=400 -Dsun.net.httpserver.idleInterval=400 -Dtest.XFixed=true -Dtest.chunkSize=64 * -Djdk.tracePinnedThreads=full * -Djdk.httpclient.HttpClient.log=channel ManyRequests2 - * @run main/othervm/timeout=400 -Djdk.internal.httpclient.debug=true + * @run main/othervm/timeout=400 -Dsun.net.httpserver.idleInterval=400 -Djdk.internal.httpclient.debug=true * -Djdk.tracePinnedThreads=full * -Djdk.httpclient.HttpClient.log=channel * -Dtest.XFixed=true -Dtest.insertDelay=true