diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index ad131b20e27..572790b567b 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -50,7 +50,14 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # add -z,relro (mark relocations read only) for all libs # add -z,now ("full relro" - more of the Global Offset Table GOT is marked read only) # add --no-as-needed to disable default --as-needed link flag on some GCC toolchains + # add --icf=all (Identical Code Folding — merges identical functions) BASIC_LDFLAGS="-Wl,-z,defs -Wl,-z,relro -Wl,-z,now -Wl,--no-as-needed -Wl,--exclude-libs,ALL" + if test "x$LINKER_TYPE" = "xgold"; then + if test x$DEBUG_LEVEL = xrelease; then + BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--icf=all" + fi + fi + # Linux : remove unused code+data in link step if test "x$ENABLE_LINKTIME_GC" = xtrue; then if test "x$OPENJDK_TARGET_CPU" = xs390x; then diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 4662c62d901..15210efe4a7 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -516,6 +516,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_LD_VERSION], if [ [[ "$LINKER_VERSION_STRING" == *gold* ]] ]; then [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*) .*/\1/'` ] + LINKER_TYPE=gold else [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*/\1/'` ] diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index 4cecc3070e7..14117421d1b 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -170,6 +170,7 @@ ifeq ($(call check-jvm-feature, compiler2), true) ifeq ($(HOTSPOT_TARGET_CPU_ARCH), aarch64) AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/$(HOTSPOT_TARGET_CPU_ARCH)_vector.ad \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/$(HOTSPOT_TARGET_CPU_ARCH)_atomic.ad \ ))) endif diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index b036973b776..4cd7f5bac90 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -237,7 +237,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) DISABLED_WARNINGS_gcc_dgif_lib.c := sign-compare, \ DISABLED_WARNINGS_gcc_jcmaster.c := implicit-fallthrough, \ DISABLED_WARNINGS_gcc_jdphuff.c := shift-negative-value, \ - DISABLED_WARNINGS_gcc_png.c := maybe-uninitialized unused-function, \ + DISABLED_WARNINGS_gcc_png.c := maybe-uninitialized, \ DISABLED_WARNINGS_gcc_pngerror.c := maybe-uninitialized, \ DISABLED_WARNINGS_gcc_splashscreen_gfx_impl.c := implicit-fallthrough \ maybe-uninitialized, \ @@ -248,7 +248,6 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) DISABLED_WARNINGS_clang := deprecated-non-prototype, \ DISABLED_WARNINGS_clang_dgif_lib.c := sign-compare, \ DISABLED_WARNINGS_clang_gzwrite.c := format-nonliteral, \ - DISABLED_WARNINGS_clang_png.c := unused-function, \ DISABLED_WARNINGS_clang_splashscreen_impl.c := sign-compare \ unused-but-set-variable unused-function, \ DISABLED_WARNINGS_clang_splashscreen_png.c := \ diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 364db407bd3..9c76ed24788 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2456,6 +2456,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) { return false; } +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) { + return false; +} + bool Matcher::is_generic_vector(MachOper* opnd) { return opnd->opcode() == VREG; } @@ -3338,73 +3342,6 @@ encode %{ __ cmpw(rscratch1, zr); %} - enc_class aarch64_enc_cmpxchg(memory mem, iRegLNoSp oldval, iRegLNoSp newval) %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ false, /*release*/ true, - /*weak*/ false, noreg); - %} - - enc_class aarch64_enc_cmpxchgw(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ false, /*release*/ true, - /*weak*/ false, noreg); - %} - - enc_class aarch64_enc_cmpxchgs(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, - Assembler::halfword, /*acquire*/ false, /*release*/ true, - /*weak*/ false, noreg); - %} - - enc_class aarch64_enc_cmpxchgb(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, - Assembler::byte, /*acquire*/ false, /*release*/ true, - /*weak*/ false, noreg); - %} - - - // The only difference between aarch64_enc_cmpxchg and - // aarch64_enc_cmpxchg_acq is that we use load-acquire in the - // CompareAndSwap sequence to serve as a barrier on acquiring a - // lock. - enc_class aarch64_enc_cmpxchg_acq(memory mem, iRegL oldval, iRegL newval) %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ true, /*release*/ true, - /*weak*/ false, noreg); - %} - - enc_class aarch64_enc_cmpxchgw_acq(memory mem, iRegI oldval, iRegI newval) %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ true, /*release*/ true, - /*weak*/ false, noreg); - %} - - enc_class aarch64_enc_cmpxchgs_acq(memory mem, iRegI oldval, iRegI newval) %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, - Assembler::halfword, /*acquire*/ true, /*release*/ true, - /*weak*/ false, noreg); - %} - - enc_class aarch64_enc_cmpxchgb_acq(memory mem, iRegI oldval, iRegI newval) %{ - guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); - __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, - Assembler::byte, /*acquire*/ true, /*release*/ true, - /*weak*/ false, noreg); - %} - - // auxiliary used for CompareAndSwapX to set result register - enc_class aarch64_enc_cset_eq(iRegI res) %{ - Register res_reg = as_Register($res$$reg); - __ cset(res_reg, Assembler::EQ); - %} - // prefetch encodings enc_class aarch64_enc_prefetchw(memory mem) %{ @@ -8376,971 +8313,6 @@ instruct castVVMask(pRegGov dst) ins_pipe(pipe_class_empty); %} -// ============================================================================ -// Atomic operation instructions -// - -// standard CompareAndSwapX when we are using barriers -// these have higher priority than the rules selected by a predicate - -// XXX No flag versions for CompareAndSwap{I,L,P,N} because matcher -// can't match them - -instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - - match(Set res (CompareAndSwapB mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchgb $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchgb(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - - match(Set res (CompareAndSwapS mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchgs $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchgs(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - - match(Set res (CompareAndSwapI mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchgw $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchgw(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ - - match(Set res (CompareAndSwapL mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchg(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - predicate(n->as_LoadStore()->barrier_data() == 0); - ins_cost(2 * VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchg(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - - match(Set res (CompareAndSwapN mem (Binary oldval newval))); - predicate(n->as_LoadStore()->barrier_data() == 0); - ins_cost(2 * VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchgw $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchgw(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -// alternative CompareAndSwapX when we are eliding barriers - -instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (CompareAndSwapB mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchgb_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchgb_acq(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (CompareAndSwapS mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchgs_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchgs_acq(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (CompareAndSwapI mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchgw_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ - - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (CompareAndSwapL mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchg_acq $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - - predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchg_acq $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - - predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndSwapN mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - - effect(KILL cr); - - format %{ - "cmpxchgw_acq $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" - "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - - ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval), - aarch64_enc_cset_eq(res)); - - ins_pipe(pipe_slow); -%} - - -// --------------------------------------------------------------------- - -// BEGIN This section of the file is automatically generated. Do not edit -------------- - -// Sundry CAS operations. Note that release is always true, -// regardless of the memory ordering of the CAS. This is because we -// need the volatile case to be sequentially consistent but there is -// no trailing StoreLoad barrier emitted by C2. Unfortunately we -// can't check the type of memory ordering here, so we always emit a -// STLXR. - -// This section is generated from cas.m4 - - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - match(Set res (CompareAndExchangeB mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchgb $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::byte, /*acquire*/ false, /*release*/ true, - /*weak*/ false, $res$$Register); - __ sxtbw($res$$Register, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - match(Set res (CompareAndExchangeS mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchgs $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::halfword, /*acquire*/ false, /*release*/ true, - /*weak*/ false, $res$$Register); - __ sxthw($res$$Register, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - match(Set res (CompareAndExchangeI mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchgw $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ false, /*release*/ true, - /*weak*/ false, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ - match(Set res (CompareAndExchangeL mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ false, /*release*/ true, - /*weak*/ false, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndExchangeN mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ false, /*release*/ true, - /*weak*/ false, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ false, /*release*/ true, - /*weak*/ false, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (CompareAndExchangeB mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::byte, /*acquire*/ true, /*release*/ true, - /*weak*/ false, $res$$Register); - __ sxtbw($res$$Register, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (CompareAndExchangeS mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::halfword, /*acquire*/ true, /*release*/ true, - /*weak*/ false, $res$$Register); - __ sxthw($res$$Register, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (CompareAndExchangeI mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ true, /*release*/ true, - /*weak*/ false, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (CompareAndExchangeL mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ true, /*release*/ true, - /*weak*/ false, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndExchangeN mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ true, /*release*/ true, - /*weak*/ false, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); - match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ true, /*release*/ true, - /*weak*/ false, $res$$Register); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgb $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::byte, /*acquire*/ false, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgs $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::halfword, /*acquire*/ false, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgw $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ false, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ - match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ false, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ false, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - ins_cost(2 * VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ false, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::byte, /*acquire*/ true, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::halfword, /*acquire*/ true, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ true, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ true, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); - match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::word, /*acquire*/ true, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); - match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - ins_cost(VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::xword, /*acquire*/ true, /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -// END This section of the file is automatically generated. Do not edit -------------- -// --------------------------------------------------------------------- - -instruct get_and_setI(indirect mem, iRegI newv, iRegINoSp prev) %{ - match(Set prev (GetAndSetI mem newv)); - ins_cost(2 * VOLATILE_REF_COST); - format %{ "atomic_xchgw $prev, $newv, [$mem]" %} - ins_encode %{ - __ atomic_xchgw($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{ - match(Set prev (GetAndSetL mem newv)); - ins_cost(2 * VOLATILE_REF_COST); - format %{ "atomic_xchg $prev, $newv, [$mem]" %} - ins_encode %{ - __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set prev (GetAndSetN mem newv)); - ins_cost(2 * VOLATILE_REF_COST); - format %{ "atomic_xchgw $prev, $newv, [$mem]" %} - ins_encode %{ - __ atomic_xchgw($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_setP(indirect mem, iRegP newv, iRegPNoSp prev) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set prev (GetAndSetP mem newv)); - ins_cost(2 * VOLATILE_REF_COST); - format %{ "atomic_xchg $prev, $newv, [$mem]" %} - ins_encode %{ - __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_setIAcq(indirect mem, iRegI newv, iRegINoSp prev) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set prev (GetAndSetI mem newv)); - ins_cost(VOLATILE_REF_COST); - format %{ "atomic_xchgw_acq $prev, $newv, [$mem]" %} - ins_encode %{ - __ atomic_xchgalw($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set prev (GetAndSetL mem newv)); - ins_cost(VOLATILE_REF_COST); - format %{ "atomic_xchg_acq $prev, $newv, [$mem]" %} - ins_encode %{ - __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev) %{ - predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); - match(Set prev (GetAndSetN mem newv)); - ins_cost(VOLATILE_REF_COST); - format %{ "atomic_xchgw_acq $prev, $newv, [$mem]" %} - ins_encode %{ - __ atomic_xchgalw($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_setPAcq(indirect mem, iRegP newv, iRegPNoSp prev) %{ - predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); - match(Set prev (GetAndSetP mem newv)); - ins_cost(VOLATILE_REF_COST); - format %{ "atomic_xchg_acq $prev, $newv, [$mem]" %} - ins_encode %{ - __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - - -instruct get_and_addL(indirect mem, iRegLNoSp newval, iRegL incr) %{ - match(Set newval (GetAndAddL mem incr)); - ins_cost(2 * VOLATILE_REF_COST + 1); - format %{ "get_and_addL $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_add($newval$$Register, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addL_no_res(indirect mem, Universe dummy, iRegL incr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddL mem incr)); - ins_cost(2 * VOLATILE_REF_COST); - format %{ "get_and_addL [$mem], $incr" %} - ins_encode %{ - __ atomic_add(noreg, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addLi(indirect mem, iRegLNoSp newval, immLAddSub incr) %{ - match(Set newval (GetAndAddL mem incr)); - ins_cost(2 * VOLATILE_REF_COST + 1); - format %{ "get_and_addL $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_add($newval$$Register, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addLi_no_res(indirect mem, Universe dummy, immLAddSub incr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddL mem incr)); - ins_cost(2 * VOLATILE_REF_COST); - format %{ "get_and_addL [$mem], $incr" %} - ins_encode %{ - __ atomic_add(noreg, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addI(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{ - match(Set newval (GetAndAddI mem incr)); - ins_cost(2 * VOLATILE_REF_COST + 1); - format %{ "get_and_addI $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_addw($newval$$Register, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addI_no_res(indirect mem, Universe dummy, iRegIorL2I incr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddI mem incr)); - ins_cost(2 * VOLATILE_REF_COST); - format %{ "get_and_addI [$mem], $incr" %} - ins_encode %{ - __ atomic_addw(noreg, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addIi(indirect mem, iRegINoSp newval, immIAddSub incr) %{ - match(Set newval (GetAndAddI mem incr)); - ins_cost(2 * VOLATILE_REF_COST + 1); - format %{ "get_and_addI $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_addw($newval$$Register, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addIi_no_res(indirect mem, Universe dummy, immIAddSub incr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddI mem incr)); - ins_cost(2 * VOLATILE_REF_COST); - format %{ "get_and_addI [$mem], $incr" %} - ins_encode %{ - __ atomic_addw(noreg, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addLAcq(indirect mem, iRegLNoSp newval, iRegL incr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set newval (GetAndAddL mem incr)); - ins_cost(VOLATILE_REF_COST + 1); - format %{ "get_and_addL_acq $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_addal($newval$$Register, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addL_no_resAcq(indirect mem, Universe dummy, iRegL incr) %{ - predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); - match(Set dummy (GetAndAddL mem incr)); - ins_cost(VOLATILE_REF_COST); - format %{ "get_and_addL_acq [$mem], $incr" %} - ins_encode %{ - __ atomic_addal(noreg, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addLiAcq(indirect mem, iRegLNoSp newval, immLAddSub incr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set newval (GetAndAddL mem incr)); - ins_cost(VOLATILE_REF_COST + 1); - format %{ "get_and_addL_acq $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_addal($newval$$Register, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addLi_no_resAcq(indirect mem, Universe dummy, immLAddSub incr) %{ - predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); - match(Set dummy (GetAndAddL mem incr)); - ins_cost(VOLATILE_REF_COST); - format %{ "get_and_addL_acq [$mem], $incr" %} - ins_encode %{ - __ atomic_addal(noreg, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addIAcq(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set newval (GetAndAddI mem incr)); - ins_cost(VOLATILE_REF_COST + 1); - format %{ "get_and_addI_acq $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_addalw($newval$$Register, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addI_no_resAcq(indirect mem, Universe dummy, iRegIorL2I incr) %{ - predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); - match(Set dummy (GetAndAddI mem incr)); - ins_cost(VOLATILE_REF_COST); - format %{ "get_and_addI_acq [$mem], $incr" %} - ins_encode %{ - __ atomic_addalw(noreg, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addIiAcq(indirect mem, iRegINoSp newval, immIAddSub incr) %{ - predicate(needs_acquiring_load_exclusive(n)); - match(Set newval (GetAndAddI mem incr)); - ins_cost(VOLATILE_REF_COST + 1); - format %{ "get_and_addI_acq $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_addalw($newval$$Register, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct get_and_addIi_no_resAcq(indirect mem, Universe dummy, immIAddSub incr) %{ - predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); - match(Set dummy (GetAndAddI mem incr)); - ins_cost(VOLATILE_REF_COST); - format %{ "get_and_addI_acq [$mem], $incr" %} - ins_encode %{ - __ atomic_addalw(noreg, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - // Manifest a CmpU result in an integer register. // (src1 < src2) ? -1 : ((src1 > src2) ? 1 : 0) instruct cmpU3_reg_reg(iRegINoSp dst, iRegI src1, iRegI src2, rFlagsReg flags) diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic.ad b/src/hotspot/cpu/aarch64/aarch64_atomic.ad new file mode 100644 index 00000000000..faac2a43110 --- /dev/null +++ b/src/hotspot/cpu/aarch64/aarch64_atomic.ad @@ -0,0 +1,909 @@ +// Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2016, 2021, Red Hat Inc. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +// + +// BEGIN This file is automatically generated. Do not edit -------------- + +// Sundry CAS operations. Note that release is always true, +// regardless of the memory ordering of the CAS. This is because we +// need the volatile case to be sequentially consistent but there is +// no trailing StoreLoad barrier emitted by C2. Unfortunately we +// can't check the type of memory ordering here, so we always emit a +// STLXR. + +// This section is generated from aarch64_atomic_ad.m4 + + +instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + match(Set res (CompareAndExchangeB mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchgb $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::byte, /*acquire*/ false, /*release*/ true, + /*weak*/ false, $res$$Register); + __ sxtbw($res$$Register, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + match(Set res (CompareAndExchangeS mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchgs $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::halfword, /*acquire*/ false, /*release*/ true, + /*weak*/ false, $res$$Register); + __ sxthw($res$$Register, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + match(Set res (CompareAndExchangeI mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchgw $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ false, /*release*/ true, + /*weak*/ false, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ + match(Set res (CompareAndExchangeL mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ false, /*release*/ true, + /*weak*/ false, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ false, /*release*/ true, + /*weak*/ false, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ false, /*release*/ true, + /*weak*/ false, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndExchangeB mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::byte, /*acquire*/ true, /*release*/ true, + /*weak*/ false, $res$$Register); + __ sxtbw($res$$Register, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndExchangeS mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::halfword, /*acquire*/ true, /*release*/ true, + /*weak*/ false, $res$$Register); + __ sxthw($res$$Register, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndExchangeI mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ true, /*release*/ true, + /*weak*/ false, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndExchangeL mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ true, /*release*/ true, + /*weak*/ false, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ true, /*release*/ true, + /*weak*/ false, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ true, /*release*/ true, + /*weak*/ false, $res$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + match(Set res (CompareAndSwapB mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgb $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::byte, /*acquire*/ false, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + match(Set res (CompareAndSwapS mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgs $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::halfword, /*acquire*/ false, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + match(Set res (CompareAndSwapI mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgw $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ false, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ + match(Set res (CompareAndSwapL mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ false, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ false, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ false, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapB mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::byte, /*acquire*/ true, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapS mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::halfword, /*acquire*/ true, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapI mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ true, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapL mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ true, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ true, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ true, /*release*/ true, + /*weak*/ false, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgb_weak $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::byte, /*acquire*/ false, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgs_weak $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::halfword, /*acquire*/ false, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgw_weak $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ false, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ + match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg_weak $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ false, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgw_weak $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ false, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + ins_cost(2*VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg_weak $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ false, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgb_acq_weak $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::byte, /*acquire*/ true, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgs_acq_weak $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::halfword, /*acquire*/ true, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgw_acq_weak $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ true, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg_acq_weak $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ true, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchgw_acq_weak $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::word, /*acquire*/ true, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg_acq_weak $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::xword, /*acquire*/ true, /*release*/ true, + /*weak*/ true, noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%} + +instruct getAndSetI(indirect mem, iRegI newval, iRegINoSp oldval) %{ + match(Set oldval (GetAndSetI mem newval)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "atomic_xchgw $oldval, $newval, [$mem]" %} + ins_encode %{ + __ atomic_xchgw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndSetL(indirect mem, iRegL newval, iRegLNoSp oldval) %{ + match(Set oldval (GetAndSetL mem newval)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "atomic_xchg $oldval, $newval, [$mem]" %} + ins_encode %{ + __ atomic_xchg($oldval$$Register, $newval$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndSetN(indirect mem, iRegN newval, iRegNNoSp oldval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set oldval (GetAndSetN mem newval)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "atomic_xchgw $oldval, $newval, [$mem]" %} + ins_encode %{ + __ atomic_xchgw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndSetP(indirect mem, iRegP newval, iRegPNoSp oldval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set oldval (GetAndSetP mem newval)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "atomic_xchg $oldval, $newval, [$mem]" %} + ins_encode %{ + __ atomic_xchg($oldval$$Register, $newval$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndSetIAcq(indirect mem, iRegI newval, iRegINoSp oldval) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set oldval (GetAndSetI mem newval)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "atomic_xchgw_acq $oldval, $newval, [$mem]" %} + ins_encode %{ + __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndSetLAcq(indirect mem, iRegL newval, iRegLNoSp oldval) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set oldval (GetAndSetL mem newval)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "atomic_xchg_acq $oldval, $newval, [$mem]" %} + ins_encode %{ + __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndSetNAcq(indirect mem, iRegN newval, iRegNNoSp oldval) %{ + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); + match(Set oldval (GetAndSetN mem newval)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "atomic_xchgw_acq $oldval, $newval, [$mem]" %} + ins_encode %{ + __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp oldval) %{ + predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); + match(Set oldval (GetAndSetP mem newval)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "atomic_xchg_acq $oldval, $newval, [$mem]" %} + ins_encode %{ + __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddI(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{ + match(Set newval (GetAndAddI mem incr)); + ins_cost(2*VOLATILE_REF_COST+1); + format %{ "get_and_addI $newval, [$mem], $incr" %} + ins_encode %{ + __ atomic_addw($newval$$Register, $incr$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddIAcq(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set newval (GetAndAddI mem incr)); + ins_cost(VOLATILE_REF_COST+1); + format %{ "get_and_addI_acq $newval, [$mem], $incr" %} + ins_encode %{ + __ atomic_addalw($newval$$Register, $incr$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddINoRes(indirect mem, Universe dummy, iRegIorL2I incr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddI mem incr)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "get_and_addI noreg, [$mem], $incr" %} + ins_encode %{ + __ atomic_addw(noreg, $incr$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddIAcqNoRes(indirect mem, Universe dummy, iRegIorL2I incr) %{ + predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); + match(Set dummy (GetAndAddI mem incr)); + ins_cost(VOLATILE_REF_COST); + format %{ "get_and_addI_acq noreg, [$mem], $incr" %} + ins_encode %{ + __ atomic_addalw(noreg, $incr$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddIConst(indirect mem, iRegINoSp newval, immIAddSub incr) %{ + match(Set newval (GetAndAddI mem incr)); + ins_cost(2*VOLATILE_REF_COST+1); + format %{ "get_and_addI $newval, [$mem], $incr" %} + ins_encode %{ + __ atomic_addw($newval$$Register, $incr$$constant, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddIAcqConst(indirect mem, iRegINoSp newval, immIAddSub incr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set newval (GetAndAddI mem incr)); + ins_cost(VOLATILE_REF_COST+1); + format %{ "get_and_addI_acq $newval, [$mem], $incr" %} + ins_encode %{ + __ atomic_addalw($newval$$Register, $incr$$constant, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddINoResConst(indirect mem, Universe dummy, immIAddSub incr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddI mem incr)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "get_and_addI noreg, [$mem], $incr" %} + ins_encode %{ + __ atomic_addw(noreg, $incr$$constant, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddIAcqNoResConst(indirect mem, Universe dummy, immIAddSub incr) %{ + predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); + match(Set dummy (GetAndAddI mem incr)); + ins_cost(VOLATILE_REF_COST); + format %{ "get_and_addI_acq noreg, [$mem], $incr" %} + ins_encode %{ + __ atomic_addalw(noreg, $incr$$constant, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddL(indirect mem, iRegLNoSp newval, iRegL incr) %{ + match(Set newval (GetAndAddL mem incr)); + ins_cost(2*VOLATILE_REF_COST+1); + format %{ "get_and_addL $newval, [$mem], $incr" %} + ins_encode %{ + __ atomic_add($newval$$Register, $incr$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddLAcq(indirect mem, iRegLNoSp newval, iRegL incr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set newval (GetAndAddL mem incr)); + ins_cost(VOLATILE_REF_COST+1); + format %{ "get_and_addL_acq $newval, [$mem], $incr" %} + ins_encode %{ + __ atomic_addal($newval$$Register, $incr$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddLNoRes(indirect mem, Universe dummy, iRegL incr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddL mem incr)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "get_and_addL noreg, [$mem], $incr" %} + ins_encode %{ + __ atomic_add(noreg, $incr$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddLAcqNoRes(indirect mem, Universe dummy, iRegL incr) %{ + predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); + match(Set dummy (GetAndAddL mem incr)); + ins_cost(VOLATILE_REF_COST); + format %{ "get_and_addL_acq noreg, [$mem], $incr" %} + ins_encode %{ + __ atomic_addal(noreg, $incr$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddLConst(indirect mem, iRegLNoSp newval, immLAddSub incr) %{ + match(Set newval (GetAndAddL mem incr)); + ins_cost(2*VOLATILE_REF_COST+1); + format %{ "get_and_addL $newval, [$mem], $incr" %} + ins_encode %{ + __ atomic_add($newval$$Register, $incr$$constant, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddLAcqConst(indirect mem, iRegLNoSp newval, immLAddSub incr) %{ + predicate(needs_acquiring_load_exclusive(n)); + match(Set newval (GetAndAddL mem incr)); + ins_cost(VOLATILE_REF_COST+1); + format %{ "get_and_addL_acq $newval, [$mem], $incr" %} + ins_encode %{ + __ atomic_addal($newval$$Register, $incr$$constant, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddLNoResConst(indirect mem, Universe dummy, immLAddSub incr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddL mem incr)); + ins_cost(2*VOLATILE_REF_COST); + format %{ "get_and_addL noreg, [$mem], $incr" %} + ins_encode %{ + __ atomic_add(noreg, $incr$$constant, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} + +instruct getAndAddLAcqNoResConst(indirect mem, Universe dummy, immLAddSub incr) %{ + predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); + match(Set dummy (GetAndAddL mem incr)); + ins_cost(VOLATILE_REF_COST); + format %{ "get_and_addL_acq noreg, [$mem], $incr" %} + ins_encode %{ + __ atomic_addal(noreg, $incr$$constant, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%} diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 new file mode 100644 index 00000000000..721b720873a --- /dev/null +++ b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 @@ -0,0 +1,246 @@ +// Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2016, 2021, Red Hat Inc. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +// + +// BEGIN This file is automatically generated. Do not edit -------------- + +// Sundry CAS operations. Note that release is always true, +// regardless of the memory ordering of the CAS. This is because we +// need the volatile case to be sequentially consistent but there is +// no trailing StoreLoad barrier emitted by C2. Unfortunately we +// can't check the type of memory ordering here, so we always emit a +// STLXR. + +// This section is generated from aarch64_atomic_ad.m4 + +dnl Return Arg1 with two spaces before it. We need this because m4 +dnl strips leading spaces from macro args. +define(`INDENT', ` $1')dnl +dnl +dnl +dnl +dnl ====================== CompareAndExchange* +dnl +define(`CAE_INSN1', +` +instruct compareAndExchange$1$7(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ +ifelse($7,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl') + match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); + ins_cost(`'ifelse($7,Acq,,2*)VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchg$5`'ifelse($7,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::$4, /*acquire*/ ifelse($7,Acq,true,false), /*release*/ true, + /*weak*/ false, $res$$Register); + __ $6($res$$Register, $res$$Register); + %} + ins_pipe(pipe_slow); +%}')dnl +define(`CAE_INSN2', +` +instruct compareAndExchange$1$6(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ +ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), + $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), + $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), + `dnl') + match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); + ins_cost(`'ifelse($6,Acq,,2*)VOLATILE_REF_COST); + effect(TEMP_DEF res, KILL cr); + format %{ + "cmpxchg$5`'ifelse($6,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3) if $mem == $oldval then $mem <-- $newval" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true, + /*weak*/ false, $res$$Register); + %} + ins_pipe(pipe_slow); +%}')dnl +dnl +CAE_INSN1(B, I, byte, byte, b, sxtbw, ) +CAE_INSN1(S, I, short, halfword, s, sxthw, ) +CAE_INSN2(I, I, int, word, w, , ) +CAE_INSN2(L, L, long, xword, , , ) +CAE_INSN2(N, N, narrow oop, word, w, , ) +CAE_INSN2(P, P, ptr, xword, , , ) +dnl +CAE_INSN1(B, I, byte, byte, b, sxtbw, Acq) +CAE_INSN1(S, I, short, halfword, s, sxthw, Acq) +CAE_INSN2(I, I, int, word, w, Acq) +CAE_INSN2(L, L, long, xword, , Acq) +CAE_INSN2(N, N, narrow oop, word, w, Acq) +CAE_INSN2(P, P, ptr, xword, , Acq) +dnl +dnl +dnl +dnl ====================== (Weak)CompareAndSwap* +dnl +define(`CAS_INSN1', +` +instruct ifelse($7,Weak,'weakCompare`,'compare`)AndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ +ifelse($6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl') + match(Set res ($7CompareAndSwap$1 mem (Binary oldval newval))); + ins_cost(`'ifelse($6,Acq,,2*)VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg$5`'ifelse($6,Acq,_acq,)`'ifelse($7,Weak,_weak) $res = $mem, $oldval, $newval\t# ($3) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true, + /*weak*/ ifelse($7,Weak,true,false), noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%}')dnl +dnl +define(`CAS_INSN2', +` +instruct ifelse($7,Weak,'weakCompare`,'compare`)AndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ +ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), + $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), + $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), + `dnl') + match(Set res ($7CompareAndSwap$1 mem (Binary oldval newval))); + ins_cost(`'ifelse($6,Acq,,2*)VOLATILE_REF_COST); + effect(KILL cr); + format %{ + "cmpxchg$5`'ifelse($6,Acq,_acq,)`'ifelse($7,Weak,_weak) $res = $mem, $oldval, $newval\t# ($3) if $mem == $oldval then $mem <-- $newval" + "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + ins_encode %{ + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, + Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true, + /*weak*/ ifelse($7,Weak,true,false), noreg); + __ csetw($res$$Register, Assembler::EQ); + %} + ins_pipe(pipe_slow); +%}')dnl +dnl +CAS_INSN1(B, I, byte, byte, b, , ) +CAS_INSN1(S, I, short, halfword, s, , ) +CAS_INSN2(I, I, int, word, w, , ) +CAS_INSN2(L, L, long, xword, , , ) +CAS_INSN2(N, N, narrow oop, word, w, , ) +CAS_INSN2(P, P, ptr, xword, , , ) +dnl +CAS_INSN1(B, I, byte, byte, b, Acq, ) +CAS_INSN1(S, I, short, halfword, s, Acq, ) +CAS_INSN2(I, I, int, word, w, Acq, ) +CAS_INSN2(L, L, long, xword, , Acq, ) +CAS_INSN2(N, N, narrow oop, word, w, Acq, ) +CAS_INSN2(P, P, ptr, xword, , Acq, ) +dnl +CAS_INSN1(B, I, byte, byte, b, , Weak) +CAS_INSN1(S, I, short, halfword, s, , Weak) +CAS_INSN2(I, I, int, word, w, , Weak) +CAS_INSN2(L, L, long, xword, , , Weak) +CAS_INSN2(N, N, narrow oop, word, w, , Weak) +CAS_INSN2(P, P, ptr, xword, , , Weak) +dnl +CAS_INSN1(B, I, byte, byte, b, Acq, Weak) +CAS_INSN1(S, I, short, halfword, s, Acq, Weak) +CAS_INSN2(I, I, int, word, w, Acq, Weak) +CAS_INSN2(L, L, long, xword, , Acq, Weak) +CAS_INSN2(N, N, narrow oop, word, w, Acq, Weak) +CAS_INSN2(P, P, ptr, xword, , Acq, Weak) +dnl +dnl +dnl +dnl ====================== GetAndSet* +dnl +define(`GAS_INSN1', +` +instruct getAndSet$1$3(indirect mem, iReg$1 newval, iReg$1NoSp oldval) %{ +ifelse($1$3,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), + $1$3,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), + $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $3,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), + `dnl') + match(Set oldval (GetAndSet$1 mem newval)); + ins_cost(`'ifelse($4,Acq,,2*)VOLATILE_REF_COST); + format %{ "atomic_xchg$2`'ifelse($3,Acq,_acq) $oldval, $newval, [$mem]" %} + ins_encode %{ + __ atomic_xchg`'ifelse($3,Acq,al)$2($oldval$$Register, $newval$$Register, as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%}')dnl +dnl +GAS_INSN1(I, w, ) +GAS_INSN1(L, , ) +GAS_INSN1(N, w, ) +GAS_INSN1(P, , ) +dnl +GAS_INSN1(I, w, Acq) +GAS_INSN1(L, , Acq) +GAS_INSN1(N, w, Acq) +GAS_INSN1(P, , Acq) +dnl +dnl +dnl +dnl ====================== GetAndAdd* +dnl +define(`GAA_INSN1', +` +instruct getAndAdd$1$4$5$6(indirect mem, `'ifelse($5,NoRes,Universe dummy,iReg$1NoSp newval), `'ifelse($6,Const,imm$1AddSub incr,iReg$2 incr)) %{ +ifelse($4$5,AcqNoRes,INDENT(predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));), + $5,NoRes,INDENT(predicate(n->as_LoadStore()->result_not_used());), + $4,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), + `dnl') + match(Set ifelse($5,NoRes,dummy,newval) (GetAndAdd$1 mem incr)); + ins_cost(`'ifelse($4,Acq,,2*)VOLATILE_REF_COST`'ifelse($5,NoRes,,+1)); + format %{ "get_and_add$1`'ifelse($4,Acq,_acq) `'ifelse($5,NoRes,noreg,$newval), [$mem], $incr" %} + ins_encode %{ + __ atomic_add`'ifelse($4,Acq,al)$3(`'ifelse($5,NoRes,noreg,$newval$$Register), `'ifelse($6,Const,$incr$$constant,$incr$$Register), as_Register($mem$$base)); + %} + ins_pipe(pipe_serial); +%}')dnl +dnl +dnl +GAA_INSN1(I, IorL2I, w, , , ) +GAA_INSN1(I, IorL2I, w, Acq, , ) +GAA_INSN1(I, IorL2I, w, , NoRes, ) +GAA_INSN1(I, IorL2I, w, Acq, NoRes, ) +GAA_INSN1(I, I, w, , , Const) +GAA_INSN1(I, I, w, Acq, , Const) +GAA_INSN1(I, I, w, , NoRes, Const) +GAA_INSN1(I, I, w, Acq, NoRes, Const) +dnl +GAA_INSN1(L, L, , , , ) +GAA_INSN1(L, L, , Acq, , ) +GAA_INSN1(L, L, , , NoRes, ) +GAA_INSN1(L, L, , Acq, NoRes, ) +GAA_INSN1(L, L, , , , Const) +GAA_INSN1(L, L, , Acq, , Const) +GAA_INSN1(L, L, , , NoRes, Const) +GAA_INSN1(L, L, , Acq, NoRes, Const) +dnl diff --git a/src/hotspot/cpu/aarch64/cas.m4 b/src/hotspot/cpu/aarch64/cas.m4 deleted file mode 100644 index 7e13e153db1..00000000000 --- a/src/hotspot/cpu/aarch64/cas.m4 +++ /dev/null @@ -1,161 +0,0 @@ -dnl Copyright (c) 2016, 2021, Red Hat Inc. All rights reserved. -dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -dnl -dnl This code is free software; you can redistribute it and/or modify it -dnl under the terms of the GNU General Public License version 2 only, as -dnl published by the Free Software Foundation. -dnl -dnl This code is distributed in the hope that it will be useful, but WITHOUT -dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -dnl version 2 for more details (a copy is included in the LICENSE file that -dnl accompanied this code). -dnl -dnl You should have received a copy of the GNU General Public License version -dnl 2 along with this work; if not, write to the Free Software Foundation, -dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -dnl -dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -dnl or visit www.oracle.com if you need additional information or have any -dnl questions. -dnl -dnl -dnl Process this file with m4 cas.m4 to generate the CAE and wCAS -dnl instructions used in aarch64.ad. -dnl - -// BEGIN This section of the file is automatically generated. Do not edit -------------- - -// Sundry CAS operations. Note that release is always true, -// regardless of the memory ordering of the CAS. This is because we -// need the volatile case to be sequentially consistent but there is -// no trailing StoreLoad barrier emitted by C2. Unfortunately we -// can't check the type of memory ordering here, so we always emit a -// STLXR. - -// This section is generated from cas.m4 - -dnl Return Arg1 with two spaces before it. We need this because m4 -dnl strips leading spaces from macro args. -define(`INDENT', ` $1')dnl -dnl -define(`CAS_INSN', -` -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchange$1$6(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ -ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), - $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), - $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), - $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), - $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), - `dnl') - match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); - ifelse($6,Acq,'ins_cost(VOLATILE_REF_COST);`,'ins_cost(2 * VOLATILE_REF_COST);`) - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchg$5`'ifelse($6,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true, - /*weak*/ false, $res$$Register); - %} - ins_pipe(pipe_slow); -%}')dnl -define(`CAS_INSN4', -` -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct compareAndExchange$1$7(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ -ifelse($7,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl') - match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); - ifelse($7,Acq,'ins_cost(VOLATILE_REF_COST);`,'ins_cost(2 * VOLATILE_REF_COST);`) - effect(TEMP_DEF res, KILL cr); - format %{ - "cmpxchg$5`'ifelse($7,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::$4, /*acquire*/ ifelse($7,Acq,true,false), /*release*/ true, - /*weak*/ false, $res$$Register); - __ $6($res$$Register, $res$$Register); - %} - ins_pipe(pipe_slow); -%}')dnl -CAS_INSN4(B,I,byte,byte,b,sxtbw) -CAS_INSN4(S,I,short,halfword,s,sxthw) -CAS_INSN(I,I,int,word,w) -CAS_INSN(L,L,long,xword) -CAS_INSN(N,N,narrow oop,word,w) -CAS_INSN(P,P,ptr,xword) -dnl -CAS_INSN4(B,I,byte,byte,b,sxtbw,Acq) -CAS_INSN4(S,I,short,halfword,s,sxthw,Acq) -CAS_INSN(I,I,int,word,w,Acq) -CAS_INSN(L,L,long,xword,,Acq) -CAS_INSN(N,N,narrow oop,word,w,Acq) -CAS_INSN(P,P,ptr,xword,,Acq) -dnl -define(`CAS_INSN2', -` -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ -ifelse($6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl') - match(Set res (WeakCompareAndSwap$1 mem (Binary oldval newval))); - ifelse($6,Acq,'ins_cost(VOLATILE_REF_COST);`,'ins_cost(2 * VOLATILE_REF_COST);`) - effect(KILL cr); - format %{ - "cmpxchg$5`'ifelse($6,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%}')dnl -define(`CAS_INSN3', -` -// This pattern is generated automatically from cas.m4. -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE -instruct weakCompareAndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ -ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), - $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), - $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), - $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), - $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), - `dnl') - match(Set res (WeakCompareAndSwap$1 mem (Binary oldval newval))); - ifelse($6,Acq,'ins_cost(VOLATILE_REF_COST);`,'ins_cost(2 * VOLATILE_REF_COST);`) - effect(KILL cr); - format %{ - "cmpxchg$5`'ifelse($6,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, - Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true, - /*weak*/ true, noreg); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%}')dnl -CAS_INSN2(B,I,byte,byte,b) -CAS_INSN2(S,I,short,halfword,s) -CAS_INSN3(I,I,int,word,w) -CAS_INSN3(L,L,long,xword) -CAS_INSN3(N,N,narrow oop,word,w) -CAS_INSN3(P,P,ptr,xword) -CAS_INSN2(B,I,byte,byte,b,Acq) -CAS_INSN2(S,I,short,halfword,s,Acq) -CAS_INSN3(I,I,int,word,w,Acq) -CAS_INSN3(L,L,long,xword,,Acq) -CAS_INSN3(N,N,narrow oop,word,w,Acq) -CAS_INSN3(P,P,ptr,xword,,Acq) -dnl - -// END This section of the file is automatically generated. Do not edit -------------- diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index af010caf616..606275d7666 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -1063,6 +1063,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) { return false; } +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) { + return false; +} + bool Matcher::is_generic_vector(MachOper* opnd) { ShouldNotReachHere(); // generic vector operands not supported return false; diff --git a/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp b/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp index a0ff19e6171..c4529b0eb1a 100644 --- a/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp +++ b/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp @@ -157,6 +157,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va return result; } +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + template<> template inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest, diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 762536df07f..87fcf112756 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -2383,6 +2383,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) { return false; } +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) { + return false; +} + bool Matcher::is_generic_vector(MachOper* opnd) { ShouldNotReachHere(); // generic vector operands not supported return false; diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index bb2ed57ef82..3f5dd4ad0ee 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -2053,6 +2053,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) { return false; } +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) { + return false; +} + bool Matcher::is_generic_vector(MachOper* opnd) { ShouldNotReachHere(); // generic vector operands not supported return false; diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 6fe051b55c7..7d3e963a108 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1865,6 +1865,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) { return false; } +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) { + return false; +} + bool Matcher::is_generic_vector(MachOper* opnd) { ShouldNotReachHere(); // generic vector operands not supported return false; diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index 586135fcebc..34de9403ccf 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -89,10 +89,10 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) { - Label done; + Label L_done; __ testptr(count, count); - __ jcc(Assembler::zero, done); + __ jccb(Assembler::zero, L_done); // Calculate end address in "count". Address::ScaleFactor scale = UseCompressedOops ? Address::times_4 : Address::times_8; @@ -111,31 +111,31 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ shrptr(count, CardTable::card_shift()); __ addptr(count, tmp); - Label loop; + Label L_loop; // Iterate from start card to end card (inclusive). - __ bind(loop); + __ bind(L_loop); - Label is_clean_card; + Label L_is_clean_card; if (UseCondCardMark) { __ cmpb(Address(addr, 0), G1CardTable::clean_card_val()); - __ jcc(Assembler::equal, is_clean_card); + __ jccb(Assembler::equal, L_is_clean_card); } else { __ movb(Address(addr, 0), G1CardTable::dirty_card_val()); } - Label next_card; - __ bind(next_card); + Label L_next_card; + __ bind(L_next_card); __ addptr(addr, sizeof(CardTable::CardValue)); __ cmpptr(addr, count); - __ jcc(Assembler::belowEqual, loop); - __ jmp(done); + __ jccb(Assembler::belowEqual, L_loop); + __ jmpb(L_done); - __ bind(is_clean_card); - // Card was clean. Dirty card and go to next.. + __ bind(L_is_clean_card); + // Card was clean. Dirty card and go to next. __ movb(Address(addr, 0), G1CardTable::dirty_card_val()); - __ jmp(next_card); + __ jmpb(L_next_card); - __ bind(done); + __ bind(L_done); } void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, @@ -157,22 +157,6 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator } } -static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, - const Register thread, const Register value, const Register temp) { - // This code assumes that buffer index is pointer sized. - STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t)); - // Can we store a value in the given thread's buffer? - // (The index field is typed as size_t.) - __ movptr(temp, Address(thread, in_bytes(index_offset))); // temp := *(index address) - __ testptr(temp, temp); // index == 0? - __ jcc(Assembler::zero, runtime); // jump to runtime if index == 0 (full buffer) - // The buffer is not full, store value into it. - __ subptr(temp, wordSize); // temp := next index - __ movptr(Address(thread, in_bytes(index_offset)), temp); // *(index address) := next index - __ addptr(temp, Address(thread, in_bytes(buffer_offset))); // temp := buffer address + next index - __ movptr(Address(temp, 0), value); // *(buffer address + next index) := value -} - static void generate_pre_barrier_fast_path(MacroAssembler* masm, const Register thread) { Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); @@ -190,21 +174,40 @@ static void generate_pre_barrier_slow_path(MacroAssembler* masm, const Register pre_val, const Register thread, const Register tmp, - Label& done, - Label& runtime) { + Label& L_done) { + Address index_addr(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); + Address buffer_addr(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); + + // This code assumes that buffer index is pointer sized. + STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t)); + + Label L_runtime; + // Do we need to load the previous value? if (obj != noreg) { __ load_heap_oop(pre_val, Address(obj, 0), noreg, AS_RAW); } + // Is the previous value null? - __ cmpptr(pre_val, NULL_WORD); - __ jcc(Assembler::equal, done); - generate_queue_insertion(masm, - G1ThreadLocalData::satb_mark_queue_index_offset(), - G1ThreadLocalData::satb_mark_queue_buffer_offset(), - runtime, - thread, pre_val, tmp); - __ jmp(done); + __ testptr(pre_val, pre_val); + __ jcc(Assembler::equal, L_done); + + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ movptr(tmp, index_addr); // temp := *(index address) + __ testptr(tmp, tmp); // index == 0? + __ jccb(Assembler::zero, L_runtime); // jump to runtime if index == 0 (full buffer) + + // The buffer is not full, store value into it. + __ subptr(tmp, wordSize); // temp := next index + __ movptr(index_addr, tmp); // *(index address) := next index + __ addptr(tmp, buffer_addr); // temp := buffer address + next index + __ movptr(Address(tmp, 0), pre_val); // *(buffer address + next index) := value + + // Jump out if done, or fall-through to runtime. + // "L_done" is far away, so jump cannot be short. + __ jmp(L_done); + __ bind(L_runtime); } void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, @@ -219,7 +222,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, const Register thread = r15_thread; Label done; - Label runtime; assert(pre_val != noreg, "check this code"); @@ -231,9 +233,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, generate_pre_barrier_fast_path(masm, thread); // If marking is not active (*(mark queue active address) == 0), jump to done __ jcc(Assembler::equal, done); - generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done, runtime); - - __ bind(runtime); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done); // Determine and save the live input values __ push_call_clobbered_registers(); @@ -272,23 +272,23 @@ static void generate_post_barrier(MacroAssembler* masm, const Register store_addr, const Register new_val, const Register tmp1, - Label& done, bool new_val_may_be_null) { assert_different_registers(store_addr, new_val, tmp1, noreg); Register thread = r15_thread; + Label L_done; // Does store cross heap regions? __ movptr(tmp1, store_addr); // tmp1 := store address __ xorptr(tmp1, new_val); // tmp1 := store address ^ new value __ shrptr(tmp1, G1HeapRegion::LogOfHRGrainBytes); // ((store address ^ new value) >> LogOfHRGrainBytes) == 0? - __ jcc(Assembler::equal, done); + __ jccb(Assembler::equal, L_done); // Crosses regions, storing null? if (new_val_may_be_null) { - __ cmpptr(new_val, NULL_WORD); // new value == null? - __ jcc(Assembler::equal, done); + __ testptr(new_val, new_val); // new value == null? + __ jccb(Assembler::equal, L_done); } __ movptr(tmp1, store_addr); // tmp1 := store address @@ -298,20 +298,19 @@ static void generate_post_barrier(MacroAssembler* masm, __ addptr(tmp1, card_table_addr); // tmp1 := card address if (UseCondCardMark) { __ cmpb(Address(tmp1, 0), G1CardTable::clean_card_val()); // *(card address) == clean_card_val? - __ jcc(Assembler::notEqual, done); + __ jccb(Assembler::notEqual, L_done); } // Storing a region crossing, non-null oop, card is clean. // Dirty card. __ movb(Address(tmp1, 0), G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val + __ bind(L_done); } void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp) { - Label done; - generate_post_barrier(masm, store_addr, new_val, tmp, done, true /* new_val_may_be_null */); - __ bind(done); + generate_post_barrier(masm, store_addr, new_val, tmp, true /* new_val_may_be_null */); } #if defined(COMPILER2) @@ -354,7 +353,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, G1PreBarrierStubC2* stub) const { Assembler::InlineSkippedInstructionsCounter skip_counter(masm); - Label runtime; Register obj = stub->obj(); Register pre_val = stub->pre_val(); Register thread = stub->thread(); @@ -362,9 +360,8 @@ void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, assert(stub->tmp2() == noreg, "not needed in this platform"); __ bind(*stub->entry()); - generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation(), runtime); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation()); - __ bind(runtime); generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); __ jmp(*stub->continuation()); } @@ -374,9 +371,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, Register new_val, Register tmp, bool new_val_may_be_null) { - Label done; - generate_post_barrier(masm, store_addr, new_val, tmp, done, new_val_may_be_null); - __ bind(done); + generate_post_barrier(masm, store_addr, new_val, tmp, new_val_may_be_null); } #endif // COMPILER2 @@ -449,7 +444,7 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/); } - __ cmpptr(pre_val_reg, NULL_WORD); + __ testptr(pre_val_reg, pre_val_reg); __ jcc(Assembler::equal, *stub->continuation()); ce->store_parameter(stub->pre_val()->as_register(), 0); __ call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); @@ -465,9 +460,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm, Register thread, Register tmp1, Register tmp2 /* unused on x86 */) { - Label done; - generate_post_barrier(masm, store_addr, new_val, tmp1, done, true /* new_val_may_be_null */); - masm->bind(done); + generate_post_barrier(masm, store_addr, new_val, tmp1, true /* new_val_may_be_null */); } #define __ sasm-> @@ -490,8 +483,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - Label done; - Label runtime; + Label L_done, L_runtime; // Is marking still active? if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { @@ -500,13 +492,13 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); __ cmpb(queue_active, 0); } - __ jcc(Assembler::equal, done); + __ jcc(Assembler::equal, L_done); // Can we store original value in the thread's buffer? __ movptr(tmp, queue_index); __ testptr(tmp, tmp); - __ jcc(Assembler::zero, runtime); + __ jccb(Assembler::zero, L_runtime); __ subptr(tmp, wordSize); __ movptr(queue_index, tmp); __ addptr(tmp, buffer); @@ -514,9 +506,9 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* // prev_val (rax) __ load_parameter(0, pre_val); __ movptr(Address(tmp, 0), pre_val); - __ jmp(done); + __ jmp(L_done); - __ bind(runtime); + __ bind(L_runtime); __ push_call_clobbered_registers(); @@ -526,7 +518,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* __ pop_call_clobbered_registers(); - __ bind(done); + __ bind(L_done); __ pop_ppx(rdx); __ pop_ppx(rax); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index f0726ded7e5..1e728ffa279 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -3524,10 +3524,10 @@ void StubGenerator::aesgcm_avx512(Register in, Register len, Register ct, Regist false, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32); ghash16_avx512(false, true, false, false, true, in, pos, avx512_subkeyHtbl, AAD_HASHx, SHUF_MASK, stack_offset, 16 * 16, 0, HashKey_16); + __ addl(pos, 16 * 16); __ bind(MESG_BELOW_32_BLKS); __ subl(len, 16 * 16); - __ addl(pos, 16 * 16); gcm_enc_dec_last_avx512(len, in, pos, AAD_HASHx, SHUF_MASK, avx512_subkeyHtbl, ghashin_offset, HashKey_16, true, true); __ bind(GHASH_DONE); @@ -4016,13 +4016,15 @@ void StubGenerator::aesgcm_avx2(Register in, Register len, Register ct, Register const Register rounds = r10; const XMMRegister ctr_blockx = xmm9; const XMMRegister aad_hashx = xmm8; - Label encrypt_done, encrypt_by_8_new, encrypt_by_8; + Label encrypt_done, encrypt_by_8_new, encrypt_by_8, exit; //This routine should be called only for message sizes of 128 bytes or more. //Macro flow: //process 8 16 byte blocks in initial_num_blocks. //process 8 16 byte blocks at a time until all are done 'encrypt_by_8_new followed by ghash_last_8' __ xorl(pos, pos); + __ cmpl(len, 128); + __ jcc(Assembler::less, exit); //Generate 8 constants for htbl generateHtbl_8_block_avx2(subkeyHtbl); @@ -4090,6 +4092,7 @@ void StubGenerator::aesgcm_avx2(Register in, Register len, Register ct, Register __ vpxor(xmm0, xmm0, xmm0, Assembler::AVX_128bit); __ vpxor(xmm13, xmm13, xmm13, Assembler::AVX_128bit); + __ bind(exit); } #undef __ diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index be9889b0a99..1d393897bca 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -2633,6 +2633,70 @@ bool Matcher::supports_vector_calling_convention(void) { return EnableVectorSupport; } +static bool is_ndd_demotable(const MachNode* mdef) { + return ((mdef->flags() & Node::PD::Flag_ndd_demotable) != 0); +} + +static bool is_ndd_demotable_commutative(const MachNode* mdef) { + return ((mdef->flags() & Node::PD::Flag_ndd_demotable_commutative) != 0); +} + +static bool is_demotion_candidate(const MachNode* mdef) { + return (is_ndd_demotable(mdef) || is_ndd_demotable_commutative(mdef)); +} + +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, + int oper_index) { + if (mdef == nullptr) { + return false; + } + + if (mdef->num_opnds() <= oper_index || mdef->operand_index(oper_index) < 0 || + mdef->in(mdef->operand_index(oper_index)) == nullptr) { + assert(oper_index != 1 || !is_demotion_candidate(mdef), "%s", mdef->Name()); + assert(oper_index != 2 || !is_ndd_demotable_commutative(mdef), "%s", mdef->Name()); + return false; + } + + // Complex memory operand covers multiple incoming edges needed for + // address computation. Biasing def towards any address component will not + // result in NDD demotion by assembler. + if (mdef->operand_num_edges(oper_index) != 1) { + assert(!is_ndd_demotable(mdef), "%s", mdef->Name()); + return false; + } + + // Demotion candidate must be register mask compatible with definition. + const RegMask& oper_mask = mdef->in_RegMask(mdef->operand_index(oper_index)); + if (!oper_mask.overlap(mdef->out_RegMask())) { + assert(!is_demotion_candidate(mdef), "%s", mdef->Name()); + return false; + } + + switch (oper_index) { + // First operand of MachNode corresponding to Intel APX NDD selection + // pattern can share its assigned register with definition operand if + // their live ranges do not overlap. In such a scenario we can demote + // it to legacy map0/map1 instruction by replacing its 4-byte extended + // EVEX prefix with shorter REX/REX2 encoding. Demotion candidates + // are decorated with a special flag by instruction selector. + case 1: + return is_demotion_candidate(mdef); + + // Definition operand of commutative operation can be biased towards second + // operand. + case 2: + return is_ndd_demotable_commutative(mdef); + + // Current scheme only selects up to two biasing candidates + default: + assert(false, "unhandled operand index: %s", mdef->Name()); + break; + } + + return false; +} + OptoRegPair Matcher::vector_return_value(uint ideal_reg) { assert(EnableVectorSupport, "sanity"); int lo = XMM0_num; @@ -2812,7 +2876,7 @@ static inline bool is_clz_non_subword_predicate_evex(BasicType bt, int vlen_byte class Node::PD { public: - enum NodeFlags { + enum NodeFlags : uint64_t { Flag_intel_jcc_erratum = Node::_last_flag << 1, Flag_sets_carry_flag = Node::_last_flag << 2, Flag_sets_parity_flag = Node::_last_flag << 3, @@ -2824,7 +2888,9 @@ public: Flag_clears_zero_flag = Node::_last_flag << 9, Flag_clears_overflow_flag = Node::_last_flag << 10, Flag_clears_sign_flag = Node::_last_flag << 11, - _last_flag = Flag_clears_sign_flag + Flag_ndd_demotable = Node::_last_flag << 12, + Flag_ndd_demotable_commutative = Node::_last_flag << 13, + _last_flag = Flag_ndd_demotable_commutative }; }; @@ -9801,7 +9867,7 @@ instruct addI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (AddI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative); format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -9829,7 +9895,7 @@ instruct addI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (AddI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -9872,7 +9938,7 @@ instruct addI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (AddI src1 (LoadI src2))); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative); ins_cost(150); format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} @@ -9929,6 +9995,7 @@ instruct incI_rReg_ndd(rRegI dst, rRegI src, immI_1 val, rFlagsReg cr) predicate(UseAPX && UseIncDec); match(Set dst (AddI src val)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "eincl $dst, $src\t# int ndd" %} ins_encode %{ @@ -9983,6 +10050,7 @@ instruct decI_rReg_ndd(rRegI dst, rRegI src, immI_M1 val, rFlagsReg cr) predicate(UseAPX && UseIncDec); match(Set dst (AddI src val)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "edecl $dst, $src\t# int ndd" %} ins_encode %{ @@ -10089,7 +10157,7 @@ instruct addL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (AddL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative); format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -10117,7 +10185,7 @@ instruct addL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr predicate(UseAPX); match(Set dst (AddL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -10160,7 +10228,7 @@ instruct addL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (AddL src1 (LoadL src2))); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative); ins_cost(150); format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} @@ -10216,6 +10284,7 @@ instruct incL_rReg_ndd(rRegL dst, rRegI src, immL1 val, rFlagsReg cr) predicate(UseAPX && UseIncDec); match(Set dst (AddL src val)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "eincq $dst, $src\t# long ndd" %} ins_encode %{ @@ -10270,6 +10339,7 @@ instruct decL_rReg_ndd(rRegL dst, rRegL src, immL_M1 val, rFlagsReg cr) predicate(UseAPX && UseIncDec); match(Set dst (AddL src val)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "edecq $dst, $src\t# long ndd" %} ins_encode %{ @@ -10984,7 +11054,7 @@ instruct subI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (SubI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "esubl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -10998,7 +11068,7 @@ instruct subI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (SubI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "esubl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -11041,7 +11111,7 @@ instruct subI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (SubI src1 (LoadI src2))); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); ins_cost(150); format %{ "esubl $dst, $src1, $src2\t# int ndd" %} @@ -11099,7 +11169,7 @@ instruct subL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (SubL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "esubq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -11113,7 +11183,7 @@ instruct subL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr predicate(UseAPX); match(Set dst (SubL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "esubq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -11156,7 +11226,7 @@ instruct subL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (SubL src1 (LoadL src2))); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); ins_cost(150); format %{ "esubq $dst, $src1, $src2\t# long ndd" %} @@ -11228,7 +11298,7 @@ instruct negI_rReg_ndd(rRegI dst, rRegI src, immI_0 zero, rFlagsReg cr) predicate(UseAPX); match(Set dst (SubI zero src)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "enegl $dst, $src\t# int ndd" %} ins_encode %{ @@ -11256,7 +11326,7 @@ instruct negI_rReg_2_ndd(rRegI dst, rRegI src, rFlagsReg cr) predicate(UseAPX); match(Set dst (NegI src)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "enegl $dst, $src\t# int ndd" %} ins_encode %{ @@ -11297,7 +11367,7 @@ instruct negL_rReg_ndd(rRegL dst, rRegL src, immL0 zero, rFlagsReg cr) predicate(UseAPX); match(Set dst (SubL zero src)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "enegq $dst, $src\t# long ndd" %} ins_encode %{ @@ -11325,7 +11395,7 @@ instruct negL_rReg_2_ndd(rRegL dst, rRegL src, rFlagsReg cr) predicate(UseAPX); match(Set dst (NegL src)); effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable); format %{ "enegq $dst, $src\t# long ndd" %} ins_encode %{ @@ -11370,6 +11440,7 @@ instruct mulI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (MulI src1 src2)); effect(KILL cr); + flag(PD::Flag_ndd_demotable_commutative); ins_cost(300); format %{ "eimull $dst, $src1, $src2\t# int ndd" %} @@ -11411,6 +11482,7 @@ instruct mulI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (MulI src1 (LoadI src2))); effect(KILL cr); + flag(PD::Flag_ndd_demotable); ins_cost(350); format %{ "eimull $dst, $src1, $src2\t# int ndd" %} @@ -11462,6 +11534,7 @@ instruct mulL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (MulL src1 src2)); effect(KILL cr); + flag(PD::Flag_ndd_demotable_commutative); ins_cost(300); format %{ "eimulq $dst, $src1, $src2\t# long ndd" %} @@ -11503,6 +11576,7 @@ instruct mulL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (MulL src1 (LoadL src2))); effect(KILL cr); + flag(PD::Flag_ndd_demotable_commutative); ins_cost(350); format %{ "eimulq $dst, $src1, $src2 \t# long" %} @@ -11777,6 +11851,7 @@ instruct salI_rReg_immI2_ndd(rRegI dst, rRegI src, immI2 shift, rFlagsReg cr) predicate(UseAPX); match(Set dst (LShiftI src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "esall $dst, $src, $shift\t# int(ndd)" %} ins_encode %{ @@ -11805,6 +11880,7 @@ instruct salI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr) predicate(UseAPX); match(Set dst (LShiftI src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "esall $dst, $src, $shift\t# int (ndd)" %} ins_encode %{ @@ -11911,6 +11987,7 @@ instruct sarI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr) predicate(UseAPX); match(Set dst (RShiftI src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "esarl $dst, $src, $shift\t# int (ndd)" %} ins_encode %{ @@ -12017,6 +12094,7 @@ instruct shrI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr) predicate(UseAPX); match(Set dst (URShiftI src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "eshrl $dst, $src, $shift\t # int (ndd)" %} ins_encode %{ @@ -12124,6 +12202,7 @@ instruct salL_rReg_immI2_ndd(rRegL dst, rRegL src, immI2 shift, rFlagsReg cr) predicate(UseAPX); match(Set dst (LShiftL src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "esalq $dst, $src, $shift\t# long (ndd)" %} ins_encode %{ @@ -12152,6 +12231,7 @@ instruct salL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr) predicate(UseAPX); match(Set dst (LShiftL src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "esalq $dst, $src, $shift\t# long (ndd)" %} ins_encode %{ @@ -12258,6 +12338,7 @@ instruct sarL_rReg_imm_ndd(rRegL dst, rRegL src, immI shift, rFlagsReg cr) predicate(UseAPX); match(Set dst (RShiftL src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "esarq $dst, $src, $shift\t# long (ndd)" %} ins_encode %{ @@ -12364,6 +12445,7 @@ instruct shrL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr) predicate(UseAPX); match(Set dst (URShiftL src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "eshrq $dst, $src, $shift\t# long (ndd)" %} ins_encode %{ @@ -12535,6 +12617,7 @@ instruct rolI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr) predicate(UseAPX && n->bottom_type()->basic_type() == T_INT); match(Set dst (RotateLeft src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "eroll $dst, $src, $shift\t# rotate left (int ndd)" %} ins_encode %{ @@ -12599,6 +12682,7 @@ instruct rorI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr) predicate(UseAPX && n->bottom_type()->basic_type() == T_INT); match(Set dst (RotateRight src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "erorl $dst, $src, $shift\t# rotate right(int ndd)" %} ins_encode %{ @@ -12651,6 +12735,7 @@ instruct rolL_rReg_Var(rRegL dst, rcx_RegI shift, rFlagsReg cr) predicate(!UseAPX && n->bottom_type()->basic_type() == T_LONG); match(Set dst (RotateLeft dst shift)); effect(KILL cr); + format %{ "rolq $dst, $shift" %} ins_encode %{ __ rolq($dst$$Register); @@ -12664,6 +12749,7 @@ instruct rolL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr) predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG); match(Set dst (RotateLeft src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "erolq $dst, $src, $shift\t# rotate left(long ndd)" %} ins_encode %{ @@ -12728,6 +12814,7 @@ instruct rorL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr) predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG); match(Set dst (RotateRight src shift)); effect(KILL cr); + flag(PD::Flag_ndd_demotable); format %{ "erorq $dst, $src, $shift\t# rotate right(long ndd)" %} ins_encode %{ @@ -12805,7 +12892,7 @@ instruct andI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (AndI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); format %{ "eandl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -12898,7 +12985,7 @@ instruct andI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (AndI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); format %{ "eandl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -12942,7 +13029,7 @@ instruct andI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (AndI src1 (LoadI src2))); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); ins_cost(150); format %{ "eandl $dst, $src1, $src2\t# int ndd" %} @@ -13142,7 +13229,7 @@ instruct orI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (OrI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); format %{ "eorl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -13171,7 +13258,7 @@ instruct orI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (OrI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); format %{ "eorl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -13185,7 +13272,7 @@ instruct orI_rReg_imm_rReg_ndd(rRegI dst, immI src1, rRegI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (OrI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); format %{ "eorl $dst, $src2, $src1\t# int ndd" %} ins_encode %{ @@ -13229,7 +13316,7 @@ instruct orI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (OrI src1 (LoadI src2))); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); ins_cost(150); format %{ "eorl $dst, $src1, $src2\t# int ndd" %} @@ -13305,7 +13392,7 @@ instruct xorI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (XorI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); format %{ "exorl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -13331,6 +13418,7 @@ instruct xorI_rReg_im1_ndd(rRegI dst, rRegI src, immI_M1 imm) %{ match(Set dst (XorI src imm)); predicate(UseAPX); + flag(PD::Flag_ndd_demotable); format %{ "enotl $dst, $src" %} ins_encode %{ @@ -13361,7 +13449,7 @@ instruct xorI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) predicate(UseAPX && n->in(2)->bottom_type()->is_int()->get_con() != -1); match(Set dst (XorI src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); format %{ "exorl $dst, $src1, $src2\t# int ndd" %} ins_encode %{ @@ -13407,7 +13495,7 @@ instruct xorI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (XorI src1 (LoadI src2))); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); ins_cost(150); format %{ "exorl $dst, $src1, $src2\t# int ndd" %} @@ -13486,7 +13574,7 @@ instruct andL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (AndL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); format %{ "eandq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -13542,7 +13630,7 @@ instruct andL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr predicate(UseAPX); match(Set dst (AndL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); format %{ "eandq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -13586,7 +13674,7 @@ instruct andL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (AndL src1 (LoadL src2))); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); ins_cost(150); format %{ "eandq $dst, $src1, $src2\t# long ndd" %} @@ -13789,7 +13877,7 @@ instruct orL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (OrL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); format %{ "eorq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -13844,7 +13932,7 @@ instruct orL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (OrL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); format %{ "eorq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -13858,7 +13946,7 @@ instruct orL_rReg_imm_rReg_ndd(rRegL dst, immL32 src1, rRegL src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (OrL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); format %{ "eorq $dst, $src2, $src1\t# long ndd" %} ins_encode %{ @@ -13903,7 +13991,7 @@ instruct orL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (OrL src1 (LoadL src2))); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); ins_cost(150); format %{ "eorq $dst, $src1, $src2\t# long ndd" %} @@ -13982,7 +14070,7 @@ instruct xorL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) predicate(UseAPX); match(Set dst (XorL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); format %{ "exorq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -14008,6 +14096,7 @@ instruct xorL_rReg_im1_ndd(rRegL dst,rRegL src, immL_M1 imm) %{ predicate(UseAPX); match(Set dst (XorL src imm)); + flag(PD::Flag_ndd_demotable); format %{ "enotq $dst, $src" %} ins_encode %{ @@ -14038,7 +14127,7 @@ instruct xorL_rReg_rReg_imm(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) predicate(UseAPX && n->in(2)->bottom_type()->is_long()->get_con() != -1L); match(Set dst (XorL src1 src2)); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable); format %{ "exorq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ @@ -14084,7 +14173,7 @@ instruct xorL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr predicate(UseAPX); match(Set dst (XorL src1 (LoadL src2))); effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative); ins_cost(150); format %{ "exorq $dst, $src1, $src2\t# long ndd" %} @@ -16539,6 +16628,7 @@ instruct minI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2) predicate(UseAPX); match(Set dst (MinI src1 src2)); effect(DEF dst, USE src1, USE src2); + flag(PD::Flag_ndd_demotable); ins_cost(200); expand %{ @@ -16590,6 +16680,7 @@ instruct maxI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2) predicate(UseAPX); match(Set dst (MaxI src1 src2)); effect(DEF dst, USE src1, USE src2); + flag(PD::Flag_ndd_demotable); ins_cost(200); expand %{ diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 48bd5e05816..7de031cac58 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1038,6 +1038,8 @@ static void* dll_load_library(const char *filename, int *eno, char *ebuf, int eb dflags |= RTLD_MEMBER; } + Events::log_dll_message(nullptr, "Attempting to load shared library %s", filename); + void* result; const char* error_report = nullptr; JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 0b37cb100f6..0889cc4cdf8 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1035,6 +1035,8 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebu int rtn = fegetenv(&default_fenv); assert(rtn == 0, "fegetenv must succeed"); + Events::log_dll_message(nullptr, "Attempting to load shared library %s", filename); + void* result; JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) result = ::dlopen(filename, RTLD_LAZY); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 30033903ca3..cf64c22ddff 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -159,9 +159,7 @@ physical_memory_size_type os::Linux::_physical_memory = 0; address os::Linux::_initial_thread_stack_bottom = nullptr; uintptr_t os::Linux::_initial_thread_stack_size = 0; -int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = nullptr; pthread_t os::Linux::_main_thread; -bool os::Linux::_supports_fast_thread_cpu_time = false; const char * os::Linux::_libc_version = nullptr; const char * os::Linux::_libpthread_version = nullptr; @@ -1475,29 +1473,6 @@ void os::Linux::capture_initial_stack(size_t max_size) { //////////////////////////////////////////////////////////////////////////////// // time support -void os::Linux::fast_thread_clock_init() { - clockid_t clockid; - struct timespec tp; - int (*pthread_getcpuclockid_func)(pthread_t, clockid_t *) = - (int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid"); - - // Switch to using fast clocks for thread cpu time if - // the clock_getres() returns 0 error code. - // Note, that some kernels may support the current thread - // clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks - // returned by the pthread_getcpuclockid(). - // If the fast POSIX clocks are supported then the clock_getres() - // must return at least tp.tv_sec == 0 which means a resolution - // better than 1 sec. This is extra check for reliability. - - if (pthread_getcpuclockid_func && - pthread_getcpuclockid_func(_main_thread, &clockid) == 0 && - clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) { - _supports_fast_thread_cpu_time = true; - _pthread_getcpuclockid = pthread_getcpuclockid_func; - } -} - // thread_id is kernel thread id (similar to Solaris LWP id) intx os::current_thread_id() { return os::Linux::gettid(); } int os::current_process_id() { @@ -1900,6 +1875,8 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) { assert(rtn == 0, "fegetenv must succeed"); #endif // IA32 + Events::log_dll_message(nullptr, "Attempting to load shared library %s", filename); + void* result; JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) result = ::dlopen(filename, RTLD_LAZY); @@ -4328,7 +4305,7 @@ OSReturn os::get_native_priority(const Thread* const thread, // For reference, please, see IEEE Std 1003.1-2004: // http://www.unix.org/single_unix_specification -jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) { +jlong os::Linux::total_thread_cpu_time(clockid_t clockid) { struct timespec tp; int status = clock_gettime(clockid, &tp); assert(status == 0, "clock_gettime error: %s", os::strerror(errno)); @@ -4556,8 +4533,6 @@ jint os::init_2(void) { os::Posix::init_2(); - Linux::fast_thread_clock_init(); - if (PosixSignals::init() == JNI_ERR) { return JNI_ERR; } @@ -4985,14 +4960,14 @@ int os::open(const char *path, int oflag, int mode) { return fd; } -static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time); +static jlong user_thread_cpu_time(Thread *thread); -static jlong fast_cpu_time(Thread *thread) { +static jlong total_thread_cpu_time(Thread *thread) { clockid_t clockid; - int rc = os::Linux::pthread_getcpuclockid(thread->osthread()->pthread_id(), + int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clockid); if (rc == 0) { - return os::Linux::fast_thread_cpu_time(clockid); + return os::Linux::total_thread_cpu_time(clockid); } else { // It's possible to encounter a terminated native thread that failed // to detach itself from the VM - which should result in ESRCH. @@ -5009,41 +4984,31 @@ static jlong fast_cpu_time(Thread *thread) { // the fast estimate available on the platform. jlong os::current_thread_cpu_time() { - if (os::Linux::supports_fast_thread_cpu_time()) { - return os::Linux::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); - } else { - // return user + sys since the cost is the same - return slow_thread_cpu_time(Thread::current(), true /* user + sys */); - } + return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } jlong os::thread_cpu_time(Thread* thread) { - // consistent with what current_thread_cpu_time() returns - if (os::Linux::supports_fast_thread_cpu_time()) { - return fast_cpu_time(thread); - } else { - return slow_thread_cpu_time(thread, true /* user + sys */); - } + return total_thread_cpu_time(thread); } jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { - if (user_sys_cpu_time && os::Linux::supports_fast_thread_cpu_time()) { - return os::Linux::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); + if (user_sys_cpu_time) { + return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } else { - return slow_thread_cpu_time(Thread::current(), user_sys_cpu_time); + return user_thread_cpu_time(Thread::current()); } } jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { - if (user_sys_cpu_time && os::Linux::supports_fast_thread_cpu_time()) { - return fast_cpu_time(thread); + if (user_sys_cpu_time) { + return total_thread_cpu_time(thread); } else { - return slow_thread_cpu_time(thread, user_sys_cpu_time); + return user_thread_cpu_time(thread); } } // -1 on error. -static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { +static jlong user_thread_cpu_time(Thread *thread) { pid_t tid = thread->osthread()->thread_id(); char *s; char stat[2048]; @@ -5080,11 +5045,8 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { &ldummy, &ldummy, &ldummy, &ldummy, &ldummy, &user_time, &sys_time); if (count != 13) return -1; - if (user_sys_cpu_time) { - return ((jlong)sys_time + (jlong)user_time) * (1000000000 / os::Posix::clock_tics_per_second()); - } else { - return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); - } + + return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { @@ -5163,7 +5125,7 @@ int os::get_core_path(char* buffer, size_t bufferSize) { if (core_pattern[0] == '|') { written = jio_snprintf(buffer, bufferSize, - "\"%s\" (or dumping to %s/core.%d)", + "\"%s\" (alternatively, falling back to %s/core.%d)", &core_pattern[1], p, current_process_id()); } else if (pid_pos != nullptr) { *pid_pos = '\0'; diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index 9c0b6723b38..dd07cb600b9 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -32,16 +32,12 @@ class os::Linux { friend class os; - static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *); - static address _initial_thread_stack_bottom; static uintptr_t _initial_thread_stack_size; static const char *_libc_version; static const char *_libpthread_version; - static bool _supports_fast_thread_cpu_time; - static GrowableArray* _cpu_to_node; static GrowableArray* _nindex_to_node; @@ -146,18 +142,7 @@ class os::Linux { static bool manually_expand_stack(JavaThread * t, address addr); static void expand_stack_to(address bottom); - // fast POSIX clocks support - static void fast_thread_clock_init(void); - - static int pthread_getcpuclockid(pthread_t tid, clockid_t *clock_id) { - return _pthread_getcpuclockid ? _pthread_getcpuclockid(tid, clock_id) : -1; - } - - static bool supports_fast_thread_cpu_time() { - return _supports_fast_thread_cpu_time; - } - - static jlong fast_thread_cpu_time(clockid_t clockid); + static jlong total_thread_cpu_time(clockid_t clockid); static jlong sendfile(int out_fd, int in_fd, jlong* offset, jlong count); diff --git a/src/hotspot/os/linux/procMapsParser.cpp b/src/hotspot/os/linux/procMapsParser.cpp index 47c5c6cc594..0663cae61f3 100644 --- a/src/hotspot/os/linux/procMapsParser.cpp +++ b/src/hotspot/os/linux/procMapsParser.cpp @@ -50,7 +50,14 @@ ProcSmapsParser::~ProcSmapsParser() { bool ProcSmapsParser::read_line() { _line[0] = '\0'; - return ::fgets(_line, _linelen, _f) != nullptr; + + if (::fgets(_line, _linelen, _f) == nullptr) { + // On error or EOF, ensure deterministic empty buffer + _line[0] = '\0'; + return false; + } else { + return true; + } } bool ProcSmapsParser::is_header_line() { @@ -101,8 +108,6 @@ void ProcSmapsParser::scan_additional_line(ProcSmapsInfo& out) { } } -// Starts or continues parsing. Returns true on success, -// false on EOF or on error. bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) { // Information about a single mapping reaches across several lines. @@ -117,15 +122,13 @@ bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) { assert(is_header_line(), "Not a header line: \"%s\".", _line); scan_header_line(out); - // Now read until we encounter the next header line or EOF or an error. - bool ok = false, stop = false; - do { - ok = read_line(); - stop = !ok || is_header_line(); - if (!stop) { - scan_additional_line(out); + while (true) { + bool ok = read_line(); + if (!ok || is_header_line()) { + break; // EOF or next header } - } while (!stop); + scan_additional_line(out); + } - return ok; + return true; // always return true if a mapping was parsed } diff --git a/src/hotspot/os/linux/procMapsParser.hpp b/src/hotspot/os/linux/procMapsParser.hpp index 06035333b2f..037af91358f 100644 --- a/src/hotspot/os/linux/procMapsParser.hpp +++ b/src/hotspot/os/linux/procMapsParser.hpp @@ -84,8 +84,7 @@ public: ProcSmapsParser(FILE* f); ~ProcSmapsParser(); - // Starts or continues parsing. Returns true on success, - // false on EOF or on error. + // Starts or continues parsing. Returns true iff a mapping was parsed. bool parse_next(ProcSmapsInfo& out); }; diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 1a04cbba0de..8f1f07dd055 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -108,41 +108,60 @@ size_t os::_os_min_stack_allowed = PTHREAD_STACK_MIN; // Check core dump limit and report possible place where core can be found void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) { + stringStream buf(buffer, bufferSize); if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) { - jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line"); - VMError::record_coredump_status(buffer, false); + buf.print("CreateCoredumpOnCrash is disabled from command line"); + VMError::record_coredump_status(buf.freeze(), false); } else { struct rlimit rlim; bool success = true; bool warn = true; char core_path[PATH_MAX]; if (get_core_path(core_path, PATH_MAX) <= 0) { - jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id()); + // In the warning message, let the user know. + if (check_only) { + buf.print("the core path couldn't be determined. It commonly defaults to "); + } + buf.print("core.%d%s", current_process_id(), check_only ? "" : " (may not exist)"); #ifdef LINUX } else if (core_path[0] == '"') { // redirect to user process - jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path); + if (check_only) { + buf.print("core dumps may be further processed by the following: "); + } else { + buf.print("Determined by the following: "); + } + buf.print("%s", core_path); #endif } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) { - jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path); + if (check_only) { + buf.print("the rlimit couldn't be determined. If resource limits permit, the core dump will be located at "); + } + buf.print("%s%s", core_path, check_only ? "" : " (may not exist)"); } else { switch(rlim.rlim_cur) { case RLIM_INFINITY: - jio_snprintf(buffer, bufferSize, "%s", core_path); + buf.print("%s", core_path); warn = false; break; case 0: - jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again"); + buf.print("%s dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again", check_only ? "core" : "Core"); success = false; break; default: - jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K); + if (check_only) { + buf.print("core dumps are constrained "); + } else { + buf.print( "%s ", core_path); + } + buf.print( "(max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", uint64_t(rlim.rlim_cur) / K); break; } } + const char* result = buf.freeze(); if (!check_only) { - VMError::record_coredump_status(buffer, success); + VMError::record_coredump_status(result, success); } else if (warn) { - warning("CreateCoredumpOnCrash specified, but %s", buffer); + warning("CreateCoredumpOnCrash specified, but %s", result); } } } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 8a450a291d3..b9aeb4e8dd6 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1715,6 +1715,8 @@ static int _print_module(const char* fname, address base_address, // same architecture as Hotspot is running on void * os::dll_load(const char *name, char *ebuf, int ebuflen) { log_info(os)("attempting shared library load of %s", name); + Events::log_dll_message(nullptr, "Attempting to load shared library %s", name); + void* result; JFR_ONLY(NativeLibraryLoadEvent load_event(name, &result);) result = LoadLibrary(name); diff --git a/src/hotspot/os/windows/sharedRuntimeRem.cpp b/src/hotspot/os/windows/sharedRuntimeRem.cpp index aae93f701ec..fbcf68a5940 100644 --- a/src/hotspot/os/windows/sharedRuntimeRem.cpp +++ b/src/hotspot/os/windows/sharedRuntimeRem.cpp @@ -50,11 +50,9 @@ double SharedRuntime::fmod_winx64(double x, double y) hx ^= sx; /* |x| */ hy &= 0x7fffffff; /* |y| */ -#pragma warning( disable : 4146 ) /* purge off exception values */ if ((hy | ly) == 0 || (hx >= 0x7ff00000) || /* y=0,or x not finite */ - ((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */ -#pragma warning( default : 4146 ) + ((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */ return (x*y) / (x*y); if (hx <= hy) { if ((hx +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + template template inline T AtomicAccess::PlatformXchg::operator()(T volatile* dest, T exchange_value, atomic_memory_order order) const { STATIC_ASSERT(byte_size == sizeof(T)); + STATIC_ASSERT(byte_size == 4 || byte_size == 8); T res = __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELEASE); FULL_MEM_BARRIER; return res; diff --git a/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp index 1024c6b1418..29471300f3d 100644 --- a/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp @@ -52,6 +52,9 @@ inline D AtomicAccess::PlatformAdd<4>::fetch_then_add(D volatile* dest, I add_va return old_value; } +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + template<> template inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest, diff --git a/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp index 6a720dac54e..6c8684718fc 100644 --- a/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp +++ b/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp @@ -66,6 +66,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va return res; } +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + template<> template inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest, diff --git a/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp index 6e5f53edfa3..4ddb2b758b4 100644 --- a/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp @@ -113,6 +113,9 @@ inline D AtomicAccess::PlatformAdd<8>::fetch_then_add(D volatile* dest, I add_va return atomic_fastcall(stub, dest, add_value); } +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + template<> template inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest, diff --git a/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp index 5b5f9da51a6..390207f9e5e 100644 --- a/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp +++ b/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp @@ -118,6 +118,8 @@ inline D AtomicAccess::PlatformAdd<4>::add_then_fetch(D volatile* dest, I add_va return add_using_helper(ARMAtomicFuncs::_add_func, dest, add_value); } +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; template<> template diff --git a/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp index 6d57ea55a83..bdbc0b8ac7f 100644 --- a/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp +++ b/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp @@ -152,6 +152,9 @@ inline T AtomicAccess::PlatformCmpxchg<4>::operator()(T volatile* dest __attribu } #endif +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + template template inline T AtomicAccess::PlatformXchg::operator()(T volatile* dest, @@ -164,6 +167,7 @@ inline T AtomicAccess::PlatformXchg::operator()(T volatile* dest, #endif STATIC_ASSERT(byte_size == sizeof(T)); + STATIC_ASSERT(byte_size == 4 || byte_size == 8); if (order != memory_order_relaxed) { FULL_MEM_BARRIER; diff --git a/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp index 5849d69ae2f..f3c1e8f1a2c 100644 --- a/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp +++ b/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp @@ -209,6 +209,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I inc, // // The return value is the (unchanged) value from memory as it was when the // replacement succeeded. +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + template<> template inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest, diff --git a/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp index dd91444d0a3..6b43b5e8e09 100644 --- a/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp @@ -52,6 +52,9 @@ inline D AtomicAccess::PlatformAdd<4>::fetch_then_add(D volatile* dest, I add_va return old_value; } +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + template<> template inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest, diff --git a/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp index 376ef7a9dc9..96c46c6f59a 100644 --- a/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp +++ b/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp @@ -65,6 +65,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va return res; } +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + template<> template inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest, diff --git a/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp index 62b6e3f87ec..f8119654c50 100644 --- a/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp @@ -68,6 +68,9 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64) #undef DEFINE_INTRINSIC_ADD +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + #define DEFINE_INTRINSIC_XCHG(IntrinsicName, IntrinsicType) \ template<> \ template \ @@ -75,6 +78,8 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64) T exchange_value, \ atomic_memory_order order) const { \ STATIC_ASSERT(sizeof(IntrinsicType) == sizeof(T)); \ + STATIC_ASSERT(sizeof(IntrinsicType) == 4 || \ + sizeof(IntrinsicType) == 8); \ return PrimitiveConversions::cast( \ IntrinsicName(reinterpret_cast(dest), \ PrimitiveConversions::cast(exchange_value))); \ diff --git a/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp index a95da151688..aa78a401235 100644 --- a/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp +++ b/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp @@ -70,6 +70,9 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64) #undef DEFINE_INTRINSIC_ADD +template<> +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; + #define DEFINE_INTRINSIC_XCHG(IntrinsicName, IntrinsicType) \ template<> \ template \ @@ -77,6 +80,8 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64) T exchange_value, \ atomic_memory_order order) const { \ STATIC_ASSERT(sizeof(IntrinsicType) == sizeof(T)); \ + STATIC_ASSERT(sizeof(IntrinsicType) == 4 || \ + sizeof(IntrinsicType) == 8); \ return PrimitiveConversions::cast( \ IntrinsicName(reinterpret_cast(dest), \ PrimitiveConversions::cast(exchange_value))); \ diff --git a/src/hotspot/share/classfile/resolutionErrors.cpp b/src/hotspot/share/classfile/resolutionErrors.cpp index 25aa370d257..f5a335f17f3 100644 --- a/src/hotspot/share/classfile/resolutionErrors.cpp +++ b/src/hotspot/share/classfile/resolutionErrors.cpp @@ -73,7 +73,7 @@ void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_inde ResolutionErrorKey key(pool(), cp_index); ResolutionErrorEntry *entry = new ResolutionErrorEntry(error, message, cause, cause_msg); - _resolution_error_table->put(key, entry); + _resolution_error_table->put_when_absent(key, entry); } // create new nest host error entry @@ -85,7 +85,7 @@ void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_inde ResolutionErrorKey key(pool(), cp_index); ResolutionErrorEntry *entry = new ResolutionErrorEntry(message); - _resolution_error_table->put(key, entry); + _resolution_error_table->put_when_absent(key, entry); } // find entry in the table @@ -126,6 +126,15 @@ ResolutionErrorEntry::~ResolutionErrorEntry() { } } +void ResolutionErrorEntry::set_nest_host_error(const char* message) { + // If a message is already set, free it. + if (nest_host_error() != nullptr) { + FREE_C_HEAP_ARRAY(char, _nest_host_error); + } + _nest_host_error = message; +} + + class ResolutionErrorDeleteIterate : StackObj { ConstantPool* p; diff --git a/src/hotspot/share/classfile/resolutionErrors.hpp b/src/hotspot/share/classfile/resolutionErrors.hpp index 60f8aea68ef..39859ad2b70 100644 --- a/src/hotspot/share/classfile/resolutionErrors.hpp +++ b/src/hotspot/share/classfile/resolutionErrors.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,10 +91,7 @@ class ResolutionErrorEntry : public CHeapObj { ~ResolutionErrorEntry(); // The incoming nest host error message is already in the C-Heap. - void set_nest_host_error(const char* message) { - _nest_host_error = message; - } - + void set_nest_host_error(const char* message); Symbol* error() const { return _error; } const char* message() const { return _message; } diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 5c49a32b8d0..a17e7e129ce 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1864,14 +1864,19 @@ void SystemDictionary::add_nest_host_error(const constantPoolHandle& pool, { MutexLocker ml(Thread::current(), SystemDictionary_lock); ResolutionErrorEntry* entry = ResolutionErrorTable::find_entry(pool, which); - if (entry != nullptr && entry->nest_host_error() == nullptr) { + if (entry == nullptr) { + // Only add a new entry to the resolution error table if one hasn't been found for this + // constant pool index. In this case resolution succeeded but there's an error in this nest host + // that we use the table to record. + assert(pool->resolved_klass_at(which) != nullptr, "klass should be resolved if there is no entry"); + ResolutionErrorTable::add_entry(pool, which, message); + } else { // An existing entry means we had a true resolution failure (LinkageError) with our nest host, but we // still want to add the error message for the higher-level access checks to report. We should // only reach here under the same error condition, so we can ignore the potential race with setting - // the message. If we see it is already set then we can ignore it. + // the message, and set it again. + assert(entry->nest_host_error() == nullptr || strcmp(entry->nest_host_error(), message) == 0, "should be the same message"); entry->set_nest_host_error(message); - } else { - ResolutionErrorTable::add_entry(pool, which, message); } } } diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index d1e2f6f34a0..1951fd066fc 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -1010,8 +1010,10 @@ void CompilationMemoryStatistic::print_error_report(outputStream* st) { oom_stats->print_peak_state_on(st); st->cr(); } - st->print_cr("Compiler Memory Statistic, 10 most expensive compilations:"); - print_all_by_size(st, false, false, 0, 10); + if (Thread::current_or_null_safe() != nullptr) { + st->print_cr("Compiler Memory Statistic, 10 most expensive compilations:"); + print_all_by_size(st, false, false, 0, 10); + } } void CompilationMemoryStatistic::print_final_report(outputStream* st) { diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.cpp b/src/hotspot/share/gc/g1/g1AllocRegion.cpp index 7e748cf7e9f..1af7638102a 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.cpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.cpp @@ -33,10 +33,10 @@ #include "utilities/align.hpp" G1CollectedHeap* G1AllocRegion::_g1h = nullptr; -G1HeapRegion* G1AllocRegion::_dummy_region = nullptr; +Atomic G1AllocRegion::_dummy_region; void G1AllocRegion::setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region) { - assert(_dummy_region == nullptr, "should be set once"); + assert(_dummy_region.load_relaxed() == nullptr, "should be set once"); assert(dummy_region != nullptr, "pre-condition"); assert(dummy_region->free() == 0, "pre-condition"); @@ -46,11 +46,11 @@ void G1AllocRegion::setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region) { assert(dummy_region->par_allocate(1, 1, &assert_tmp) == nullptr, "should fail"); _g1h = g1h; - _dummy_region = dummy_region; + _dummy_region.release_store(dummy_region); } size_t G1AllocRegion::fill_up_remaining_space(G1HeapRegion* alloc_region) { - assert(alloc_region != nullptr && alloc_region != _dummy_region, + assert(alloc_region != nullptr && alloc_region != _dummy_region.load_relaxed(), "pre-condition"); size_t result = 0; @@ -111,13 +111,13 @@ size_t G1AllocRegion::retire_internal(G1HeapRegion* alloc_region, bool fill_up) } size_t G1AllocRegion::retire(bool fill_up) { - assert_alloc_region(_alloc_region != nullptr, "not initialized properly"); + assert_alloc_region(_alloc_region.load_relaxed() != nullptr, "not initialized properly"); size_t waste = 0; trace("retiring"); - G1HeapRegion* alloc_region = _alloc_region; - if (alloc_region != _dummy_region) { + G1HeapRegion* alloc_region = _alloc_region.load_acquire(); + if (alloc_region != _dummy_region.load_relaxed()) { waste = retire_internal(alloc_region, fill_up); reset_alloc_region(); } @@ -127,7 +127,7 @@ size_t G1AllocRegion::retire(bool fill_up) { } HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) { - assert_alloc_region(_alloc_region == _dummy_region, "pre-condition"); + assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed(), "pre-condition"); trace("attempting region allocation"); G1HeapRegion* new_alloc_region = allocate_new_region(word_size); @@ -138,7 +138,6 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) { HeapWord* result = new_alloc_region->allocate(word_size); assert_alloc_region(result != nullptr, "the allocation should succeeded"); - OrderAccess::storestore(); // Note that we first perform the allocation and then we store the // region in _alloc_region. This is the reason why an active region // can never be empty. @@ -154,16 +153,16 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) { void G1AllocRegion::init() { trace("initializing"); - assert_alloc_region(_alloc_region == nullptr, "pre-condition"); - assert_alloc_region(_dummy_region != nullptr, "should have been set"); - _alloc_region = _dummy_region; + assert_alloc_region(_alloc_region.load_relaxed() == nullptr, "pre-condition"); + assert_alloc_region(_dummy_region.load_relaxed() != nullptr, "should have been set"); + _alloc_region.release_store(_dummy_region.load_relaxed()); _count = 0; trace("initialized"); } void G1AllocRegion::set(G1HeapRegion* alloc_region) { trace("setting"); - assert_alloc_region(_alloc_region == _dummy_region && _count == 0, "pre-condition"); + assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed() && _count == 0, "pre-condition"); update_alloc_region(alloc_region); trace("set"); @@ -175,19 +174,19 @@ void G1AllocRegion::update_alloc_region(G1HeapRegion* alloc_region) { // maintain the "the alloc region cannot be empty" invariant. assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "pre-condition"); - _alloc_region = alloc_region; + _alloc_region.release_store(alloc_region); _count += 1; trace("updated"); } G1HeapRegion* G1AllocRegion::release() { trace("releasing"); - G1HeapRegion* alloc_region = _alloc_region; + G1HeapRegion* alloc_region = _alloc_region.load_acquire(); retire(false /* fill_up */); - assert_alloc_region(_alloc_region == _dummy_region, "post-condition of retire()"); - _alloc_region = nullptr; + assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed(), "post-condition of retire()"); + _alloc_region.store_relaxed(nullptr); trace("released"); - return (alloc_region == _dummy_region) ? nullptr : alloc_region; + return (alloc_region == _dummy_region.load_relaxed()) ? nullptr : alloc_region; } #ifndef PRODUCT @@ -211,12 +210,13 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_ out->print("%s: %u ", _name, _count); - if (_alloc_region == nullptr) { + G1HeapRegion* alloc_region = _alloc_region.load_acquire(); + if (alloc_region == nullptr) { out->print("null"); - } else if (_alloc_region == _dummy_region) { + } else if (alloc_region == _dummy_region.load_relaxed()) { out->print("DUMMY"); } else { - out->print(HR_FORMAT, HR_FORMAT_PARAMS(_alloc_region)); + out->print(HR_FORMAT, HR_FORMAT_PARAMS(alloc_region)); } out->print(" : %s", str); @@ -235,7 +235,7 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_ #endif // PRODUCT G1AllocRegion::G1AllocRegion(const char* name, uint node_index) - : _alloc_region(nullptr), + : _alloc_region(), _count(0), _name(name), _node_index(node_index) @@ -250,7 +250,7 @@ void MutatorAllocRegion::retire_region(G1HeapRegion* alloc_region) { } void MutatorAllocRegion::init() { - assert(_retained_alloc_region == nullptr, "Pre-condition"); + assert(_retained_alloc_region.load_relaxed() == nullptr, "Pre-condition"); G1AllocRegion::init(); _wasted_bytes = 0; } @@ -261,8 +261,9 @@ bool MutatorAllocRegion::should_retain(G1HeapRegion* region) { return false; } - if (_retained_alloc_region != nullptr && - free_bytes < _retained_alloc_region->free()) { + G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire(); + if (retained_alloc_region != nullptr && + free_bytes < retained_alloc_region->free()) { return false; } @@ -278,10 +279,11 @@ size_t MutatorAllocRegion::retire(bool fill_up) { // free than the currently retained region. if (should_retain(current_region)) { trace("mutator retained"); - if (_retained_alloc_region != nullptr) { - waste = retire_internal(_retained_alloc_region, true); + G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire(); + if (retained_alloc_region != nullptr) { + waste = retire_internal(retained_alloc_region, true); } - _retained_alloc_region = current_region; + _retained_alloc_region.release_store(current_region); } else { waste = retire_internal(current_region, fill_up); } @@ -300,7 +302,7 @@ size_t MutatorAllocRegion::used_in_alloc_regions() { used += hr->used(); } - hr = _retained_alloc_region; + hr = _retained_alloc_region.load_acquire(); if (hr != nullptr) { used += hr->used(); } @@ -313,9 +315,10 @@ G1HeapRegion* MutatorAllocRegion::release() { // The retained alloc region must be retired and this must be // done after the above call to release the mutator alloc region, // since it might update the _retained_alloc_region member. - if (_retained_alloc_region != nullptr) { - _wasted_bytes += retire_internal(_retained_alloc_region, false); - _retained_alloc_region = nullptr; + G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire(); + if (retained_alloc_region != nullptr) { + _wasted_bytes += retire_internal(retained_alloc_region, false); + _retained_alloc_region.store_relaxed(nullptr); } log_debug(gc, alloc, region)("Mutator Allocation stats, regions: %u, wasted size: %zu%s (%4.1f%%)", count(), diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.hpp index 3e38332ee6f..248aa0a9da0 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.hpp @@ -29,6 +29,7 @@ #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1HeapRegionAttr.hpp" #include "gc/g1/g1NUMA.hpp" +#include "runtime/atomic.hpp" class G1CollectedHeap; @@ -40,8 +41,6 @@ class G1CollectedHeap; // replaced. class G1AllocRegion : public CHeapObj { - -private: // The active allocating region we are currently allocating out // of. The invariant is that if this object is initialized (i.e., // init() has been called and release() has not) then _alloc_region @@ -52,7 +51,7 @@ private: // then _alloc_region is null and this object should not be used to // satisfy allocation requests (it was done this way to force the // correct use of init() and release()). - G1HeapRegion* volatile _alloc_region; + Atomic _alloc_region; // It keeps track of the distinct number of regions that are used // for allocation in the active interval of this object, i.e., @@ -71,7 +70,7 @@ private: // == end()). When we don't have a valid active region we make // _alloc_region point to this. This allows us to skip checking // whether the _alloc_region is null or not. - static G1HeapRegion* _dummy_region; + static Atomic _dummy_region; // After a region is allocated by alloc_new_region, this // method is used to set it as the active alloc_region @@ -124,9 +123,9 @@ public: static void setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region); G1HeapRegion* get() const { - G1HeapRegion * hr = _alloc_region; + G1HeapRegion * hr = _alloc_region.load_acquire(); // Make sure that the dummy region does not escape this class. - return (hr == _dummy_region) ? nullptr : hr; + return (hr == _dummy_region.load_relaxed()) ? nullptr : hr; } uint count() { return _count; } @@ -177,7 +176,7 @@ private: // Retained allocation region. Used to lower the waste generated // during mutation by having two active regions if the free space // in a region about to be retired still could fit a TLAB. - G1HeapRegion* volatile _retained_alloc_region; + Atomic _retained_alloc_region; // Decide if the region should be retained, based on the free size // in it and the free size in the currently retained region, if any. diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp index af9156163ac..e1d23867ea3 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp @@ -32,13 +32,13 @@ #define assert_alloc_region(p, message) \ do { \ assert((p), "[%s] %s c: %u r: " PTR_FORMAT, \ - _name, (message), _count, p2i(_alloc_region) \ + _name, (message), _count, p2i(_alloc_region.load_relaxed()) \ ); \ } while (0) inline void G1AllocRegion::reset_alloc_region() { - _alloc_region = _dummy_region; + _alloc_region.store_relaxed(_dummy_region.load_relaxed()); } inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t word_size) { @@ -51,7 +51,7 @@ inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { - G1HeapRegion* alloc_region = _alloc_region; + G1HeapRegion* alloc_region = _alloc_region.load_acquire(); assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "not initialized properly"); HeapWord* result = alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); @@ -97,8 +97,9 @@ inline HeapWord* G1AllocRegion::attempt_allocation_using_new_region(size_t min_w inline HeapWord* MutatorAllocRegion::attempt_retained_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { - if (_retained_alloc_region != nullptr) { - HeapWord* result = _retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); + G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire(); + if (retained_alloc_region != nullptr) { + HeapWord* result = retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); if (result != nullptr) { trace("alloc retained", min_word_size, desired_word_size, *actual_word_size, result); return result; diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index 5cbafd2ae94..2be0e008c22 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -77,10 +77,11 @@ void G1Arguments::initialize_alignments() { } size_t G1Arguments::conservative_max_heap_alignment() { - if (FLAG_IS_DEFAULT(G1HeapRegionSize)) { - return G1HeapRegion::max_ergonomics_size(); - } - return G1HeapRegion::max_region_size(); + const size_t region_size = FLAG_IS_DEFAULT(G1HeapRegionSize) + ? G1HeapRegion::max_ergonomics_size() + : G1HeapRegion::max_region_size(); + + return calculate_heap_alignment(region_size); } void G1Arguments::initialize_verification_types() { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 5567d84bee4..061241c24e2 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2355,7 +2355,8 @@ static void print_region_type(outputStream* st, const char* type, uint count, bo } void G1CollectedHeap::print_heap_on(outputStream* st) const { - size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked(); + size_t heap_used = (Thread::current_or_null_safe() != nullptr && + Heap_lock->owned_by_self()) ? used() : used_unlocked(); st->print("%-20s", "garbage-first heap"); st->print(" total reserved %zuK, committed %zuK, used %zuK", _hrm.reserved().byte_size()/K, capacity()/K, heap_used/K); diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index d0633466f37..c7724de280f 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -611,23 +611,24 @@ void G1RemSet::scan_collection_set_code_roots(G1ParScanThreadState* pss, G1GCPhaseTimes::GCParPhases coderoots_phase, G1GCPhaseTimes::GCParPhases objcopy_phase) { EventGCPhaseParallel event; - Tickspan code_root_scan_time; Tickspan code_root_trim_partially_time; - G1EvacPhaseWithTrimTimeTracker timer(pss, code_root_scan_time, code_root_trim_partially_time); G1GCPhaseTimes* p = _g1h->phase_times(); + { + G1EvacPhaseWithTrimTimeTracker timer(pss, code_root_scan_time, code_root_trim_partially_time); - G1ScanCodeRootsClosure cl(_scan_state, pss, worker_id); - // Code roots work distribution occurs inside the iteration method. So scan all collection - // set regions for all threads. - _g1h->collection_set_iterate_increment_from(&cl, worker_id); + G1ScanCodeRootsClosure cl(_scan_state, pss, worker_id); + // Code roots work distribution occurs inside the iteration method. So scan all collection + // set regions for all threads. + _g1h->collection_set_iterate_increment_from(&cl, worker_id); + + p->record_or_add_thread_work_item(coderoots_phase, worker_id, cl.code_roots_scanned(), G1GCPhaseTimes::CodeRootsScannedNMethods); + } p->record_or_add_time_secs(coderoots_phase, worker_id, code_root_scan_time.seconds()); p->add_time_secs(objcopy_phase, worker_id, code_root_trim_partially_time.seconds()); - p->record_or_add_thread_work_item(coderoots_phase, worker_id, cl.code_roots_scanned(), G1GCPhaseTimes::CodeRootsScannedNMethods); - event.commit(GCId::current(), worker_id, G1GCPhaseTimes::phase_name(coderoots_phase)); } diff --git a/src/hotspot/share/gc/parallel/parallelArguments.cpp b/src/hotspot/share/gc/parallel/parallelArguments.cpp index 629690a6258..be9673224f5 100644 --- a/src/hotspot/share/gc/parallel/parallelArguments.cpp +++ b/src/hotspot/share/gc/parallel/parallelArguments.cpp @@ -37,8 +37,45 @@ #include "utilities/defaultStream.hpp" #include "utilities/powerOfTwo.hpp" -size_t ParallelArguments::conservative_max_heap_alignment() { - return compute_heap_alignment(); +static size_t num_young_spaces() { + // When using NUMA, we create one MutableNUMASpace for each NUMA node + const size_t num_eden_spaces = UseNUMA ? os::numa_get_groups_num() : 1; + + // The young generation must have room for eden + two survivors + return num_eden_spaces + 2; +} + +static size_t num_old_spaces() { + return 1; +} + +void ParallelArguments::initialize_alignments() { + // Initialize card size before initializing alignments + CardTable::initialize_card_size(); + const size_t card_table_alignment = CardTable::ct_max_alignment_constraint(); + SpaceAlignment = ParallelScavengeHeap::default_space_alignment(); + + if (UseLargePages) { + const size_t total_spaces = num_young_spaces() + num_old_spaces(); + const size_t page_size = os::page_size_for_region_unaligned(MaxHeapSize, total_spaces); + ParallelScavengeHeap::set_desired_page_size(page_size); + + if (page_size == os::vm_page_size()) { + log_warning(gc, heap)("MaxHeapSize (%zu) must be large enough for %zu * page-size; Disabling UseLargePages for heap", + MaxHeapSize, total_spaces); + } + + if (page_size > SpaceAlignment) { + SpaceAlignment = page_size; + } + + HeapAlignment = lcm(page_size, card_table_alignment); + + } else { + assert(is_aligned(SpaceAlignment, os::vm_page_size()), ""); + ParallelScavengeHeap::set_desired_page_size(os::vm_page_size()); + HeapAlignment = card_table_alignment; + } } void ParallelArguments::initialize() { @@ -98,49 +135,36 @@ void ParallelArguments::initialize() { FullGCForwarding::initialize_flags(heap_reserved_size_bytes()); } -void ParallelArguments::initialize_alignments() { - // Initialize card size before initializing alignments - CardTable::initialize_card_size(); - SpaceAlignment = ParallelScavengeHeap::default_space_alignment(); - HeapAlignment = compute_heap_alignment(); -} +size_t ParallelArguments::conservative_max_heap_alignment() { + // The card marking array and the offset arrays for old generations are + // committed in os pages as well. Make sure they are entirely full (to + // avoid partial page problems), e.g. if 512 bytes heap corresponds to 1 + // byte entry and the os page size is 4096, the maximum heap size should + // be 512*4096 = 2MB aligned. -void ParallelArguments::initialize_heap_flags_and_sizes_one_pass() { - // Do basic sizing work - GenArguments::initialize_heap_flags_and_sizes(); -} + size_t alignment = CardTable::ct_max_alignment_constraint(); -void ParallelArguments::initialize_heap_flags_and_sizes() { - initialize_heap_flags_and_sizes_one_pass(); - - if (!UseLargePages) { - ParallelScavengeHeap::set_desired_page_size(os::vm_page_size()); - return; + if (UseLargePages) { + // In presence of large pages we have to make sure that our + // alignment is large page aware. + alignment = lcm(os::large_page_size(), alignment); } - // If using large-page, need to update SpaceAlignment so that spaces are page-size aligned. - const size_t min_pages = 4; // 1 for eden + 1 for each survivor + 1 for old - const size_t page_sz = os::page_size_for_region_aligned(MinHeapSize, min_pages); - ParallelScavengeHeap::set_desired_page_size(page_sz); - - if (page_sz == os::vm_page_size()) { - log_warning(gc, heap)("MinHeapSize (%zu) must be large enough for 4 * page-size; Disabling UseLargePages for heap", MinHeapSize); - return; - } - - // Space is largepage-aligned. - size_t new_alignment = page_sz; - if (new_alignment != SpaceAlignment) { - SpaceAlignment = new_alignment; - // Redo everything from the start - initialize_heap_flags_and_sizes_one_pass(); - } -} - -size_t ParallelArguments::heap_reserved_size_bytes() { - return MaxHeapSize; + return alignment; } CollectedHeap* ParallelArguments::create_heap() { return new ParallelScavengeHeap(); } + +size_t ParallelArguments::young_gen_size_lower_bound() { + return num_young_spaces() * SpaceAlignment; +} + +size_t ParallelArguments::old_gen_size_lower_bound() { + return num_old_spaces() * SpaceAlignment; +} + +size_t ParallelArguments::heap_reserved_size_bytes() { + return MaxHeapSize; +} diff --git a/src/hotspot/share/gc/parallel/parallelArguments.hpp b/src/hotspot/share/gc/parallel/parallelArguments.hpp index 159441be792..729fe43b879 100644 --- a/src/hotspot/share/gc/parallel/parallelArguments.hpp +++ b/src/hotspot/share/gc/parallel/parallelArguments.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,21 +26,16 @@ #ifndef SHARE_GC_PARALLEL_PARALLELARGUMENTS_HPP #define SHARE_GC_PARALLEL_PARALLELARGUMENTS_HPP -#include "gc/shared/gcArguments.hpp" #include "gc/shared/genArguments.hpp" -class CollectedHeap; - class ParallelArguments : public GenArguments { private: virtual void initialize_alignments(); - virtual void initialize_heap_flags_and_sizes(); - - void initialize_heap_flags_and_sizes_one_pass(); - virtual void initialize(); virtual size_t conservative_max_heap_alignment(); virtual CollectedHeap* create_heap(); + virtual size_t young_gen_size_lower_bound(); + virtual size_t old_gen_size_lower_bound(); public: static size_t heap_reserved_size_bytes(); diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 3a13d0d0535..4d291120e4a 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -307,9 +307,13 @@ HeapWord* ParallelScavengeHeap::mem_allocate_cas_noexpand(size_t size, bool is_t HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { for (uint loop_count = 0; /* empty */; ++loop_count) { - HeapWord* result = mem_allocate_cas_noexpand(size, is_tlab); - if (result != nullptr) { - return result; + HeapWord* result; + { + ConditionalMutexLocker locker(Heap_lock, !is_init_completed()); + result = mem_allocate_cas_noexpand(size, is_tlab); + if (result != nullptr) { + return result; + } } // Read total_collections() under the lock so that multiple @@ -326,10 +330,15 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { } if (!is_init_completed()) { - // Can't do GC; try heap expansion to satisfy the request. - result = expand_heap_and_allocate(size, is_tlab); - if (result != nullptr) { - return result; + // Double checked locking, this ensure that is_init_completed() does not + // transition while expanding the heap. + MonitorLocker ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag); + if (!is_init_completed()) { + // Can't do GC; try heap expansion to satisfy the request. + result = expand_heap_and_allocate(size, is_tlab); + if (result != nullptr) { + return result; + } } } diff --git a/src/hotspot/share/gc/serial/serialArguments.cpp b/src/hotspot/share/gc/serial/serialArguments.cpp index aed1c2353b4..efebec4fa38 100644 --- a/src/hotspot/share/gc/serial/serialArguments.cpp +++ b/src/hotspot/share/gc/serial/serialArguments.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +28,49 @@ #include "gc/shared/fullGCForwarding.hpp" #include "gc/shared/gcArguments.hpp" +static size_t compute_heap_alignment() { + // The card marking array and the offset arrays for old generations are + // committed in os pages as well. Make sure they are entirely full (to + // avoid partial page problems), e.g. if 512 bytes heap corresponds to 1 + // byte entry and the os page size is 4096, the maximum heap size should + // be 512*4096 = 2MB aligned. + + size_t alignment = CardTable::ct_max_alignment_constraint(); + + if (UseLargePages) { + // In presence of large pages we have to make sure that our + // alignment is large page aware. + alignment = lcm(os::large_page_size(), alignment); + } + + return alignment; +} + +void SerialArguments::initialize_alignments() { + // Initialize card size before initializing alignments + CardTable::initialize_card_size(); + SpaceAlignment = (size_t)Generation::GenGrain; + HeapAlignment = compute_heap_alignment(); +} + void SerialArguments::initialize() { GCArguments::initialize(); FullGCForwarding::initialize_flags(MaxHeapSize); } +size_t SerialArguments::conservative_max_heap_alignment() { + return MAX2((size_t)Generation::GenGrain, compute_heap_alignment()); +} + CollectedHeap* SerialArguments::create_heap() { return new SerialHeap(); } + +size_t SerialArguments::young_gen_size_lower_bound() { + // The young generation must be aligned and have room for eden + two survivors + return 3 * SpaceAlignment; +} + +size_t SerialArguments::old_gen_size_lower_bound() { + return SpaceAlignment; +} diff --git a/src/hotspot/share/gc/serial/serialArguments.hpp b/src/hotspot/share/gc/serial/serialArguments.hpp index 90c3225ff8d..774168eb626 100644 --- a/src/hotspot/share/gc/serial/serialArguments.hpp +++ b/src/hotspot/share/gc/serial/serialArguments.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,12 +28,14 @@ #include "gc/shared/genArguments.hpp" -class CollectedHeap; - class SerialArguments : public GenArguments { private: + virtual void initialize_alignments(); virtual void initialize(); + virtual size_t conservative_max_heap_alignment(); virtual CollectedHeap* create_heap(); + virtual size_t young_gen_size_lower_bound(); + virtual size_t old_gen_size_lower_bound(); }; #endif // SHARE_GC_SERIAL_SERIALARGUMENTS_HPP diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 03ad1282f5f..faef3b89125 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -304,9 +304,12 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { HeapWord* result = nullptr; for (uint try_count = 1; /* break */; try_count++) { - result = mem_allocate_cas_noexpand(size, is_tlab); - if (result != nullptr) { - break; + { + ConditionalMutexLocker locker(Heap_lock, !is_init_completed()); + result = mem_allocate_cas_noexpand(size, is_tlab); + if (result != nullptr) { + break; + } } uint gc_count_before; // Read inside the Heap_lock locked region. { @@ -320,10 +323,15 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { } if (!is_init_completed()) { - // Can't do GC; try heap expansion to satisfy the request. - result = expand_heap_and_allocate(size, is_tlab); - if (result != nullptr) { - return result; + // Double checked locking, this ensure that is_init_completed() does not + // transition while expanding the heap. + MonitorLocker ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag); + if (!is_init_completed()) { + // Can't do GC; try heap expansion to satisfy the request. + result = expand_heap_and_allocate(size, is_tlab); + if (result != nullptr) { + return result; + } } } diff --git a/src/hotspot/share/gc/shared/bufferNode.hpp b/src/hotspot/share/gc/shared/bufferNode.hpp index a453bbc964b..e4e2ff23fb1 100644 --- a/src/hotspot/share/gc/shared/bufferNode.hpp +++ b/src/hotspot/share/gc/shared/bufferNode.hpp @@ -27,6 +27,7 @@ #include "cppstdlib/limits.hpp" #include "gc/shared/freeListAllocator.hpp" +#include "runtime/atomic.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/lockFreeStack.hpp" @@ -38,7 +39,7 @@ class BufferNode { InternalSizeType _index; InternalSizeType _capacity; - BufferNode* volatile _next; + Atomic _next; void* _buffer[1]; // Pseudo flexible array member. BufferNode(InternalSizeType capacity) @@ -58,11 +59,11 @@ public: return std::numeric_limits::max(); } - static BufferNode* volatile* next_ptr(BufferNode& bn) { return &bn._next; } + static Atomic* next_ptr(BufferNode& bn) { return &bn._next; } typedef LockFreeStack Stack; - BufferNode* next() const { return _next; } - void set_next(BufferNode* n) { _next = n; } + BufferNode* next() const { return _next.load_relaxed(); } + void set_next(BufferNode* n) { _next.store_relaxed(n); } size_t index() const { return _index; } void set_index(size_t i) { diff --git a/src/hotspot/share/gc/shared/gcArguments.cpp b/src/hotspot/share/gc/shared/gcArguments.cpp index d45e6a9c7dd..424427c12b6 100644 --- a/src/hotspot/share/gc/shared/gcArguments.cpp +++ b/src/hotspot/share/gc/shared/gcArguments.cpp @@ -62,24 +62,6 @@ void GCArguments::initialize_heap_sizes() { initialize_size_info(); } -size_t GCArguments::compute_heap_alignment() { - // The card marking array and the offset arrays for old generations are - // committed in os pages as well. Make sure they are entirely full (to - // avoid partial page problems), e.g. if 512 bytes heap corresponds to 1 - // byte entry and the os page size is 4096, the maximum heap size should - // be 512*4096 = 2MB aligned. - - size_t alignment = CardTable::ct_max_alignment_constraint(); - - if (UseLargePages) { - // In presence of large pages we have to make sure that our - // alignment is large page aware. - alignment = lcm(os::large_page_size(), alignment); - } - - return alignment; -} - #ifdef ASSERT void GCArguments::assert_flags() { assert(InitialHeapSize <= MaxHeapSize, "Ergonomics decided on incompatible initial and maximum heap sizes"); diff --git a/src/hotspot/share/gc/shared/gcArguments.hpp b/src/hotspot/share/gc/shared/gcArguments.hpp index fff41e85d8c..d8a4901f887 100644 --- a/src/hotspot/share/gc/shared/gcArguments.hpp +++ b/src/hotspot/share/gc/shared/gcArguments.hpp @@ -45,6 +45,8 @@ protected: public: virtual void initialize(); + + // Return the (conservative) maximum heap alignment virtual size_t conservative_max_heap_alignment() = 0; // Used by heap size heuristics to determine max @@ -59,8 +61,6 @@ public: } void initialize_heap_sizes(); - - static size_t compute_heap_alignment(); }; #endif // SHARE_GC_SHARED_GCARGUMENTS_HPP diff --git a/src/hotspot/share/gc/shared/gcLogPrecious.cpp b/src/hotspot/share/gc/shared/gcLogPrecious.cpp index 43bd58db1aa..d556eed1b69 100644 --- a/src/hotspot/share/gc/shared/gcLogPrecious.cpp +++ b/src/hotspot/share/gc/shared/gcLogPrecious.cpp @@ -25,6 +25,7 @@ #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" +#include "runtime/thread.hpp" #include "utilities/ostream.hpp" stringStream* GCLogPrecious::_lines = nullptr; @@ -83,7 +84,8 @@ void GCLogPrecious::print_on_error(outputStream* st) { return; } - if (!_lock->try_lock_without_rank_check()) { + if (Thread::current_or_null_safe() == nullptr || + !_lock->try_lock_without_rank_check()) { st->print_cr("\n"); return; } diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index e86a8744847..d08e95378f7 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -291,7 +291,7 @@ "size on systems with small physical memory size") \ range(0.0, 100.0) \ \ - product(double, InitialRAMPercentage, 0.2, \ + product(double, InitialRAMPercentage, 0.0, \ "Percentage of real memory used for initial heap size") \ range(0.0, 100.0) \ \ diff --git a/src/hotspot/share/gc/shared/genArguments.cpp b/src/hotspot/share/gc/shared/genArguments.cpp index 9618c515b7d..5d5003f8d9f 100644 --- a/src/hotspot/share/gc/shared/genArguments.cpp +++ b/src/hotspot/share/gc/shared/genArguments.cpp @@ -42,17 +42,6 @@ size_t MaxOldSize = 0; // See more in JDK-8346005 size_t OldSize = ScaleForWordSize(4*M); -size_t GenArguments::conservative_max_heap_alignment() { return (size_t)Generation::GenGrain; } - -static size_t young_gen_size_lower_bound() { - // The young generation must be aligned and have room for eden + two survivors - return 3 * SpaceAlignment; -} - -static size_t old_gen_size_lower_bound() { - return SpaceAlignment; -} - size_t GenArguments::scale_by_NewRatio_aligned(size_t base_size, size_t alignment) { return align_down_bounded(base_size / (NewRatio + 1), alignment); } @@ -64,13 +53,6 @@ static size_t bound_minus_alignment(size_t desired_size, return MIN2(desired_size, max_minus); } -void GenArguments::initialize_alignments() { - // Initialize card size before initializing alignments - CardTable::initialize_card_size(); - SpaceAlignment = (size_t)Generation::GenGrain; - HeapAlignment = compute_heap_alignment(); -} - void GenArguments::initialize_heap_flags_and_sizes() { GCArguments::initialize_heap_flags_and_sizes(); diff --git a/src/hotspot/share/gc/shared/genArguments.hpp b/src/hotspot/share/gc/shared/genArguments.hpp index 80133bd1ec1..0ff9568575d 100644 --- a/src/hotspot/share/gc/shared/genArguments.hpp +++ b/src/hotspot/share/gc/shared/genArguments.hpp @@ -38,17 +38,16 @@ extern size_t OldSize; class GenArguments : public GCArguments { friend class TestGenCollectorPolicy; // Testing private: - virtual void initialize_alignments(); virtual void initialize_size_info(); - // Return the (conservative) maximum heap alignment - virtual size_t conservative_max_heap_alignment(); - DEBUG_ONLY(void assert_flags();) DEBUG_ONLY(void assert_size_info();) static size_t scale_by_NewRatio_aligned(size_t base_size, size_t alignment); + virtual size_t young_gen_size_lower_bound() = 0; + virtual size_t old_gen_size_lower_bound() = 0; + protected: virtual void initialize_heap_flags_and_sizes(); }; diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index 1ed3701fdab..ea3d644d105 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -250,7 +250,7 @@ static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bo } else #endif { - heap_alignment = GCArguments::compute_heap_alignment(); + heap_alignment = Arguments::conservative_max_heap_alignment(); } return MaxSizeForAlignment(name, value, heap_alignment, verbose); @@ -285,7 +285,7 @@ JVMFlag::Error SoftMaxHeapSizeConstraintFunc(size_t value, bool verbose) { JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value. // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx. - if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) { + if (value > (max_uintx - MaxHeapSize)) { JVMFlag::printError(verbose, "HeapBaseMinAddress (%zu) or MaxHeapSize (%zu) is too large. " "Sum of them must be less than or equal to maximum of size_t (%zu)\n", diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.cpp b/src/hotspot/share/gc/shared/satbMarkQueue.cpp index e6ffe39facf..93c52b499a0 100644 --- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp +++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp @@ -27,7 +27,6 @@ #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" #include "runtime/safepoint.hpp" @@ -85,28 +84,28 @@ SATBMarkQueueSet::~SATBMarkQueueSet() { // remains set until the count is reduced to zero. // Increment count. If count > threshold, set flag, else maintain flag. -static void increment_count(volatile size_t* cfptr, size_t threshold) { +static void increment_count(Atomic* cfptr, size_t threshold) { size_t old; - size_t value = AtomicAccess::load(cfptr); + size_t value = cfptr->load_relaxed(); do { old = value; value += 2; assert(value > old, "overflow"); if (value > threshold) value |= 1; - value = AtomicAccess::cmpxchg(cfptr, old, value); + value = cfptr->compare_exchange(old, value); } while (value != old); } // Decrement count. If count == 0, clear flag, else maintain flag. -static void decrement_count(volatile size_t* cfptr) { +static void decrement_count(Atomic* cfptr) { size_t old; - size_t value = AtomicAccess::load(cfptr); + size_t value = cfptr->load_relaxed(); do { assert((value >> 1) != 0, "underflow"); old = value; value -= 2; if (value <= 1) value = 0; - value = AtomicAccess::cmpxchg(cfptr, old, value); + value = cfptr->compare_exchange(old, value); } while (value != old); } @@ -332,7 +331,7 @@ void SATBMarkQueueSet::print_all(const char* msg) { #endif // PRODUCT void SATBMarkQueueSet::abandon_completed_buffers() { - AtomicAccess::store(&_count_and_process_flag, size_t(0)); + _count_and_process_flag.store_relaxed(0u); BufferNode* buffers_to_delete = _list.pop_all(); while (buffers_to_delete != nullptr) { BufferNode* bn = buffers_to_delete; diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.hpp b/src/hotspot/share/gc/shared/satbMarkQueue.hpp index e40b2a3ecf3..d2b14a3cc92 100644 --- a/src/hotspot/share/gc/shared/satbMarkQueue.hpp +++ b/src/hotspot/share/gc/shared/satbMarkQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "memory/allocation.hpp" #include "memory/padded.hpp" #include "oops/oopsHierarchy.hpp" +#include "runtime/atomic.hpp" class Thread; class Monitor; @@ -87,7 +88,7 @@ class SATBMarkQueueSet: public PtrQueueSet { DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, 0); PaddedEnd _list; - volatile size_t _count_and_process_flag; + Atomic _count_and_process_flag; // These are rarely (if ever) changed, so same cache line as count. size_t _process_completed_buffers_threshold; size_t _buffer_enqueue_threshold; @@ -148,12 +149,12 @@ public: // The number of buffers in the list. Racy and not updated atomically // with the set of completed buffers. size_t completed_buffers_num() const { - return _count_and_process_flag >> 1; + return _count_and_process_flag.load_relaxed() >> 1; } // Return true if completed buffers should be processed. bool process_completed_buffers() const { - return (_count_and_process_flag & 1) != 0; + return (_count_and_process_flag.load_relaxed() & 1) != 0; } #ifndef PRODUCT diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index a7cf8e638dd..c1fa4b964b7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -37,6 +37,7 @@ #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "utilities/defaultStream.hpp" +#include "utilities/powerOfTwo.hpp" void ShenandoahArguments::initialize() { #if !(defined AARCH64 || defined AMD64 || defined PPC64 || defined RISCV64) @@ -205,7 +206,7 @@ void ShenandoahArguments::initialize() { } size_t ShenandoahArguments::conservative_max_heap_alignment() { - size_t align = ShenandoahMaxRegionSize; + size_t align = next_power_of_2(ShenandoahMaxRegionSize); if (UseLargePages) { align = MAX2(align, os::large_page_size()); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index e582ea6b189..134ae371bce 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -208,13 +208,13 @@ oop ShenandoahGenerationalHeap::evacuate_object(oop p, Thread* thread) { assert(ShenandoahThreadLocalData::is_evac_allowed(thread), "must be enclosed in oom-evac scope"); - ShenandoahHeapRegion* r = heap_region_containing(p); - assert(!r->is_humongous(), "never evacuate humongous objects"); + ShenandoahHeapRegion* from_region = heap_region_containing(p); + assert(!from_region->is_humongous(), "never evacuate humongous objects"); - ShenandoahAffiliation target_gen = r->affiliation(); - // gc_generation() can change asynchronously and should not be used here. - assert(active_generation() != nullptr, "Error"); - if (active_generation()->is_young() && target_gen == YOUNG_GENERATION) { + // Try to keep the object in the same generation + const ShenandoahAffiliation target_gen = from_region->affiliation(); + + if (target_gen == YOUNG_GENERATION) { markWord mark = p->mark(); if (mark.is_marked()) { // Already forwarded. @@ -224,26 +224,31 @@ oop ShenandoahGenerationalHeap::evacuate_object(oop p, Thread* thread) { if (mark.has_displaced_mark_helper()) { // We don't want to deal with MT here just to ensure we read the right mark word. // Skip the potential promotion attempt for this one. - } else if (age_census()->is_tenurable(r->age() + mark.age())) { - oop result = try_evacuate_object(p, thread, r, OLD_GENERATION); + } else if (age_census()->is_tenurable(from_region->age() + mark.age())) { + // If the object is tenurable, try to promote it + oop result = try_evacuate_object(p, thread, from_region->age()); + + // If we failed to promote this aged object, we'll fall through to code below and evacuate to young-gen. if (result != nullptr) { return result; } - // If we failed to promote this aged object, we'll fall through to code below and evacuate to young-gen. } + return try_evacuate_object(p, thread, from_region->age()); } - return try_evacuate_object(p, thread, r, target_gen); + + assert(target_gen == OLD_GENERATION, "Expected evacuation to old"); + return try_evacuate_object(p, thread, from_region->age()); } // try_evacuate_object registers the object and dirties the associated remembered set information when evacuating // to OLD_GENERATION. -oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, ShenandoahHeapRegion* from_region, - ShenandoahAffiliation target_gen) { +template +oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age) { bool alloc_from_lab = true; bool has_plab = false; HeapWord* copy = nullptr; size_t size = ShenandoahForwarding::size(p); - bool is_promotion = (target_gen == OLD_GENERATION) && from_region->is_young(); + constexpr bool is_promotion = (TO_GENERATION == OLD_GENERATION) && (FROM_GENERATION == YOUNG_GENERATION); #ifdef ASSERT if (ShenandoahOOMDuringEvacALot && @@ -252,7 +257,7 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena } else { #endif if (UseTLAB) { - switch (target_gen) { + switch (TO_GENERATION) { case YOUNG_GENERATION: { copy = allocate_from_gclab(thread, size); if ((copy == nullptr) && (size < ShenandoahThreadLocalData::gclab_size(thread))) { @@ -300,7 +305,7 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena if (copy == nullptr) { // If we failed to allocate in LAB, we'll try a shared allocation. if (!is_promotion || !has_plab || (size > PLAB::min_size())) { - ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size, target_gen, is_promotion); + ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size, TO_GENERATION, is_promotion); copy = allocate_memory(req); alloc_from_lab = false; } @@ -314,8 +319,8 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena #endif if (copy == nullptr) { - if (target_gen == OLD_GENERATION) { - if (from_region->is_young()) { + if (TO_GENERATION == OLD_GENERATION) { + if (FROM_GENERATION == YOUNG_GENERATION) { // Signal that promotion failed. Will evacuate this old object somewhere in young gen. old_generation()->handle_failed_promotion(thread, size); return nullptr; @@ -327,14 +332,12 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena } control_thread()->handle_alloc_failure_evac(size); - oom_evac_handler()->handle_out_of_memory_during_evacuation(); - return ShenandoahBarrierSet::resolve_forwarded(p); } if (ShenandoahEvacTracking) { - evac_tracker()->begin_evacuation(thread, size * HeapWordSize, from_region->affiliation(), target_gen); + evac_tracker()->begin_evacuation(thread, size * HeapWordSize, FROM_GENERATION, TO_GENERATION); } // Copy the object: @@ -342,8 +345,8 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena oop copy_val = cast_to_oop(copy); // Update the age of the evacuated object - if (target_gen == YOUNG_GENERATION && is_aging_cycle()) { - ShenandoahHeap::increase_object_age(copy_val, from_region->age() + 1); + if (TO_GENERATION == YOUNG_GENERATION && is_aging_cycle()) { + increase_object_age(copy_val, from_region_age + 1); } // Try to install the new forwarding pointer. @@ -360,18 +363,12 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena if (ShenandoahEvacTracking) { // Record that the evacuation succeeded - evac_tracker()->end_evacuation(thread, size * HeapWordSize, from_region->affiliation(), target_gen); + evac_tracker()->end_evacuation(thread, size * HeapWordSize, FROM_GENERATION, TO_GENERATION); } - if (target_gen == OLD_GENERATION) { - old_generation()->handle_evacuation(copy, size, from_region->is_young()); - } else { - // When copying to the old generation above, we don't care - // about recording object age in the census stats. - assert(target_gen == YOUNG_GENERATION, "Error"); + if (TO_GENERATION == OLD_GENERATION) { + old_generation()->handle_evacuation(copy, size); } - shenandoah_assert_correct(nullptr, copy_val); - return copy_val; } else { // Failed to evacuate. We need to deal with the object that is left behind. Since this // new allocation is certainly after TAMS, it will be considered live in the next cycle. @@ -382,7 +379,7 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena // For LAB allocations, it is enough to rollback the allocation ptr. Either the next // object will overwrite this stale copy, or the filler object on LAB retirement will // do this. - switch (target_gen) { + switch (TO_GENERATION) { case YOUNG_GENERATION: { ShenandoahThreadLocalData::gclab(thread)->undo_allocation(copy, size); break; @@ -405,14 +402,16 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena // we have to keep the fwdptr initialized and pointing to our (stale) copy. assert(size >= ShenandoahHeap::min_fill_size(), "previously allocated object known to be larger than min_size"); fill_with_object(copy, size); - shenandoah_assert_correct(nullptr, copy_val); - // For non-LAB allocations, the object has already been registered } - shenandoah_assert_correct(nullptr, result); - return result; } + shenandoah_assert_correct(nullptr, result); + return result; } +template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age); +template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age); +template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age); + inline HeapWord* ShenandoahGenerationalHeap::allocate_from_plab(Thread* thread, size_t size, bool is_promotion) { assert(UseTLAB, "TLABs should be enabled"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index ed0223dc6fd..704c8538397 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -87,7 +87,9 @@ public: void update_region_ages(ShenandoahMarkingContext* ctx); oop evacuate_object(oop p, Thread* thread) override; - oop try_evacuate_object(oop p, Thread* thread, ShenandoahHeapRegion* from_region, ShenandoahAffiliation target_gen); + + template + oop try_evacuate_object(oop p, Thread* thread, uint from_region_age); // In the generational mode, we will use these two functions for young, mixed, and global collections. // For young and mixed, the generation argument will be the young generation, otherwise it will be the global generation. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp index 8289b48185b..aa20c686bd8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp @@ -34,4 +34,5 @@ inline bool ShenandoahGenerationalHeap::is_tenurable(const ShenandoahHeapRegion* return _age_census->is_tenurable(r->age()); } + #endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 22a59b5ac18..5c4d10ca8a5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1015,7 +1015,7 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // Record the plab configuration for this result and register the object. if (result != nullptr && req.is_old()) { old_generation()->configure_plab_for_current_thread(req); - if (req.type() == ShenandoahAllocRequest::_alloc_shared_gc) { + if (!req.is_lab_alloc()) { // Register the newly allocated object while we're holding the global lock since there's no synchronization // built in to the implementation of register_object(). There are potential races when multiple independent // threads are allocating objects, some of which might span the same card region. For example, consider diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 338c99c7c55..838326c0288 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -619,7 +619,7 @@ void ShenandoahOldGeneration::log_failed_promotion(LogStream& ls, Thread* thread } } -void ShenandoahOldGeneration::handle_evacuation(HeapWord* obj, size_t words, bool promotion) { +void ShenandoahOldGeneration::handle_evacuation(HeapWord* obj, size_t words) const { // Only register the copy of the object that won the evacuation race. _card_scan->register_object_without_lock(obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp index cd78ed4ef5e..614a1596287 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -179,7 +179,7 @@ public: void log_failed_promotion(LogStream& ls, Thread* thread, size_t size) const; // A successful evacuation re-dirties the cards and registers the object with the remembered set - void handle_evacuation(HeapWord* obj, size_t words, bool promotion); + void handle_evacuation(HeapWord* obj, size_t words) const; // Clear the flag after it is consumed by the control thread bool clear_failed_evacuation() { diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 180ce22b041..24c4bdeac16 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -1087,7 +1087,6 @@ private: ZRelocateSmallAllocator _small_allocator; ZRelocateMediumAllocator _medium_allocator; const size_t _total_forwardings; - volatile size_t _numa_local_forwardings; public: ZRelocateTask(ZRelocationSet* relocation_set, @@ -1104,8 +1103,7 @@ public: _medium_targets(medium_targets), _small_allocator(_generation), _medium_allocator(_generation, shared_medium_targets), - _total_forwardings(relocation_set->nforwardings()), - _numa_local_forwardings(0) { + _total_forwardings(relocation_set->nforwardings()) { for (uint32_t i = 0; i < ZNUMA::count(); i++) { ZRelocationSetParallelIterator* const iter = _iters->addr(i); @@ -1124,18 +1122,17 @@ public: // Signal that we're not using the queue anymore. Used mostly for asserts. _queue->deactivate(); - - if (ZNUMA::is_enabled()) { - log_debug(gc, reloc, numa)("Forwardings relocated NUMA-locally: %zu / %zu (%.0f%%)", - _numa_local_forwardings, _total_forwardings, percent_of(_numa_local_forwardings, _total_forwardings)); - } } virtual void work() { ZRelocateWork small(&_small_allocator, _small_targets->addr(), _generation); ZRelocateWork medium(&_medium_allocator, _medium_targets->addr(), _generation); + const uint32_t num_nodes = ZNUMA::count(); - uint32_t numa_local_forwardings_worker = 0; + const uint32_t start_node = ZNUMA::id(); + uint32_t current_node = start_node; + bool has_affinity = false; + bool has_affinity_current_node = false; const auto do_forwarding = [&](ZForwarding* forwarding) { ZPage* const page = forwarding->page(); @@ -1167,26 +1164,30 @@ public: const auto do_forwarding_one_from_iter = [&]() { ZForwarding* forwarding; - const uint32_t start_node = ZNUMA::id(); - uint32_t current_node = start_node; - for (uint32_t i = 0; i < num_nodes; i++) { + for (;;) { if (_iters->get(current_node).next_if(&forwarding, check_numa_local, current_node)) { - claim_and_do_forwarding(forwarding); - - if (current_node == start_node) { - // Track if this forwarding was relocated on the local NUMA node - numa_local_forwardings_worker++; + // Set thread affinity for NUMA-local processing (if needed) + if (UseNUMA && !has_affinity_current_node) { + os::numa_set_thread_affinity(Thread::current(), ZNUMA::numa_id_to_node(current_node)); + has_affinity = true; + has_affinity_current_node = true; } + // Perform the forwarding task + claim_and_do_forwarding(forwarding); return true; } - // Check next node. + // No work found on the current node, move to the next node current_node = (current_node + 1) % num_nodes; - } + has_affinity_current_node = false; - return false; + // If we've looped back to the starting node there's no more work to do + if (current_node == start_node) { + return false; + } + } }; for (;;) { @@ -1209,11 +1210,13 @@ public: } } - if (ZNUMA::is_enabled()) { - AtomicAccess::add(&_numa_local_forwardings, numa_local_forwardings_worker, memory_order_relaxed); - } - _queue->leave(); + + if (UseNUMA && has_affinity) { + // Restore the affinity of the thread so that it isn't bound to a specific + // node any more + os::numa_set_thread_affinity(Thread::current(), -1); + } } virtual void resize_workers(uint nworkers) { diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 55f13be9b44..db3db14afa2 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -130,7 +130,10 @@ static void z_verify_root_oop_object(zaddress addr, void* p) { static void z_verify_old_oop(zpointer* p) { const zpointer o = *p; - assert(o != zpointer::null, "Old should not contain raw null"); + if (o == zpointer::null) { + guarantee(ZGeneration::young()->is_phase_mark_complete(), "Only possible when flip promoting"); + guarantee(ZHeap::heap()->page(p)->is_allocating(), "Raw nulls only possible in allocating pages"); + } if (!z_is_null_relaxed(o)) { if (ZPointer::is_mark_good(o)) { // Even though the pointer is mark good, we can't verify that it should diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp index b5720351bdf..534c9996cfe 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp @@ -217,7 +217,8 @@ static bool compute_top_frame(const JfrSampleRequest& request, frame& top_frame, const PcDesc* const pc_desc = get_pc_desc(sampled_nm, sampled_pc); if (is_valid(pc_desc)) { intptr_t* const synthetic_sp = sender_sp - sampled_nm->frame_size(); - top_frame = frame(synthetic_sp, synthetic_sp, sender_sp - 2, pc_desc->real_pc(sampled_nm), sampled_nm); + intptr_t* const synthetic_fp = sender_sp AARCH64_ONLY( - frame::sender_sp_offset); + top_frame = frame(synthetic_sp, synthetic_sp, synthetic_fp, pc_desc->real_pc(sampled_nm), sampled_nm); in_continuation = is_in_continuation(top_frame, jt); return true; } diff --git a/src/hotspot/share/memory/memoryReserver.cpp b/src/hotspot/share/memory/memoryReserver.cpp index 11a0422f7b0..e8d1887f59f 100644 --- a/src/hotspot/share/memory/memoryReserver.cpp +++ b/src/hotspot/share/memory/memoryReserver.cpp @@ -437,7 +437,7 @@ ReservedSpace HeapReserver::Instance::try_reserve_range(char *highest_start, if (reserved.is_reserved()) { if (reserved.base() >= aligned_heap_base_min_address && - size <= (uintptr_t)(upper_bound - reserved.base())) { + size <= (size_t)(upper_bound - reserved.base())) { // Got a successful reservation. return reserved; } @@ -546,16 +546,16 @@ ReservedHeapSpace HeapReserver::Instance::reserve_compressed_oops_heap(const siz const size_t attach_point_alignment = lcm(alignment, os_attach_point_alignment); - char* aligned_heap_base_min_address = align_up((char*)HeapBaseMinAddress, alignment); - size_t noaccess_prefix = ((aligned_heap_base_min_address + size) > (char*)OopEncodingHeapMax) ? + uintptr_t aligned_heap_base_min_address = align_up(MAX2(HeapBaseMinAddress, alignment), alignment); + size_t noaccess_prefix = ((aligned_heap_base_min_address + size) > OopEncodingHeapMax) ? noaccess_prefix_size : 0; ReservedSpace reserved{}; // Attempt to alloc at user-given address. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { - reserved = try_reserve_memory(size + noaccess_prefix, alignment, page_size, aligned_heap_base_min_address); - if (reserved.base() != aligned_heap_base_min_address) { // Enforce this exact address. + reserved = try_reserve_memory(size + noaccess_prefix, alignment, page_size, (char*)aligned_heap_base_min_address); + if (reserved.base() != (char*)aligned_heap_base_min_address) { // Enforce this exact address. release(reserved); reserved = {}; } @@ -575,38 +575,41 @@ ReservedHeapSpace HeapReserver::Instance::reserve_compressed_oops_heap(const siz // Attempt to allocate so that we can run without base and scale (32-Bit unscaled compressed oops). // Give it several tries from top of range to bottom. - if (aligned_heap_base_min_address + size <= (char *)UnscaledOopHeapMax) { + if (aligned_heap_base_min_address + size <= UnscaledOopHeapMax) { // Calc address range within we try to attach (range of possible start addresses). - char* const highest_start = align_down((char *)UnscaledOopHeapMax - size, attach_point_alignment); - char* const lowest_start = align_up(aligned_heap_base_min_address, attach_point_alignment); - reserved = try_reserve_range(highest_start, lowest_start, attach_point_alignment, - aligned_heap_base_min_address, (char *)UnscaledOopHeapMax, size, alignment, page_size); + uintptr_t const highest_start = align_down(UnscaledOopHeapMax - size, attach_point_alignment); + uintptr_t const lowest_start = align_up(aligned_heap_base_min_address, attach_point_alignment); + assert(lowest_start <= highest_start, "lowest: " INTPTR_FORMAT " highest: " INTPTR_FORMAT , + lowest_start, highest_start); + reserved = try_reserve_range((char*)highest_start, (char*)lowest_start, attach_point_alignment, + (char*)aligned_heap_base_min_address, (char*)UnscaledOopHeapMax, size, alignment, page_size); } // zerobased: Attempt to allocate in the lower 32G. - char *zerobased_max = (char *)OopEncodingHeapMax; + const uintptr_t zerobased_max = OopEncodingHeapMax; // Give it several tries from top of range to bottom. if (aligned_heap_base_min_address + size <= zerobased_max && // Zerobased theoretical possible. ((!reserved.is_reserved()) || // No previous try succeeded. - (reserved.end() > zerobased_max))) { // Unscaled delivered an arbitrary address. + (reserved.end() > (char*)zerobased_max))) { // Unscaled delivered an arbitrary address. // Release previous reservation release(reserved); // Calc address range within we try to attach (range of possible start addresses). - char *const highest_start = align_down(zerobased_max - size, attach_point_alignment); + uintptr_t const highest_start = align_down(zerobased_max - size, attach_point_alignment); // Need to be careful about size being guaranteed to be less // than UnscaledOopHeapMax due to type constraints. - char *lowest_start = aligned_heap_base_min_address; - uint64_t unscaled_end = UnscaledOopHeapMax - size; - if (unscaled_end < UnscaledOopHeapMax) { // unscaled_end wrapped if size is large - lowest_start = MAX2(lowest_start, (char*)unscaled_end); + uintptr_t lowest_start = aligned_heap_base_min_address; + if (size < UnscaledOopHeapMax) { + lowest_start = MAX2(lowest_start, UnscaledOopHeapMax - size); } lowest_start = align_up(lowest_start, attach_point_alignment); - reserved = try_reserve_range(highest_start, lowest_start, attach_point_alignment, - aligned_heap_base_min_address, zerobased_max, size, alignment, page_size); + assert(lowest_start <= highest_start, "lowest: " INTPTR_FORMAT " highest: " INTPTR_FORMAT, + lowest_start, highest_start); + reserved = try_reserve_range((char*)highest_start, (char*)lowest_start, attach_point_alignment, + (char*)aligned_heap_base_min_address, (char*)zerobased_max, size, alignment, page_size); } // Now we go for heaps with base != 0. We need a noaccess prefix to efficiently @@ -616,17 +619,17 @@ ReservedHeapSpace HeapReserver::Instance::reserve_compressed_oops_heap(const siz // Try to attach at addresses that are aligned to OopEncodingHeapMax. Disjointbase mode. char** addresses = get_attach_addresses_for_disjoint_mode(); int i = 0; - while ((addresses[i] != nullptr) && // End of array not yet reached. - ((!reserved.is_reserved()) || // No previous try succeeded. - (reserved.end() > zerobased_max && // Not zerobased or unscaled address. - // Not disjoint address. + while ((addresses[i] != nullptr) && // End of array not yet reached. + ((!reserved.is_reserved()) || // No previous try succeeded. + (reserved.end() > (char*)zerobased_max && // Not zerobased or unscaled address. + // Not disjoint address. !CompressedOops::is_disjoint_heap_base_address((address)reserved.base())))) { // Release previous reservation release(reserved); char* const attach_point = addresses[i]; - assert(attach_point >= aligned_heap_base_min_address, "Flag support broken"); + assert((uintptr_t)attach_point >= aligned_heap_base_min_address, "Flag support broken"); reserved = try_reserve_memory(size + noaccess_prefix, alignment, page_size, attach_point); i++; } diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 0293f42d791..0598f10b880 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -326,7 +326,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) { // First, cut the simple case of fallthrough region when NONE of // region's phis references itself directly or through a data node. - if (is_possible_unsafe_loop(phase)) { + if (is_possible_unsafe_loop()) { // If we have a possible unsafe loop, check if the region node is actually unreachable from root. if (is_unreachable_from_root(phase)) { _is_unreachable_region = true; @@ -336,7 +336,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) { return false; } -bool RegionNode::is_possible_unsafe_loop(const PhaseGVN* phase) const { +bool RegionNode::is_possible_unsafe_loop() const { uint max = outcnt(); uint i; for (i = 0; i < max; i++) { @@ -634,8 +634,8 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { } } else if (can_reshape && cnt == 1) { // Is it dead loop? - // If it is LoopNopde it had 2 (+1 itself) inputs and - // one of them was cut. The loop is dead if it was EntryContol. + // If it is LoopNode it had 2 (+1 itself) inputs and + // one of them was cut. The loop is dead if it was EntryControl. // Loop node may have only one input because entry path // is removed in PhaseIdealLoop::Dominators(). assert(!this->is_Loop() || cnt_orig <= 3, "Loop node should have 3 or less inputs"); @@ -1392,7 +1392,7 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) { } assert(is_diamond_phi() > 0, "sanity"); assert(req() == 3, "same as region"); - const Node* region = in(0); + RegionNode* region = in(0)->as_Region(); for (uint i = 1; i < 3; i++) { Node* phi_input = in(i); if (phi_input != nullptr && phi_input->is_MergeMem() && region->in(i)->outcnt() == 1) { @@ -1400,8 +1400,9 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) { MergeMemNode* merge_mem = phi_input->as_MergeMem(); uint j = 3 - i; Node* other_phi_input = in(j); - if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory()) { + if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory() && !is_data_loop(region, phi_input, igvn)) { // merge_mem is a successor memory to other_phi_input, and is not pinned inside the diamond, so push it out. + // Only proceed if the transformation doesn't create a data loop // This will allow the diamond to collapse completely if there are no other phis left. igvn->replace_node(this, merge_mem); return true; diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 78ad085e03d..bc0b38e2f97 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -84,7 +84,7 @@ private: bool _is_unreachable_region; LoopStatus _loop_status; - bool is_possible_unsafe_loop(const PhaseGVN* phase) const; + bool is_possible_unsafe_loop() const; bool is_unreachable_from_root(const PhaseGVN* phase) const; public: // Node layout (parallels PhiNode): diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index 524dee6e06a..667270d96b4 100644 --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -1471,6 +1471,65 @@ static OptoReg::Name find_first_set(LRG& lrg, RegMask& mask) { return assigned; } +OptoReg::Name PhaseChaitin::select_bias_lrg_color(LRG& lrg) { + uint bias_lrg1_idx = _lrg_map.find(lrg._copy_bias); + uint bias_lrg2_idx = _lrg_map.find(lrg._copy_bias2); + + // If bias_lrg1 has a color + if (bias_lrg1_idx != 0 && !_ifg->_yanked->test(bias_lrg1_idx)) { + OptoReg::Name reg = lrgs(bias_lrg1_idx).reg(); + // and it is legal for lrg + if (is_legal_reg(lrg, reg)) { + return reg; + } + } + + // If bias_lrg2 has a color + if (bias_lrg2_idx != 0 && !_ifg->_yanked->test(bias_lrg2_idx)) { + OptoReg::Name reg = lrgs(bias_lrg2_idx).reg(); + // and it is legal for lrg + if (is_legal_reg(lrg, reg)) { + return reg; + } + } + + uint bias_lrg_idx = 0; + if (bias_lrg1_idx != 0 && bias_lrg2_idx != 0) { + // Since none of the bias live ranges are part of the IFG yet, constrain the + // definition mask with the bias live range with the least degrees of + // freedom. This will increase the chances of register sharing once the bias + // live range becomes part of the IFG. + lrgs(bias_lrg1_idx).compute_set_mask_size(); + lrgs(bias_lrg2_idx).compute_set_mask_size(); + bias_lrg_idx = lrgs(bias_lrg1_idx).degrees_of_freedom() > + lrgs(bias_lrg2_idx).degrees_of_freedom() + ? bias_lrg2_idx + : bias_lrg1_idx; + } else if (bias_lrg1_idx != 0) { + bias_lrg_idx = bias_lrg1_idx; + } else if (bias_lrg2_idx != 0) { + bias_lrg_idx = bias_lrg2_idx; + } + + // Register masks with offset excludes all mask bits before the offset. + // Such masks are mainly used for allocation from stack slots. Constrain the + // register mask of definition live range using bias mask only if + // both masks have zero offset. + if (bias_lrg_idx != 0 && !lrg.mask().is_offset() && + !lrgs(bias_lrg_idx).mask().is_offset()) { + // Choose a color which is legal for bias_lrg + ResourceMark rm(C->regmask_arena()); + RegMask tempmask(lrg.mask(), C->regmask_arena()); + tempmask.and_with(lrgs(bias_lrg_idx).mask()); + tempmask.clear_to_sets(lrg.num_regs()); + OptoReg::Name reg = find_first_set(lrg, tempmask); + if (OptoReg::is_valid(reg)) { + return reg; + } + } + return OptoReg::Bad; +} + // Choose a color using the biasing heuristic OptoReg::Name PhaseChaitin::bias_color(LRG& lrg) { @@ -1492,25 +1551,10 @@ OptoReg::Name PhaseChaitin::bias_color(LRG& lrg) { } } - uint copy_lrg = _lrg_map.find(lrg._copy_bias); - if (copy_lrg != 0) { - // If he has a color, - if(!_ifg->_yanked->test(copy_lrg)) { - OptoReg::Name reg = lrgs(copy_lrg).reg(); - // And it is legal for you, - if (is_legal_reg(lrg, reg)) { - return reg; - } - } else if (!lrg.mask().is_offset()) { - // Choose a color which is legal for him - ResourceMark rm(C->regmask_arena()); - RegMask tempmask(lrg.mask(), C->regmask_arena()); - tempmask.and_with(lrgs(copy_lrg).mask()); - tempmask.clear_to_sets(lrg.num_regs()); - OptoReg::Name reg = find_first_set(lrg, tempmask); - if (OptoReg::is_valid(reg)) - return reg; - } + // Try biasing the color with non-interfering bias live range[s]. + OptoReg::Name reg = select_bias_lrg_color(lrg); + if (OptoReg::is_valid(reg)) { + return reg; } // If no bias info exists, just go with the register selection ordering @@ -1524,7 +1568,7 @@ OptoReg::Name PhaseChaitin::bias_color(LRG& lrg) { // CNC - Fun hack. Alternate 1st and 2nd selection. Enables post-allocate // copy removal to remove many more copies, by preventing a just-assigned // register from being repeatedly assigned. - OptoReg::Name reg = lrg.mask().find_first_elem(); + reg = lrg.mask().find_first_elem(); if( (++_alternate & 1) && OptoReg::is_valid(reg) ) { // This 'Remove; find; Insert' idiom is an expensive way to find the // SECOND element in the mask. @@ -1640,6 +1684,27 @@ uint PhaseChaitin::Select( ) { } } } + + Node* def = lrg->_def; + if (lrg->is_singledef() && !lrg->_is_bound && def->is_Mach()) { + MachNode* mdef = def->as_Mach(); + if (Matcher::is_register_biasing_candidate(mdef, 1)) { + Node* in1 = mdef->in(mdef->operand_index(1)); + if (in1 != nullptr && lrg->_copy_bias == 0) { + lrg->_copy_bias = _lrg_map.find(in1); + } + } + + // For commutative operations, def allocation can also be + // biased towards LRG of second input's def. + if (Matcher::is_register_biasing_candidate(mdef, 2)) { + Node* in2 = mdef->in(mdef->operand_index(2)); + if (in2 != nullptr && lrg->_copy_bias2 == 0) { + lrg->_copy_bias2 = _lrg_map.find(in2); + } + } + } + //assert(is_infinite_stack == lrg->mask().is_infinite_stack(), "nbrs must not change InfiniteStackedness"); // Aligned pairs need aligned masks assert(!lrg->_is_vector || !lrg->_fat_proj, "sanity"); diff --git a/src/hotspot/share/opto/chaitin.hpp b/src/hotspot/share/opto/chaitin.hpp index b477c54fcae..ac072e94e2b 100644 --- a/src/hotspot/share/opto/chaitin.hpp +++ b/src/hotspot/share/opto/chaitin.hpp @@ -63,6 +63,7 @@ public: uint _risk_bias; // Index of LRG which we want to avoid color uint _copy_bias; // Index of LRG which we want to share color + uint _copy_bias2; // Index of second LRG which we want to share color uint _next; // Index of next LRG in linked list uint _prev; // Index of prev LRG in linked list @@ -703,6 +704,8 @@ private: OptoReg::Name choose_color(LRG& lrg); // Helper function which implements biasing heuristic OptoReg::Name bias_color(LRG& lrg); + // Helper function which implements color biasing + OptoReg::Name select_bias_lrg_color(LRG& lrg); // Split uncolorable live ranges // Return new number of live ranges diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 6a738878a1b..5070a9f00e1 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -35,6 +35,97 @@ #ifndef PRODUCT +// Support for printing properties +class PrintProperties +{ +private: + IdealGraphPrinter* _printer; + +public: + PrintProperties(IdealGraphPrinter* printer) : _printer(printer) {} + void print_node_properties(Node* node); + void print_lrg_properties(const LRG& lrg, const char* buffer); + void print_property(int flag, const char* name); + void print_property(int flag, const char* name, const char* val); + void print_property(int flag, const char* name, int val); +}; + +void PrintProperties::print_node_properties(Node* node) { + const jushort flags = node->flags(); + print_property((flags & Node::Flag_is_Copy), "is_copy"); + print_property((flags & Node::Flag_rematerialize), "rematerialize"); + print_property((flags & Node::Flag_needs_anti_dependence_check), "needs_anti_dependence_check"); + print_property((flags & Node::Flag_is_macro), "is_macro"); + print_property((flags & Node::Flag_is_Con), "is_con"); + print_property((flags & Node::Flag_is_cisc_alternate), "is_cisc_alternate"); + print_property((flags & Node::Flag_is_dead_loop_safe), "is_dead_loop_safe"); + print_property((flags & Node::Flag_may_be_short_branch), "may_be_short_branch"); + print_property((flags & Node::Flag_has_call), "has_call"); + print_property((flags & Node::Flag_has_swapped_edges), "has_swapped_edges"); + Matcher* matcher = _printer->C->matcher(); + if (matcher != nullptr) { + print_property(matcher->is_shared(node),"is_shared"); + print_property(!(matcher->is_shared(node)), "is_shared", IdealGraphPrinter::FALSE_VALUE); + print_property(matcher->is_dontcare(node), "is_dontcare"); + print_property(!(matcher->is_dontcare(node)),"is_dontcare", IdealGraphPrinter::FALSE_VALUE); + Node* old = matcher->find_old_node(node); + if (old != nullptr) { + print_property(true, "old_node_idx", old->_idx); + } + } +} + +void PrintProperties::print_lrg_properties(const LRG &lrg, const char *buffer) { + print_property(true, "mask", buffer); + print_property(true, "mask_size", lrg.mask_size()); + if (lrg._degree_valid) { + print_property(true, "degree", lrg.degree()); + } + print_property(true, "num_regs", lrg.num_regs()); + print_property(true, "reg_pressure", lrg.reg_pressure()); + print_property(true, "cost", lrg._cost); + print_property(true, "area", lrg._area); + print_property(true, "score", lrg.score()); + print_property((lrg._risk_bias != 0), "risk_bias", lrg._risk_bias); + print_property((lrg._copy_bias != 0), "copy_bias", lrg._copy_bias); + print_property((lrg._copy_bias2 != 0), "copy_bias2", lrg._copy_bias2); + print_property(lrg.is_singledef(), "is_singledef"); + print_property(lrg.is_multidef(), "is_multidef"); + print_property(lrg._is_oop, "is_oop"); + print_property(lrg._is_float, "is_float"); + print_property(lrg._is_vector, "is_vector"); + print_property(lrg._is_predicate, "is_predicate"); + print_property(lrg._is_scalable, "is_scalable"); + print_property(lrg._was_spilled1, "was_spilled1"); + print_property(lrg._was_spilled2, "was_spilled2"); + print_property(lrg._direct_conflict, "direct_conflict"); + print_property(lrg._fat_proj, "fat_proj"); + print_property(lrg._was_lo, "_was_lo"); + print_property(lrg._has_copy, "has_copy"); + print_property(lrg._at_risk, "at_risk"); + print_property(lrg._must_spill, "must_spill"); + print_property(lrg._is_bound, "is_bound"); + print_property((lrg._msize_valid && lrg._degree_valid && lrg.lo_degree()), "trivial"); +} + +void PrintProperties::print_property(int flag, const char* name) { + if (flag != 0) { + _printer->print_prop(name, IdealGraphPrinter::TRUE_VALUE); + } +} + +void PrintProperties::print_property(int flag, const char* name, const char* val) { + if (flag != 0) { + _printer->print_prop(name, val); + } +} + +void PrintProperties::print_property(int flag, const char* name, int val) { + if (flag != 0) { + _printer->print_prop(name, val); + } +} + // Constants // Keep consistent with Java constants const char *IdealGraphPrinter::INDENT = " "; @@ -522,54 +613,8 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) { print_prop("jvms", buffer); } - const jushort flags = node->flags(); - if (flags & Node::Flag_is_Copy) { - print_prop("is_copy", "true"); - } - if (flags & Node::Flag_rematerialize) { - print_prop("rematerialize", "true"); - } - if (flags & Node::Flag_needs_anti_dependence_check) { - print_prop("needs_anti_dependence_check", "true"); - } - if (flags & Node::Flag_is_macro) { - print_prop("is_macro", "true"); - } - if (flags & Node::Flag_is_Con) { - print_prop("is_con", "true"); - } - if (flags & Node::Flag_is_cisc_alternate) { - print_prop("is_cisc_alternate", "true"); - } - if (flags & Node::Flag_is_dead_loop_safe) { - print_prop("is_dead_loop_safe", "true"); - } - if (flags & Node::Flag_may_be_short_branch) { - print_prop("may_be_short_branch", "true"); - } - if (flags & Node::Flag_has_call) { - print_prop("has_call", "true"); - } - if (flags & Node::Flag_has_swapped_edges) { - print_prop("has_swapped_edges", "true"); - } - - if (C->matcher() != nullptr) { - if (C->matcher()->is_shared(node)) { - print_prop("is_shared", "true"); - } else { - print_prop("is_shared", "false"); - } - if (C->matcher()->is_dontcare(node)) { - print_prop("is_dontcare", "true"); - } else { - print_prop("is_dontcare", "false"); - } - Node* old = C->matcher()->find_old_node(node); - if (old != nullptr) { - print_prop("old_node_idx", old->_idx); - } - } + PrintProperties print_node(this); + print_node.print_node_properties(node); if (node->is_Proj()) { print_prop("con", (int)node->as_Proj()->_con); @@ -1145,73 +1190,10 @@ void IdealGraphPrinter::print(const char* name, Node* node, GrowableArray { - private: + friend class PrintProperties; +private: static const char *INDENT; static const char *TOP_ELEMENT; static const char *GROUP_ELEMENT; diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp index e58befd8032..ec861865ff5 100644 --- a/src/hotspot/share/opto/machnode.cpp +++ b/src/hotspot/share/opto/machnode.cpp @@ -460,6 +460,13 @@ int MachNode::operand_index(Node* def) const { return -1; } +int MachNode::operand_num_edges(uint oper_index) const { + if (num_opnds() > oper_index) { + return _opnds[oper_index]->num_edges(); + } + return 0; +} + //------------------------------peephole--------------------------------------- // Apply peephole rule(s) to this instruction int MachNode::peephole(Block *block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc *ra_) { diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index 093f466678c..b60313b7f75 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -266,6 +266,7 @@ public: int operand_index(uint operand) const; int operand_index(const MachOper *oper) const; int operand_index(Node* m) const; + int operand_num_edges(uint operand) const; // Register class input is expected in virtual const RegMask &in_RegMask(uint) const; diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index 01f11b1fdc9..ca13d0166a1 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -512,6 +512,8 @@ public: DEBUG_ONLY( bool verify_after_postselect_cleanup(); ) public: + static bool is_register_biasing_candidate(const MachNode* mdef, int oper_index); + // This routine is run whenever a graph fails to match. // If it returns, the compiler should bailout to interpreter without error. // In non-product mode, SoftMatchFailure is false to detect non-canonical diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index ec80fb6a0ab..2e19d1d247b 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -828,26 +828,26 @@ public: #undef DEFINE_CLASS_ID // Flags are sorted by usage frequency. - enum NodeFlags { - Flag_is_Copy = 1 << 0, // should be first bit to avoid shift - Flag_rematerialize = 1 << 1, - Flag_needs_anti_dependence_check = 1 << 2, - Flag_is_macro = 1 << 3, - Flag_is_Con = 1 << 4, - Flag_is_cisc_alternate = 1 << 5, - Flag_is_dead_loop_safe = 1 << 6, - Flag_may_be_short_branch = 1 << 7, - Flag_avoid_back_to_back_before = 1 << 8, - Flag_avoid_back_to_back_after = 1 << 9, - Flag_has_call = 1 << 10, - Flag_has_swapped_edges = 1 << 11, - Flag_is_scheduled = 1 << 12, - Flag_is_expensive = 1 << 13, - Flag_is_predicated_vector = 1 << 14, - Flag_for_post_loop_opts_igvn = 1 << 15, - Flag_for_merge_stores_igvn = 1 << 16, - Flag_is_removed_by_peephole = 1 << 17, - Flag_is_predicated_using_blend = 1 << 18, + enum NodeFlags : uint64_t { + Flag_is_Copy = 1ULL << 0, // should be first bit to avoid shift + Flag_rematerialize = 1ULL << 1, + Flag_needs_anti_dependence_check = 1ULL << 2, + Flag_is_macro = 1ULL << 3, + Flag_is_Con = 1ULL << 4, + Flag_is_cisc_alternate = 1ULL << 5, + Flag_is_dead_loop_safe = 1ULL << 6, + Flag_may_be_short_branch = 1ULL << 7, + Flag_avoid_back_to_back_before = 1ULL << 8, + Flag_avoid_back_to_back_after = 1ULL << 9, + Flag_has_call = 1ULL << 10, + Flag_has_swapped_edges = 1ULL << 11, + Flag_is_scheduled = 1ULL << 12, + Flag_is_expensive = 1ULL << 13, + Flag_is_predicated_vector = 1ULL << 14, + Flag_for_post_loop_opts_igvn = 1ULL << 15, + Flag_for_merge_stores_igvn = 1ULL << 16, + Flag_is_removed_by_peephole = 1ULL << 17, + Flag_is_predicated_using_blend = 1ULL << 18, _last_flag = Flag_is_predicated_using_blend }; diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 98f3d79c9f5..15b2df663b6 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -1022,27 +1022,39 @@ bool VPointer::can_make_speculative_aliasing_check_with(const VPointer& other) c // or at the multiversion_if. That is before the pre-loop. From the construction of // VPointer, we already know that all its variables (except iv) are pre-loop invariant. // - // For the computation of main_init, we also need the pre_limit, and so we need - // to check that this value is pre-loop invariant. In the case of non-equal iv_scales, - // we also need the main_limit in the aliasing check, and so this value must then - // also be pre-loop invariant. + // In VPointer::make_speculative_aliasing_check_with we compute main_init in all + // cases. For this, we require pre_init and pre_limit. These values must be available + // for the speculative check, i.e. their control must dominate the speculative check. + // Further, "if vp1.iv_scale() != vp2.iv_scale()" we additionally need to have + // main_limit available for the speculative check. + // Note: no matter if the speculative check is inserted as a predicate or at the + // multiversion if, the speculative check happens before (dominates) the + // pre-loop. + Node* pre_init = _vloop.pre_loop_end()->init_trip(); Opaque1Node* pre_limit_opaq = _vloop.pre_loop_end()->limit()->as_Opaque1(); Node* pre_limit = pre_limit_opaq->in(1); Node* main_limit = _vloop.cl()->limit(); - - if (!_vloop.is_pre_loop_invariant(pre_limit)) { + if (!_vloop.is_available_for_speculative_check(pre_init)) { #ifdef ASSERT if (_vloop.is_trace_speculative_aliasing_analysis()) { - tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not pre-loop independent!"); + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not available at speculative check!"); + } +#endif + return false; + } + if (!_vloop.is_available_for_speculative_check(pre_limit)) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis()) { + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not available at speculative check!"); } #endif return false; } - if (vp1.iv_scale() != vp2.iv_scale() && !_vloop.is_pre_loop_invariant(main_limit)) { + if (vp1.iv_scale() != vp2.iv_scale() && !_vloop.is_available_for_speculative_check(main_limit)) { #ifdef ASSERT if (_vloop.is_trace_speculative_aliasing_analysis()) { - tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: main_limit is not pre-loop independent!"); + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: main_limit is not available at speculative check!"); } #endif return false; @@ -1119,6 +1131,8 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other, Node* pre_limit = pre_limit_opaq->in(1); assert(_vloop.is_pre_loop_invariant(pre_init), "needed for aliasing check before pre-loop"); assert(_vloop.is_pre_loop_invariant(pre_limit), "needed for aliasing check before pre-loop"); + assert(_vloop.is_available_for_speculative_check(pre_init), "ctrl must be early enough to avoid cycles"); + assert(_vloop.is_available_for_speculative_check(pre_limit), "ctrl must be early enough to avoid cycles"); Node* pre_initL = new ConvI2LNode(pre_init); Node* pre_limitL = new ConvI2LNode(pre_limit); @@ -1180,6 +1194,7 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other, jint main_iv_stride = _vloop.iv_stride(); Node* main_limit = _vloop.cl()->limit(); assert(_vloop.is_pre_loop_invariant(main_limit), "needed for aliasing check before pre-loop"); + assert(_vloop.is_available_for_speculative_check(main_limit), "ctrl must be early enough to avoid cycles"); Node* main_limitL = new ConvI2LNode(main_limit); phase->register_new_node_with_ctrl_of(main_limitL, pre_init); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index f7099b5b7c0..aacd406f798 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -236,6 +236,8 @@ public: // Some nodes must be pre-loop invariant, so that they can be used for conditions // before or inside the pre-loop. For example, alignment of main-loop vector // memops must be achieved in the pre-loop, via the exit check in the pre-loop. + // Note: this condition is NOT strong enough for speculative checks, those happen + // before the pre-loop. See is_available_for_speculative_check bool is_pre_loop_invariant(Node* n) const { // Must be in the main-loop, otherwise we can't access the pre-loop. // This fails during SuperWord::unrolling_analysis, but that is ok. @@ -257,6 +259,28 @@ public: return is_before_pre_loop(early); } + // Nodes that are to be used in speculative checks must be available early enough. + // Note: the speculative check happens before the pre-loop, either at the auto + // vectorization predicate or the multiversion if. This is before the + // pre-loop, and thus the condition here is stronger then the one from + // is_pre_loop_invariant. + bool is_available_for_speculative_check(Node* n) const { + assert(are_speculative_checks_possible(), "meaningless without speculative check"); + ParsePredicateSuccessProj* parse_predicate_proj = auto_vectorization_parse_predicate_proj(); + // Find the control of the predicate: + ProjNode* proj = (parse_predicate_proj != nullptr) ? parse_predicate_proj : multiversioning_fast_proj(); + Node* check_ctrl = proj->in(0)->as_If()->in(0); + + // Often, the control of n already dominates that of the predicate. + Node* n_ctrl = phase()->get_ctrl(n); + if (phase()->is_dominator(n_ctrl, check_ctrl)) { return true; } + + // But in some cases, the ctrl of n is after that of the predicate, + // but the early ctrl is before the predicate. + Node* n_early = phase()->compute_early_ctrl(n, n_ctrl); + return phase()->is_dominator(n_early, check_ctrl); + } + // Check if the loop passes some basic preconditions for vectorization. // Return indicates if analysis succeeded. bool check_preconditions(); diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index b437d2e6eac..93aefe0d505 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -40,38 +40,76 @@ void VTransformGraph::add_vtnode(VTransformNode* vtnode) { } \ ) -// This is similar to IGVN optimization. But we are a bit lazy, and don't care about -// notification / worklist, since the list of nodes is rather small, and we don't -// expect optimizations that trickle over the whole graph. -void VTransformGraph::optimize(VTransform& vtransform) { - TRACE_OPTIMIZE( tty->print_cr("\nVTransformGraph::optimize"); ) - - bool progress = true; - DEBUG_ONLY(int pass_count = 0;) - while (progress) { - progress = false; - assert(++pass_count < 10, "ensure we do not have endless loops"); - for (int i = 0; i < _vtnodes.length(); i++) { - VTransformNode* vtn = _vtnodes.at(i); - if (!vtn->is_alive()) { continue; } - progress |= vtn->optimize(_vloop_analyzer, vtransform); - - // Nodes that have no use any more are dead. - if (vtn->out_strong_edges() == 0 && - // There are some exceptions: - // 1. Memory phi uses are not modeled, so they appear to have no use here, but must be kept alive. - // 2. Similarly, some stores may not have their memory uses modeled, but need to be kept alive. - // 3. Outer node with strong inputs: is a use after the loop that we must keep alive. - !(vtn->isa_PhiScalar() != nullptr || - vtn->is_load_or_store_in_loop() || - (vtn->isa_Outer() != nullptr && vtn->has_strong_in_edge()))) { - vtn->mark_dead(); - progress = true; - } - } +void VTransformOptimize::worklist_push(VTransformNode* vtn) { + if (!_worklist_set.test_set(vtn->_idx)) { + _worklist.push(vtn); } } +VTransformNode* VTransformOptimize::worklist_pop() { + VTransformNode* vtn = _worklist.pop(); + _worklist_set.remove(vtn->_idx); + return vtn; +} + +void VTransform::optimize() { + NOT_PRODUCT( if (vloop().is_trace_optimization()) { tty->print_cr("\nVTransform::optimize"); } ) + ResourceMark rm; + VTransformOptimize vtoptimize(_vloop_analyzer, *this); + vtoptimize.optimize(); +} + +void VTransformOptimize::optimize() { + // Initialize: push all nodes to worklist. + for (int i = 0; i < _vtransform.graph().vtnodes().length(); i++) { + VTransformNode* vtn = _vtransform.graph().vtnodes().at(i); + worklist_push(vtn); + } + + // We don't want to iterate too many times. We set some arbitrary limit, + // just to catch infinite loops. + DEBUG_ONLY( int allowed_steps = 100 * _worklist.length(); ) + + // Optimize iteratively. + while (_worklist.is_nonempty()) { + VTransformNode* vtn = worklist_pop(); + optimize_step(vtn); + assert(--allowed_steps > 0, "no endless loop"); + } + + DEBUG_ONLY( verify(); ) +} + +#ifdef ASSERT +void VTransformOptimize::verify() { + for (int i = 0; i < _vtransform.graph().vtnodes().length(); i++) { + VTransformNode* vtn = _vtransform.graph().vtnodes().at(i); + assert(!optimize_step(vtn), "Missed optimization during VTransform::optimize for %s", vtn->name()); + assert(_worklist.is_empty(), "vtnode on worklist despite no progress for %s", vtn->name()); + } +} +#endif + +// Return true if (and only if) we made progress. +bool VTransformOptimize::optimize_step(VTransformNode* vtn) { + if (!vtn->is_alive()) { return false; } + bool progress = vtn->optimize(*this); + + // Nodes that have no use any more are dead. + if (vtn->out_strong_edges() == 0 && + // There are some exceptions: + // 1. Memory phi uses are not modeled, so they appear to have no use here, but must be kept alive. + // 2. Similarly, some stores may not have their memory uses modeled, but need to be kept alive. + // 3. Outer node with strong inputs: is a use after the loop that we must keep alive. + !(vtn->isa_PhiScalar() != nullptr || + vtn->is_load_or_store_in_loop() || + (vtn->isa_Outer() != nullptr && vtn->has_strong_in_edge()))) { + vtn->mark_dead(*this); + return true; + } + return progress; +} + // Compute a linearization of the graph. We do this with a reverse-post-order of a DFS. // This only works if the graph is a directed acyclic graph (DAG). The C2 graph, and // the VLoopDependencyGraph are both DAGs, but after introduction of vectors/packs, the @@ -1141,8 +1179,8 @@ VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& appl return VTransformApplyResult::make_vector(vn); } -bool VTransformReductionVectorNode::optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { - return optimize_move_non_strict_order_reductions_out_of_loop(vloop_analyzer, vtransform); +bool VTransformReductionVectorNode::optimize(VTransformOptimize& vtoptimize) { + return optimize_move_non_strict_order_reductions_out_of_loop(vtoptimize); } int VTransformReductionVectorNode::vector_reduction_opcode() const { @@ -1213,7 +1251,7 @@ bool VTransformReductionVectorNode::requires_strict_order() const { // become profitable, since the expensive reduction node is moved // outside the loop, and instead cheaper element-wise vector accumulations // are performed inside the loop. -bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop_preconditions(VTransform& vtransform) { +bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop_preconditions(const VTransform& vtransform) { // We have a phi with a single use. VTransformPhiScalarNode* phi = in_req(1)->isa_PhiScalar(); if (phi == nullptr) { @@ -1260,13 +1298,13 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou current_red->element_basic_type() != bt || current_red->vector_length() != vlen) { TRACE_OPTIMIZE( - tty->print(" Cannot move out of loop, other reduction node does not match:"); + tty->print(" Cannot move out of loop, other reduction node does not match: "); print(); tty->print(" other: "); if (current_red != nullptr) { current_red->print(); } else { - tty->print("nullptr"); + tty->print_cr("nullptr"); } ) return false; // not compatible @@ -1314,7 +1352,8 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou return true; // success } -bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { +bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop(VTransformOptimize& vtoptimize) { + VTransform& vtransform = vtoptimize.vtransform(); if (!optimize_move_non_strict_order_reductions_out_of_loop_preconditions(vtransform)) { return false; } @@ -1328,7 +1367,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou const uint vlen = vector_length(); const BasicType bt = element_basic_type(); const int vopc = VectorNode::opcode(sopc, bt); - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + PhaseIdealLoop* phase = vtoptimize.vloop_analyzer().vloop().phase(); // Create a vector of identity values. Node* identity = ReductionNode::make_identity_con_scalar(phase->igvn(), sopc, bt); @@ -1341,6 +1380,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou // Look at old scalar phi. VTransformPhiScalarNode* phi_scalar = in_req(1)->isa_PhiScalar(); PhiNode* old_phi = phi_scalar->node(); + vtoptimize.worklist_push(phi_scalar); VTransformNode* init = phi_scalar->in_req(1); TRACE_OPTIMIZE( @@ -1354,6 +1394,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou phi_vector->init_req(0, phi_scalar->in_req(0)); phi_vector->init_req(1, vtn_identity_vector); // Note: backedge comes later + vtoptimize.worklist_push(phi_vector); // Traverse down the chain of reductions, and replace them with vector_accumulators. VTransformReductionVectorNode* first_red = this; @@ -1365,6 +1406,8 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou VTransformVectorNode* vector_accumulator = new (vtransform.arena()) VTransformElementWiseVectorNode(vtransform, 3, current_red->properties(), vopc); vector_accumulator->init_req(1, current_vector_accumulator); vector_accumulator->init_req(2, vector_input); + vtoptimize.worklist_push(current_red); + vtoptimize.worklist_push(vector_accumulator); TRACE_OPTIMIZE( tty->print(" replace "); current_red->print(); diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index a3e4977494e..b60c71945e1 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -24,6 +24,7 @@ #ifndef SHARE_OPTO_VTRANSFORM_HPP #define SHARE_OPTO_VTRANSFORM_HPP +#include "libadt/vectset.hpp" #include "opto/node.hpp" #include "opto/vectorization.hpp" #include "opto/vectornode.hpp" @@ -192,7 +193,6 @@ public: const GrowableArray& vtnodes() const { return _vtnodes; } const GrowableArray& get_schedule() const { return _schedule; } - void optimize(VTransform& vtransform); bool schedule(); bool has_store_to_load_forwarding_failure(const VLoopAnalyzer& vloop_analyzer) const; float cost_for_vector_loop() const; @@ -257,7 +257,7 @@ public: DEBUG_ONLY( bool has_graph() const { return !_graph.is_empty(); } ) VTransformGraph& graph() { return _graph; } - void optimize() { return _graph.optimize(*this); } + void optimize(); bool schedule() { return _graph.schedule(); } bool is_profitable() const; float cost_for_vector_loop() const { return _graph.cost_for_vector_loop(); } @@ -291,6 +291,36 @@ private: void apply_vectorization() const; }; +// We keep track of the worklist during optimizations. +// The concept is somewhat parallel to IGVN: we keep on +// optimizing vtnodes on the worklist, which may in turn +// add more nodes to the list. We keep on optimizing until +// no more nodes are on the worklist. +class VTransformOptimize : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + VTransform& _vtransform; + + GrowableArray _worklist; + VectorSet _worklist_set; + +public: + VTransformOptimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) : + _vloop_analyzer(vloop_analyzer), + _vtransform(vtransform) {} + + const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; } + VTransform& vtransform() { return _vtransform; } + + void worklist_push(VTransformNode* vtn); + void optimize(); + +private: + VTransformNode* worklist_pop(); + bool optimize_step(VTransformNode* vtn); + DEBUG_ONLY( void verify(); ) +}; + // Keeps track of the state during "VTransform::apply" // -> keep track of the already transformed nodes and the memory state. class VTransformApplyState : public StackObj { @@ -531,10 +561,15 @@ public: bool is_alive() const { return _is_alive; } - void mark_dead() { + void mark_dead(VTransformOptimize& vtoptimize) { _is_alive = false; - // Remove all inputs + // Remove all inputs, and put inputs on worklist in + // case they are also dead. for (uint i = 0; i < req(); i++) { + VTransformNode* in = in_req(i); + if (in != nullptr) { + vtoptimize.worklist_push(in); + } set_req(i, nullptr); } } @@ -558,7 +593,7 @@ public: virtual const VPointer& vpointer() const { ShouldNotReachHere(); } virtual bool is_loop_head_phi() const { return false; } - virtual bool optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { return false; } + virtual bool optimize(VTransformOptimize& vtoptimize) { return false; } virtual float cost(const VLoopAnalyzer& vloop_analyzer) const = 0; @@ -868,7 +903,7 @@ public: VTransformReductionVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : VTransformVectorNode(vtransform, 3, properties) {} virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; } - virtual bool optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) override; + virtual bool optimize(VTransformOptimize& vtoptimize) override; virtual float cost(const VLoopAnalyzer& vloop_analyzer) const override; virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) @@ -876,8 +911,8 @@ public: private: int vector_reduction_opcode() const; bool requires_strict_order() const; - bool optimize_move_non_strict_order_reductions_out_of_loop_preconditions(VTransform& vtransform); - bool optimize_move_non_strict_order_reductions_out_of_loop(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform); + bool optimize_move_non_strict_order_reductions_out_of_loop_preconditions(const VTransform& vtransform); + bool optimize_move_non_strict_order_reductions_out_of_loop(VTransformOptimize& vtoptimize); }; class VTransformPhiVectorNode : public VTransformVectorNode { diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 55ee7641a5f..4a983095593 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1478,10 +1478,10 @@ void Arguments::set_conservative_max_heap_alignment() { // the alignments imposed by several sources: any requirements from the heap // itself and the maximum page size we may run the VM with. size_t heap_alignment = GCConfig::arguments()->conservative_max_heap_alignment(); - _conservative_max_heap_alignment = MAX4(heap_alignment, + _conservative_max_heap_alignment = MAX3(heap_alignment, os::vm_allocation_granularity(), - os::max_page_size(), - GCArguments::compute_heap_alignment()); + os::max_page_size()); + assert(is_power_of_2(_conservative_max_heap_alignment), "Expected to be a power-of-2"); } jint Arguments::set_ergonomics_flags() { @@ -1589,8 +1589,8 @@ void Arguments::set_heap_size() { } if (UseCompressedOops) { - size_t heap_end = HeapBaseMinAddress + MaxHeapSize; - size_t max_coop_heap = max_heap_for_compressed_oops(); + uintptr_t heap_end = HeapBaseMinAddress + MaxHeapSize; + uintptr_t max_coop_heap = max_heap_for_compressed_oops(); // Limit the heap size to the maximum possible when using compressed oops if (heap_end < max_coop_heap) { @@ -1607,7 +1607,7 @@ void Arguments::set_heap_size() { aot_log_info(aot)("UseCompressedOops disabled due to " "max heap %zu > compressed oop heap %zu. " "Please check the setting of MaxRAMPercentage %5.2f.", - reasonable_max, max_coop_heap, MaxRAMPercentage); + reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage); FLAG_SET_ERGO(UseCompressedOops, false); } else { reasonable_max = max_coop_heap; diff --git a/src/hotspot/share/runtime/atomic.hpp b/src/hotspot/share/runtime/atomic.hpp index 5b4d7d8659f..b8960fd796b 100644 --- a/src/hotspot/share/runtime/atomic.hpp +++ b/src/hotspot/share/runtime/atomic.hpp @@ -75,6 +75,7 @@ // v.release_store(x) -> void // v.release_store_fence(x) -> void // v.compare_exchange(x, y [, o]) -> T +// v.exchange(x [, o]) -> T // // (2) All atomic types are default constructible. // @@ -92,7 +93,6 @@ // (3) Atomic pointers and atomic integers additionally provide // // member functions: -// v.exchange(x [, o]) -> T // v.add_then_fetch(i [, o]) -> T // v.sub_then_fetch(i [, o]) -> T // v.fetch_then_add(i [, o]) -> T @@ -102,10 +102,7 @@ // type of i must be signed, or both must be unsigned. Atomic pointers perform // element arithmetic. // -// (4) An atomic translated type additionally provides the exchange -// function if its associated atomic decayed type provides that function. -// -// (5) Atomic integers additionally provide +// (4) Atomic integers additionally provide // // member functions: // v.and_then_fetch(x [, o]) -> T @@ -115,7 +112,7 @@ // v.fetch_then_or(x [, o]) -> T // v.fetch_then_xor(x [, o]) -> T // -// (6) Atomic pointers additionally provide +// (5) Atomic pointers additionally provide // // nested types: // ElementType -> std::remove_pointer_t @@ -127,9 +124,6 @@ // stand out a little more when used in surrounding non-atomic code. Without // the "AtomicAccess::" qualifier, some of those names are easily overlooked. // -// Atomic bytes don't provide exchange(). This is because that operation -// hasn't been implemented for 1 byte values. That could be changed if needed. -// // Atomic for 2 byte integers is not supported. This is because atomic // operations of that size have not been implemented. There haven't been // required use-cases. Many platforms don't provide hardware support. @@ -184,15 +178,8 @@ private: // Helper base classes, providing various parts of the APIs. template class CommonCore; - template class SupportsExchange; template class SupportsArithmetic; - // Support conditional exchange() for atomic translated types. - template class HasExchange; - template class DecayedHasExchange; - template::value> - class TranslatedExchange; - public: template()> class Atomic; @@ -275,15 +262,7 @@ public: atomic_memory_order order = memory_order_conservative) { return AtomicAccess::cmpxchg(value_ptr(), compare_value, new_value, order); } -}; -template -class AtomicImpl::SupportsExchange : public CommonCore { -protected: - explicit SupportsExchange(T value) : CommonCore(value) {} - ~SupportsExchange() = default; - -public: T exchange(T new_value, atomic_memory_order order = memory_order_conservative) { return AtomicAccess::xchg(this->value_ptr(), new_value, order); @@ -291,7 +270,7 @@ public: }; template -class AtomicImpl::SupportsArithmetic : public SupportsExchange { +class AtomicImpl::SupportsArithmetic : public CommonCore { // Guarding the AtomicAccess calls with constexpr checking of Offset produces // better compile-time error messages. template @@ -311,7 +290,7 @@ class AtomicImpl::SupportsArithmetic : public SupportsExchange { } protected: - explicit SupportsArithmetic(T value) : SupportsExchange(value) {} + explicit SupportsArithmetic(T value) : CommonCore(value) {} ~SupportsArithmetic() = default; public: @@ -424,54 +403,8 @@ public: // Atomic translated type -// Test whether Atomic has exchange(). template -class AtomicImpl::HasExchange { - template static void* test(decltype(&Check::exchange)); - template static int test(...); - using test_type = decltype(test>(nullptr)); -public: - static constexpr bool value = std::is_pointer_v; -}; - -// Test whether the atomic decayed type associated with T has exchange(). -template -class AtomicImpl::DecayedHasExchange { - using Translator = PrimitiveConversions::Translate; - using Decayed = typename Translator::Decayed; - - // "Unit test" HasExchange<>. - static_assert(HasExchange::value); - static_assert(HasExchange::value); - static_assert(!HasExchange::value); - -public: - static constexpr bool value = HasExchange::value; -}; - -// Base class for atomic translated type if atomic decayed type doesn't have -// exchange(). -template -class AtomicImpl::TranslatedExchange {}; - -// Base class for atomic translated type if atomic decayed type does have -// exchange(). -template -class AtomicImpl::TranslatedExchange { -public: - T exchange(T new_value, - atomic_memory_order order = memory_order_conservative) { - return static_cast(this)->exchange_impl(new_value, order); - } -}; - -template -class AtomicImpl::Atomic - : public TranslatedExchange, T> -{ - // Give TranslatedExchange<> access to exchange_impl() if needed. - friend class TranslatedExchange, T>; - +class AtomicImpl::Atomic { using Translator = PrimitiveConversions::Translate; using Decayed = typename Translator::Decayed; @@ -533,12 +466,7 @@ public: order)); } -private: - // Implementation of exchange() if needed. - // Exclude when not needed, to prevent reference to non-existent function - // of atomic decayed type if someone explicitly instantiates Atomic. - template::value)> - T exchange_impl(T new_value, atomic_memory_order order) { + T exchange(T new_value, atomic_memory_order order = memory_order_conservative) { return recover(_value.exchange(decay(new_value), order)); } }; diff --git a/src/hotspot/share/runtime/atomicAccess.hpp b/src/hotspot/share/runtime/atomicAccess.hpp index 72b7f92cf04..c9a2dfb9383 100644 --- a/src/hotspot/share/runtime/atomicAccess.hpp +++ b/src/hotspot/share/runtime/atomicAccess.hpp @@ -419,8 +419,8 @@ private: struct XchgImpl; // Platform-specific implementation of xchg. Support for sizes - // of 4, and sizeof(intptr_t) are required. The class is a function - // object that must be default constructable, with these requirements: + // of 1, 4, and 8 are required. The class is a function object + // that must be default constructable, with these requirements: // // - dest is of type T*. // - exchange_value is of type T. @@ -635,7 +635,6 @@ inline void AtomicAccess::dec(D volatile* dest, atomic_memory_order order) { STATIC_ASSERT(std::is_pointer::value || std::is_integral::value); using I = std::conditional_t::value, ptrdiff_t, D>; // Assumes two's complement integer representation. - #pragma warning(suppress: 4146) AtomicAccess::add(dest, I(-1), order); } @@ -652,7 +651,6 @@ inline D AtomicAccess::sub(D volatile* dest, I sub_value, atomic_memory_order or STATIC_ASSERT(sizeof(I) <= sizeof(AddendType)); AddendType addend = sub_value; // Assumes two's complement integer representation. - #pragma warning(suppress: 4146) // In case AddendType is not signed. return AtomicAccess::add(dest, -addend, order); } diff --git a/src/hotspot/share/runtime/cpuTimeCounters.cpp b/src/hotspot/share/runtime/cpuTimeCounters.cpp index e5364550b6c..e174407089c 100644 --- a/src/hotspot/share/runtime/cpuTimeCounters.cpp +++ b/src/hotspot/share/runtime/cpuTimeCounters.cpp @@ -118,8 +118,5 @@ ThreadTotalCPUTimeClosure::~ThreadTotalCPUTimeClosure() { } void ThreadTotalCPUTimeClosure::do_thread(Thread* thread) { - // The default code path (fast_thread_cpu_time()) asserts that - // pthread_getcpuclockid() and clock_gettime() must return 0. Thus caller - // must ensure the thread exists and has not terminated. _total += os::thread_cpu_time(thread); } diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 487528c49bd..51517fa49db 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -162,7 +162,7 @@ void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) co // uintx ThresholdTolerance = 10 {product} {default} // size_t TLABSize = 0 {product} {default} // uintx SurvivorRatio = 8 {product} {default} - // double InitialRAMPercentage = 1.562500 {product} {default} + // double InitialRAMPercentage = 0.000000 {product} {default} // ccstr CompileCommandFile = MyFile.cmd {product} {command line} // ccstrlist CompileOnly = Method1 // CompileOnly += Method2 {product} {command line} diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index e0cbb60c744..a290602e0be 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -664,6 +664,7 @@ void VMError::report(outputStream* st, bool _verbose) { BEGIN if (MemTracker::enabled() && NmtVirtualMemory_lock != nullptr && + _thread != nullptr && NmtVirtualMemory_lock->owned_by_self()) { // Manually unlock to avoid reentrancy due to mallocs in detailed mode. NmtVirtualMemory_lock->unlock(); @@ -1305,7 +1306,7 @@ void VMError::report(outputStream* st, bool _verbose) { os::print_signal_handlers(st, buf, sizeof(buf)); st->cr(); - STEP_IF("Native Memory Tracking", _verbose) + STEP_IF("Native Memory Tracking", _verbose && _thread != nullptr) MemTracker::error_report(st); st->cr(); diff --git a/src/hotspot/share/utilities/waitBarrier_generic.cpp b/src/hotspot/share/utilities/waitBarrier_generic.cpp index a6436d93ffc..b268b10c757 100644 --- a/src/hotspot/share/utilities/waitBarrier_generic.cpp +++ b/src/hotspot/share/utilities/waitBarrier_generic.cpp @@ -23,7 +23,6 @@ * */ -#include "runtime/atomicAccess.hpp" #include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "utilities/spinYield.hpp" @@ -79,10 +78,10 @@ void GenericWaitBarrier::arm(int barrier_tag) { assert(barrier_tag != 0, "Pre arm: Should be arming with armed value"); - assert(AtomicAccess::load(&_barrier_tag) == 0, + assert(_barrier_tag.load_relaxed() == 0, "Pre arm: Should not be already armed. Tag: %d", - AtomicAccess::load(&_barrier_tag)); - AtomicAccess::release_store(&_barrier_tag, barrier_tag); + _barrier_tag.load_relaxed()); + _barrier_tag.release_store(barrier_tag); Cell &cell = tag_to_cell(barrier_tag); cell.arm(barrier_tag); @@ -92,9 +91,9 @@ void GenericWaitBarrier::arm(int barrier_tag) { } void GenericWaitBarrier::disarm() { - int barrier_tag = AtomicAccess::load_acquire(&_barrier_tag); + int barrier_tag = _barrier_tag.load_acquire(); assert(barrier_tag != 0, "Pre disarm: Should be armed. Tag: %d", barrier_tag); - AtomicAccess::release_store(&_barrier_tag, 0); + _barrier_tag.release_store(0); Cell &cell = tag_to_cell(barrier_tag); cell.disarm(barrier_tag); @@ -121,7 +120,7 @@ void GenericWaitBarrier::Cell::arm(int32_t requested_tag) { SpinYield sp; while (true) { - state = AtomicAccess::load_acquire(&_state); + state = _state.load_acquire(); assert(decode_tag(state) == 0, "Pre arm: Should not be armed. " "Tag: " INT32_FORMAT "; Waiters: " INT32_FORMAT, @@ -134,7 +133,7 @@ void GenericWaitBarrier::Cell::arm(int32_t requested_tag) { // Try to swing cell to armed. This should always succeed after the check above. int64_t new_state = encode(requested_tag, 0); - int64_t prev_state = AtomicAccess::cmpxchg(&_state, state, new_state); + int64_t prev_state = _state.compare_exchange(state, new_state); if (prev_state != state) { fatal("Cannot arm the wait barrier. " "Tag: " INT32_FORMAT "; Waiters: " INT32_FORMAT, @@ -145,14 +144,14 @@ void GenericWaitBarrier::Cell::arm(int32_t requested_tag) { int GenericWaitBarrier::Cell::signal_if_needed(int max) { int signals = 0; while (true) { - int cur = AtomicAccess::load_acquire(&_outstanding_wakeups); + int cur = _outstanding_wakeups.load_acquire(); if (cur == 0) { // All done, no more waiters. return 0; } assert(cur > 0, "Sanity"); - int prev = AtomicAccess::cmpxchg(&_outstanding_wakeups, cur, cur - 1); + int prev = _outstanding_wakeups.compare_exchange(cur, cur - 1); if (prev != cur) { // Contention, return to caller for early return or backoff. return prev; @@ -172,7 +171,7 @@ void GenericWaitBarrier::Cell::disarm(int32_t expected_tag) { int32_t waiters; while (true) { - int64_t state = AtomicAccess::load_acquire(&_state); + int64_t state = _state.load_acquire(); int32_t tag = decode_tag(state); waiters = decode_waiters(state); @@ -182,7 +181,7 @@ void GenericWaitBarrier::Cell::disarm(int32_t expected_tag) { tag, waiters); int64_t new_state = encode(0, waiters); - if (AtomicAccess::cmpxchg(&_state, state, new_state) == state) { + if (_state.compare_exchange(state, new_state) == state) { // Successfully disarmed. break; } @@ -191,19 +190,19 @@ void GenericWaitBarrier::Cell::disarm(int32_t expected_tag) { // Wake up waiters, if we have at least one. // Allow other threads to assist with wakeups, if possible. if (waiters > 0) { - AtomicAccess::release_store(&_outstanding_wakeups, waiters); + _outstanding_wakeups.release_store(waiters); SpinYield sp; while (signal_if_needed(INT_MAX) > 0) { sp.wait(); } } - assert(AtomicAccess::load(&_outstanding_wakeups) == 0, "Post disarm: Should not have outstanding wakeups"); + assert(_outstanding_wakeups.load_relaxed() == 0, "Post disarm: Should not have outstanding wakeups"); } void GenericWaitBarrier::Cell::wait(int32_t expected_tag) { // Try to register ourselves as pending waiter. while (true) { - int64_t state = AtomicAccess::load_acquire(&_state); + int64_t state = _state.load_acquire(); int32_t tag = decode_tag(state); if (tag != expected_tag) { // Cell tag had changed while waiting here. This means either the cell had @@ -219,7 +218,7 @@ void GenericWaitBarrier::Cell::wait(int32_t expected_tag) { tag, waiters); int64_t new_state = encode(tag, waiters + 1); - if (AtomicAccess::cmpxchg(&_state, state, new_state) == state) { + if (_state.compare_exchange(state, new_state) == state) { // Success! Proceed to wait. break; } @@ -238,7 +237,7 @@ void GenericWaitBarrier::Cell::wait(int32_t expected_tag) { // Register ourselves as completed waiter before leaving. while (true) { - int64_t state = AtomicAccess::load_acquire(&_state); + int64_t state = _state.load_acquire(); int32_t tag = decode_tag(state); int32_t waiters = decode_waiters(state); @@ -248,7 +247,7 @@ void GenericWaitBarrier::Cell::wait(int32_t expected_tag) { tag, waiters); int64_t new_state = encode(tag, waiters - 1); - if (AtomicAccess::cmpxchg(&_state, state, new_state) == state) { + if (_state.compare_exchange(state, new_state) == state) { // Success! break; } diff --git a/src/hotspot/share/utilities/waitBarrier_generic.hpp b/src/hotspot/share/utilities/waitBarrier_generic.hpp index 8ed9ef3ac6e..0cbba1041db 100644 --- a/src/hotspot/share/utilities/waitBarrier_generic.hpp +++ b/src/hotspot/share/utilities/waitBarrier_generic.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "memory/padded.hpp" +#include "runtime/atomic.hpp" #include "runtime/semaphore.hpp" #include "utilities/globalDefinitions.hpp" @@ -43,10 +44,10 @@ private: Semaphore _sem; // Cell state, tracks the arming + waiters status - volatile int64_t _state; + Atomic _state; // Wakeups to deliver for current waiters - volatile int _outstanding_wakeups; + Atomic _outstanding_wakeups; int signal_if_needed(int max); @@ -83,7 +84,7 @@ private: // Trailing padding to protect the last cell. DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0); - volatile int _barrier_tag; + Atomic _barrier_tag; // Trailing padding to insulate the rest of the barrier from adjacent // data structures. The leading padding is not needed, as cell padding diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 6064b46d50a..51543f835c1 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -315,6 +315,18 @@ final class VirtualThread extends BaseVirtualThread { } } + /** + * Submits the given task to the given executor. If the scheduler is a + * ForkJoinPool then the task is first adapted to a ForkJoinTask. + */ + private void submit(Executor executor, Runnable task) { + if (executor instanceof ForkJoinPool pool) { + pool.submit(ForkJoinTask.adapt(task)); + } else { + executor.execute(task); + } + } + /** * Submits the runContinuation task to the scheduler. For the default scheduler, * and calling it on a worker thread, the task will be pushed to the local queue, @@ -335,12 +347,12 @@ final class VirtualThread extends BaseVirtualThread { if (currentThread().isVirtual()) { Continuation.pin(); try { - scheduler.execute(runContinuation); + submit(scheduler, runContinuation); } finally { Continuation.unpin(); } } else { - scheduler.execute(runContinuation); + submit(scheduler, runContinuation); } done = true; } catch (RejectedExecutionException ree) { @@ -1536,4 +1548,4 @@ final class VirtualThread extends BaseVirtualThread { unblocker.setDaemon(true); unblocker.start(); } -} \ No newline at end of file +} diff --git a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java index 01746e34385..85e99fd3f92 100644 --- a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java +++ b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,7 +72,7 @@ public interface TypeVariable extends Type, Annota Type[] getBounds(); /** - * Returns the {@code GenericDeclaration} object representing the + * Returns a {@code GenericDeclaration} object representing the * generic declaration declared for this type variable. * * @return the generic declaration declared for this type variable. diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index 80c771f5306..3f1d6fae4e4 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -203,7 +203,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) * @throws IOException @@ -340,7 +340,7 @@ public final class Files { * if an unsupported open option is specified or the array contains * attributes that cannot be set atomically when creating the file * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * and the file is being opened for writing (optional specific * exception) @@ -377,7 +377,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported open option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * and the file is being opened for writing (optional specific * exception) @@ -575,10 +575,11 @@ public final class Files { Set.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE); /** - * Creates a new and empty file, failing if the file already exists. The - * check for the existence of the file and the creation of the new file if - * it does not exist are a single operation that is atomic with respect to - * all other filesystem activities that might affect the directory. + * Creates a new and empty file, failing if {@code path} locates an existing + * file. The check for the existence of the file and the creation of the new + * file if it does not exist are a single operation that is atomic with + * respect to all other filesystem activities that might affect the + * directory. * *

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

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

The {@code link} parameter locates the directory entry to create. @@ -1007,8 +1011,8 @@ public final class Files { * if the implementation does not support adding an existing file * to a directory * @throws FileAlreadyExistsException - * if the entry could not otherwise be created because a file of - * that name already exists (optional specific exception) + * if {@code link} locates an existing file + * (optional specific exception) * @throws IOException * if an I/O error occurs */ @@ -2711,7 +2715,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) * @@ -2754,7 +2758,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) * @@ -3161,7 +3165,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) */ @@ -3222,7 +3226,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) */ diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 1f2c8d2ffa6..f289186e0ad 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -560,89 +560,70 @@ public class ForkJoinPool extends AbstractExecutorService * access (which is usually needed anyway). * * Signalling. Signals (in signalWork) cause new or reactivated - * workers to scan for tasks. Method signalWork and its callers - * try to approximate the unattainable goal of having the right - * number of workers activated for the tasks at hand, but must err - * on the side of too many workers vs too few to avoid stalls: + * workers to scan for tasks. SignalWork is invoked in two cases: + * (1) When a task is pushed onto an empty queue, and (2) When a + * worker takes a top-level task from a queue that has additional + * tasks. Together, these suffice in O(log(#threads)) steps to + * fully activate with at least enough workers, and ideally no + * more than required. This ideal is unobtainable: Callers do not + * know whether another worker will finish its current task and + * poll for others without need of a signal (which is otherwise an + * advantage of work-stealing vs other schemes), and also must + * conservatively estimate the triggering conditions of emptiness + * or non-emptiness; all of which usually cause more activations + * than necessary (see below). (Method signalWork is also used as + * failsafe in case of Thread failures in deregisterWorker, to + * activate or create a new worker to replace them). * - * * If computations are purely tree structured, it suffices for - * every worker to activate another when it pushes a task into - * an empty queue, resulting in O(log(#threads)) steps to full - * activation. Emptiness must be conservatively approximated, - * which may result in unnecessary signals. Also, to reduce - * resource usages in some cases, at the expense of slower - * startup in others, activation of an idle thread is preferred - * over creating a new one, here and elsewhere. - * - * * At the other extreme, if "flat" tasks (those that do not in - * turn generate others) come in serially from only a single - * producer, each worker taking a task from a queue should - * propagate a signal if there are more tasks in that - * queue. This is equivalent to, but generally faster than, - * arranging the stealer take multiple tasks, re-pushing one or - * more on its own queue, and signalling (because its queue is - * empty), also resulting in logarithmic full activation - * time. If tasks do not not engage in unbounded loops based on - * the actions of other workers with unknown dependencies loop, - * this form of proagation can be limited to one signal per - * activation (phase change). We distinguish the cases by - * further signalling only if the task is an InterruptibleTask - * (see below), which are the only supported forms of task that - * may do so. - * - * * Because we don't know about usage patterns (or most commonly, - * mixtures), we use both approaches, which present even more - * opportunities to over-signal. (Failure to distinguish these - * cases in terms of submission methods was arguably an early - * design mistake.) Note that in either of these contexts, - * signals may be (and often are) unnecessary because active - * workers continue scanning after running tasks without the - * need to be signalled (which is one reason work stealing is - * often faster than alternatives), so additional workers - * aren't needed. - * - * * For rapidly branching tasks that require full pool resources, - * oversignalling is OK, because signalWork will soon have no - * more workers to create or reactivate. But for others (mainly - * externally submitted tasks), overprovisioning may cause very - * noticeable slowdowns due to contention and resource - * wastage. We reduce impact by deactivating workers when - * queues don't have accessible tasks, but reactivating and - * rescanning if other tasks remain. - * - * * Despite these, signal contention and overhead effects still - * occur during ramp-up and ramp-down of small computations. + * Top-Level scheduling + * ==================== * * Scanning. Method runWorker performs top-level scanning for (and * execution of) tasks by polling a pseudo-random permutation of * the array (by starting at a given index, and using a constant * cyclically exhaustive stride.) It uses the same basic polling * method as WorkQueue.poll(), but restarts with a different - * permutation on each invocation. The pseudorandom generator - * need not have high-quality statistical properties in the long + * permutation on each rescan. The pseudorandom generator need + * not have high-quality statistical properties in the long * term. We use Marsaglia XorShifts, seeded with the Weyl sequence - * from ThreadLocalRandom probes, which are cheap and - * suffice. Each queue's polling attempts to avoid becoming stuck - * when other scanners/pollers stall. Scans do not otherwise - * explicitly take into account core affinities, loads, cache - * localities, etc, However, they do exploit temporal locality - * (which usually approximates these) by preferring to re-poll - * from the same queue after a successful poll before trying - * others, which also reduces bookkeeping, cache traffic, and - * scanning overhead. But it also reduces fairness, which is - * partially counteracted by giving up on detected interference - * (which also reduces contention when too many workers try to - * take small tasks from the same queue). + * from ThreadLocalRandom probes, which are cheap and suffice. * * Deactivation. When no tasks are found by a worker in runWorker, - * it tries to deactivate()), giving up (and rescanning) on "ctl" - * contention. To avoid missed signals during deactivation, the - * method rescans and reactivates if there may have been a missed - * signal during deactivation. To reduce false-alarm reactivations - * while doing so, we scan multiple times (analogously to method - * quiescent()) before trying to reactivate. Because idle workers - * are often not yet blocked (parked), we use a WorkQueue field to - * advertise that a waiter actually needs unparking upon signal. + * it invokes deactivate, that first deactivates (to an IDLE + * phase). Avoiding missed signals during deactivation requires a + * (conservative) rescan, reactivating if there may be tasks to + * poll. Because idle workers are often not yet blocked (parked), + * we use a WorkQueue field to advertise that a waiter actually + * needs unparking upon signal. + * + * When tasks are constructed as (recursive) DAGs, top-level + * scanning is usually infrequent, and doesn't encounter most + * of the following problems addressed by runWorker and awaitWork: + * + * Locality. Polls are organized into "runs", continuing until + * empty or contended, while also minimizing interference by + * postponing bookeeping to ends of runs. This may reduce + * fairness. + * + * Contention. When many workers try to poll few queues, they + * often collide, generating CAS failures and disrupting locality + * of workers already running their tasks. This also leads to + * stalls when tasks cannot be taken because other workers have + * not finished poll operations, which is detected by reading + * ahead in queue arrays. In both cases, workers restart scans in a + * way that approximates randomized backoff. + * + * Oversignalling. When many short top-level tasks are present in + * a small number of queues, the above signalling strategy may + * activate many more workers than needed, worsening locality and + * contention problems, while also generating more global + * contention (field ctl is CASed on every activation and + * deactivation). We filter out (both in runWorker and + * signalWork) attempted signals that are surely not needed + * because the signalled tasks are already taken. + * + * Shutdown and Quiescence + * ======================= * * Quiescence. Workers scan looking for work, giving up when they * don't find any, without being sure that none are available. @@ -892,9 +873,7 @@ public class ForkJoinPool extends AbstractExecutorService * shutdown, runners are interrupted so they can cancel. Since * external joining callers never run these tasks, they must await * cancellation by others, which can occur along several different - * paths. The inability to rely on caller-runs may also require - * extra signalling (resulting in scanning and contention) so is - * done only conditionally in methods push and runworker. + * paths. * * Across these APIs, rules for reporting exceptions for tasks * with results accessed via join() differ from those via get(), @@ -961,9 +940,13 @@ public class ForkJoinPool extends AbstractExecutorService * less-contended applications. To help arrange this, some * non-reference fields are declared as "long" even when ints or * shorts would suffice. For class WorkQueue, an - * embedded @Contended region segregates fields most heavily - * updated by owners from those most commonly read by stealers or - * other management. + * embedded @Contended isolates the very busy top index, along + * with status and bookkeeping fields written (mostly) by owners, + * that otherwise interfere with reading array and base + * fields. There are other variables commonly contributing to + * false-sharing-related performance issues (including fields of + * class Thread), but we can't do much about this except try to + * minimize access. * * Initial sizing and resizing of WorkQueue arrays is an even more * delicate tradeoff because the best strategy systematically @@ -972,13 +955,11 @@ public class ForkJoinPool extends AbstractExecutorService * direct false-sharing and indirect cases due to GC bookkeeping * (cardmarks etc), and reduce the number of resizes, which are * not especially fast because they require atomic transfers. - * Currently, arrays for workers are initialized to be just large - * enough to avoid resizing in most tree-structured tasks, but - * larger for external queues where both false-sharing problems - * and the need for resizing are more common. (Maintenance note: - * any changes in fields, queues, or their uses, or JVM layout - * policies, must be accompanied by re-evaluation of these - * placement and sizing decisions.) + * Currently, arrays are initialized to be just large enough to + * avoid resizing in most tree-structured tasks, but grow rapidly + * until large. (Maintenance note: any changes in fields, queues, + * or their uses, or JVM layout policies, must be accompanied by + * re-evaluation of these placement and sizing decisions.) * * Style notes * =========== @@ -1061,17 +1042,11 @@ public class ForkJoinPool extends AbstractExecutorService static final int DEFAULT_COMMON_MAX_SPARES = 256; /** - * Initial capacity of work-stealing queue array for workers. + * Initial capacity of work-stealing queue array. * Must be a power of two, at least 2. See above. */ static final int INITIAL_QUEUE_CAPACITY = 1 << 6; - /** - * Initial capacity of work-stealing queue array for external queues. - * Must be a power of two, at least 2. See above. - */ - static final int INITIAL_EXTERNAL_QUEUE_CAPACITY = 1 << 9; - // conversions among short, int, long static final int SMASK = 0xffff; // (unsigned) short bits static final long LMASK = 0xffffffffL; // lower 32 bits of long @@ -1211,11 +1186,11 @@ public class ForkJoinPool extends AbstractExecutorService @jdk.internal.vm.annotation.Contended("w") int stackPred; // pool stack (ctl) predecessor link @jdk.internal.vm.annotation.Contended("w") + volatile int parking; // nonzero if parked in awaitWork + @jdk.internal.vm.annotation.Contended("w") volatile int source; // source queue id (or DROPPED) @jdk.internal.vm.annotation.Contended("w") int nsteals; // number of steals from other queues - @jdk.internal.vm.annotation.Contended("w") - volatile int parking; // nonzero if parked in awaitWork // Support for atomic operations private static final Unsafe U; @@ -1248,11 +1223,11 @@ public class ForkJoinPool extends AbstractExecutorService */ WorkQueue(ForkJoinWorkerThread owner, int id, int cfg, boolean clearThreadLocals) { - array = new ForkJoinTask[owner == null ? - INITIAL_EXTERNAL_QUEUE_CAPACITY : - INITIAL_QUEUE_CAPACITY]; - this.owner = owner; this.config = (clearThreadLocals) ? cfg | CLEAR_TLS : cfg; + if ((this.owner = owner) == null) { + array = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; + phase = id | IDLE; + } } /** @@ -1279,27 +1254,27 @@ public class ForkJoinPool extends AbstractExecutorService * @throws RejectedExecutionException if array could not be resized */ final void push(ForkJoinTask task, ForkJoinPool pool, boolean internal) { - int s = top, b = base, m, cap, room; ForkJoinTask[] a; - if ((a = array) != null && (cap = a.length) > 0 && // else disabled - task != null) { - int pk = task.noUserHelp() + 1; // prev slot offset - if ((room = (m = cap - 1) - (s - b)) >= 0) { + int s = top, b = base, m, cap, room; ForkJoinTask[] a, na; + if ((a = array) != null && (cap = a.length) > 0) { // else disabled + int k = (m = cap - 1) & s; + if ((room = m - (s - b)) >= 0) { top = s + 1; - long pos = slotOffset(m & s); + long pos = slotOffset(k); if (!internal) U.putReference(a, pos, task); // inside lock else U.getAndSetReference(a, pos, task); // fully fenced - if (room == 0) // resize - growArray(a, cap, s); + if (room == 0 && (na = growArray(a, cap, s)) != null) + k = ((a = na).length - 1) & s; // resize } if (!internal) unlockPhase(); if (room < 0) throw new RejectedExecutionException("Queue capacity exceeded"); - if ((room == 0 || a[m & (s - pk)] == null) && - pool != null) - pool.signalWork(); // may have appeared empty + if (pool != null && + (room == 0 || + U.getReferenceAcquire(a, slotOffset(m & (s - 1))) == null)) + pool.signalWork(a, k); // may have appeared empty } } @@ -1308,11 +1283,12 @@ public class ForkJoinPool extends AbstractExecutorService * @param a old array * @param cap old array capacity * @param s current top + * @return new array, or null on failure */ - private void growArray(ForkJoinTask[] a, int cap, int s) { - int newCap = cap << 1; + private ForkJoinTask[] growArray(ForkJoinTask[] a, int cap, int s) { + int newCap = (cap >= 1 << 16) ? cap << 1 : cap << 2; + ForkJoinTask[] newArray = null; if (a != null && a.length == cap && cap > 0 && newCap > 0) { - ForkJoinTask[] newArray = null; try { newArray = new ForkJoinTask[newCap]; } catch (OutOfMemoryError ex) { @@ -1329,34 +1305,45 @@ public class ForkJoinPool extends AbstractExecutorService updateArray(newArray); // fully fenced } } + return newArray; } /** - * Takes next task, if one exists, in order specified by mode, - * so acts as either local-pop or local-poll. Called only by owner. - * @param fifo nonzero if FIFO mode + * Takes next task, if one exists, in lifo order. */ - private ForkJoinTask nextLocalTask(int fifo) { + private ForkJoinTask localPop() { ForkJoinTask t = null; - ForkJoinTask[] a = array; - int b = base, p = top, cap; - if (p - b > 0 && a != null && (cap = a.length) > 0) { - for (int m = cap - 1, s, nb;;) { - if (fifo == 0 || (nb = b + 1) == p) { - if ((t = (ForkJoinTask)U.getAndSetReference( - a, slotOffset(m & (s = p - 1)), null)) != null) - updateTop(s); // else lost race for only task - break; + int s = top - 1, cap; long k; ForkJoinTask[] a; + if ((a = array) != null && (cap = a.length) > 0 && + U.getReference(a, k = slotOffset((cap - 1) & s)) != null && + (t = (ForkJoinTask)U.getAndSetReference(a, k, null)) != null) + updateTop(s); + return t; + } + + /** + * Takes next task, if one exists, in fifo order. + */ + private ForkJoinTask localPoll() { + ForkJoinTask t = null; + int p = top, cap; ForkJoinTask[] a; + if ((a = array) != null && (cap = a.length) > 0) { + for (int b = base; p - b > 0; ) { + int nb = b + 1; + long k = slotOffset((cap - 1) & b); + if (U.getReference(a, k) == null) { + if (nb == p) + break; // else base is lagging + while (b == (b = U.getIntAcquire(this, BASE))) + Thread.onSpinWait(); // spin to reduce memory traffic } - if ((t = (ForkJoinTask)U.getAndSetReference( - a, slotOffset(m & b), null)) != null) { + else if ((t = (ForkJoinTask) + U.getAndSetReference(a, k, null)) != null) { updateBase(nb); break; } - while (b == (b = U.getIntAcquire(this, BASE))) - Thread.onSpinWait(); // spin to reduce memory traffic - if (p - b <= 0) - break; + else + b = base; } } return t; @@ -1364,10 +1351,9 @@ public class ForkJoinPool extends AbstractExecutorService /** * Takes next task, if one exists, using configured mode. - * (Always internal, never called for Common pool.) */ final ForkJoinTask nextLocalTask() { - return nextLocalTask(config & FIFO); + return (config & FIFO) == 0 ? localPop() : localPoll(); } /** @@ -1443,12 +1429,12 @@ public class ForkJoinPool extends AbstractExecutorService // specialized execution methods /** - * Runs the given task, as well as remaining local tasks. + * Runs the given task, as well as remaining local tasks */ final void topLevelExec(ForkJoinTask task, int fifo) { while (task != null) { task.doExec(); - task = nextLocalTask(fifo); + task = (fifo != 0) ? localPoll() : localPop(); } } @@ -1578,7 +1564,7 @@ public class ForkJoinPool extends AbstractExecutorService * Cancels all local tasks. Called only by owner. */ final void cancelTasks() { - for (ForkJoinTask t; (t = nextLocalTask(0)) != null; ) { + for (ForkJoinTask t; (t = localPop()) != null; ) { try { t.cancel(false); } catch (Throwable ignore) { @@ -1780,7 +1766,8 @@ public class ForkJoinPool extends AbstractExecutorService * @param w caller's WorkQueue */ final void registerWorker(WorkQueue w) { - if (w != null && (runState & STOP) == 0L) { + if (w != null) { + w.array = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; ThreadLocalRandom.localInit(); int seed = w.stackPred = ThreadLocalRandom.getProbe(); int phaseSeq = seed & ~((IDLE << 1) - 1); // initial phase tag @@ -1858,17 +1845,18 @@ public class ForkJoinPool extends AbstractExecutorService } if ((tryTerminate(false, false) & STOP) == 0L && phase != 0 && w != null && w.source != DROPPED) { - signalWork(); // possibly replace w.cancelTasks(); // clean queue + signalWork(null, 0); // possibly replace } if (ex != null) ForkJoinTask.rethrow(ex); } /** - * Releases an idle worker, or creates one if not enough exist. + * Releases an idle worker, or creates one if not enough exist, + * giving up if array a is nonnull and task at a[k] already taken. */ - final void signalWork() { + final void signalWork(ForkJoinTask[] a, int k) { int pc = parallelism; for (long c = ctl;;) { WorkQueue[] qs = queues; @@ -1884,13 +1872,15 @@ public class ForkJoinPool extends AbstractExecutorService if (sp == 0) { if ((short)(c >>> TC_SHIFT) >= pc) break; - nc = ((c + TC_UNIT) & TC_MASK); + nc = ((c + TC_UNIT) & TC_MASK) | ac; } else if ((v = w) == null) break; else - nc = (v.stackPred & LMASK) | (c & TC_MASK); - if (c == (c = compareAndExchangeCtl(c, nc | ac))) { + nc = (v.stackPred & LMASK) | (c & TC_MASK) | ac; + if (a != null && k < a.length && k >= 0 && a[k] == null) + break; + if (c == (c = ctl) && c == (c = compareAndExchangeCtl(c, nc))) { if (v == null) createWorker(); else { @@ -1973,178 +1963,196 @@ public class ForkJoinPool extends AbstractExecutorService * @param w caller's WorkQueue (may be null on failed initialization) */ final void runWorker(WorkQueue w) { - if (w != null) { - int phase = w.phase, r = w.stackPred; // seed from registerWorker - int fifo = w.config & FIFO, nsteals = 0, src = -1; - for (;;) { - WorkQueue[] qs; + if (w != null && w.phase != 0) { // else unregistered + WorkQueue[] qs; + int r = w.stackPred; // seed from registerWorker + int fifo = (int)config & FIFO, rescans = 0, inactive = 0, taken = 0, n; + while ((runState & STOP) == 0L && (qs = queues) != null && + (n = qs.length) > 0) { + int i = r, step = (r >>> 16) | 1; r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift - if ((runState & STOP) != 0L || (qs = queues) == null) - break; - int n = qs.length, i = r, step = (r >>> 16) | 1; - boolean rescan = false; - scan: for (int l = n; l > 0; --l, i += step) { // scan queues - int j, cap; WorkQueue q; ForkJoinTask[] a; - if ((q = qs[j = i & (n - 1)]) != null && - (a = q.array) != null && (cap = a.length) > 0) { - for (int m = cap - 1, pb = -1, b = q.base;;) { - ForkJoinTask t; long k; + scan: for (int j = n; j != 0; --j, i += step) { + WorkQueue q; int qid; + if ((q = qs[qid = i & (n - 1)]) != null) { + ForkJoinTask[] a; int cap; // poll queue + while ((a = q.array) != null && (cap = a.length) > 0) { + int b, nb, nk; long bp; ForkJoinTask t; t = (ForkJoinTask)U.getReferenceAcquire( - a, k = slotOffset(m & b)); - if (b != (b = q.base) || t == null || - !U.compareAndSetReference(a, k, t, null)) { - if (a[b & m] == null) { - if (rescan) // end of run - break scan; - if (a[(b + 1) & m] == null && - a[(b + 2) & m] == null) { - break; // probably empty + a, bp = slotOffset((cap - 1) & (b = q.base))); + long np = slotOffset(nk = (nb = b + 1) & (cap - 1)); + if (q.base == b) { // else inconsistent + if (t == null) { + if (q.array == a) { // else resized + if (rescans > 0) // ran or stalled + break scan; + if (U.getReference(a, np) == null && + (rescans >= 0 || + (U.getReferenceAcquire(a, bp) == null && + q.top == q.base))) + break; + rescans = 1; // may be stalled } - if (pb == (pb = b)) { // track progress - rescan = true; // stalled; reorder scan + } + else if (inactive != 0) { + if ((inactive = tryReactivate(w)) != 0) { + rescans = 1; // can't take yet break scan; } } - } - else { - boolean propagate; - int nb = q.base = b + 1, prevSrc = src; - w.nsteals = ++nsteals; - w.source = src = j; // volatile - rescan = true; - int nh = t.noUserHelp(); - if (propagate = - (prevSrc != src || nh != 0) && a[nb & m] != null) - signalWork(); - w.topLevelExec(t, fifo); - if ((b = q.base) != nb && !propagate) - break scan; // reduce interference + else if (U.compareAndSetReference(a, bp, t, null)) { + q.base = nb; + Object nt = U.getReferenceAcquire(a, np); + w.source = qid; + rescans = 1; + ++taken; + if (nt != null && // confirm a[nk] + U.getReferenceAcquire(a, np) == nt) + signalWork(a, nk); // propagate + w.topLevelExec(t, fifo); + } } } } } - if (!rescan) { - if (((phase = deactivate(w, phase)) & IDLE) != 0) - break; - src = -1; // re-enable propagation + if (rescans >= 0) + --rescans; + else if (inactive == 0) { + if ((inactive = deactivate(w, taken)) != 0) + taken = 0; } + else if (awaitWork(w) == 0) + inactive = rescans = 0; + else + break; } } } /** - * Deactivates and if necessary awaits signal or termination. + * Tries to deactivate worker, keeping active on contention * - * @param w the worker - * @param phase current phase - * @return current phase, with IDLE set if worker should exit + * @param w the work queue + * @param taken number of stolen tasks since last deactivation + * @return nonzero if inactive */ - private int deactivate(WorkQueue w, int phase) { - if (w == null) // currently impossible - return IDLE; - int p = phase | IDLE, activePhase = phase + (IDLE << 1); - long pc = ctl, qc = (activePhase & LMASK) | ((pc - RC_UNIT) & UMASK); - int sp = w.stackPred = (int)pc; // set ctl stack link - w.phase = p; - if (!compareAndSetCtl(pc, qc)) // try to enqueue - return w.phase = phase; // back out on possible signal - int ac = (short)(qc >>> RC_SHIFT), n; long e; WorkQueue[] qs; - if (((e = runState) & STOP) != 0L || - ((e & SHUTDOWN) != 0L && ac == 0 && quiescent() > 0) || - (qs = queues) == null || (n = qs.length) <= 0) - return IDLE; // terminating - - for (int prechecks = Math.min(ac, 2), // reactivation threshold - k = Math.max(n + (n << 1), SPIN_WAITS << 1);;) { - WorkQueue q; int cap; ForkJoinTask[] a; long c; - if (w.phase == activePhase) - return activePhase; - if (--k < 0) - return awaitWork(w, p); // block, drop, or exit - if ((q = qs[k & (n - 1)]) == null) - Thread.onSpinWait(); - else if ((a = q.array) != null && (cap = a.length) > 0 && - a[q.base & (cap - 1)] != null && --prechecks < 0 && - (int)(c = ctl) == activePhase && - compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) - return w.phase = activePhase; // reactivate + private int deactivate(WorkQueue w, int taken) { + int inactive = 0, phase; + if (w != null && (inactive = (phase = w.phase) & IDLE) == 0) { + long sp = (phase + (IDLE << 1)) & LMASK, pc, c; + w.phase = phase | IDLE; + w.stackPred = (int)(pc = ctl); // set ctl stack link + if (!compareAndSetCtl( // try to enqueue + pc, c = ((pc - RC_UNIT) & UMASK) | sp)) + w.phase = phase; // back out on contention + else { + if (taken != 0) { + w.nsteals += taken; + if ((w.config & CLEAR_TLS) != 0 && + (Thread.currentThread() instanceof ForkJoinWorkerThread f)) + f.resetThreadLocals(); // (instanceof check always true) + } + if (((c & RC_MASK) == 0L && quiescent() > 0) || taken == 0) + inactive = w.phase & IDLE; // check quiescent termination + else { // spin for approx 1 scan cost + int tc = (short)(c >>> TC_SHIFT); + int spins = Math.max((tc << 1) + tc, SPIN_WAITS); + while ((inactive = w.phase & IDLE) != 0 && --spins != 0) + Thread.onSpinWait(); + } + } } + return inactive; + } + + /** + * Reactivates worker w if it is currently top of ctl stack + * + * @param w the work queue + * @return 0 if now active + */ + private int tryReactivate(WorkQueue w) { + int inactive = 0; + if (w != null) { // always true; hoist checks + int sp = w.stackPred, phase, activePhase; long c; + if ((inactive = (phase = w.phase) & IDLE) != 0 && + (int)(c = ctl) == (activePhase = phase + IDLE) && + compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) { + w.phase = activePhase; + inactive = 0; + } + } + return inactive; } /** * Awaits signal or termination. * * @param w the work queue - * @param p current phase (known to be idle) - * @return current phase, with IDLE set if worker should exit + * @return 0 if now active */ - private int awaitWork(WorkQueue w, int p) { - if (w != null) { - ForkJoinWorkerThread t; long deadline; - if ((w.config & CLEAR_TLS) != 0 && (t = w.owner) != null) - t.resetThreadLocals(); // clear before reactivate - if ((ctl & RC_MASK) > 0L) - deadline = 0L; - else if ((deadline = - (((w.source != INVALID_ID) ? keepAlive : TIMEOUT_SLOP)) + - System.currentTimeMillis()) == 0L) - deadline = 1L; // avoid zero - int activePhase = p + IDLE; - if ((p = w.phase) != activePhase && (runState & STOP) == 0L) { + private int awaitWork(WorkQueue w) { + int inactive = 0, phase; + if (w != null) { // always true; hoist checks + long waitTime = (w.source == INVALID_ID) ? 0L : keepAlive; + if ((inactive = (phase = w.phase) & IDLE) != 0) { LockSupport.setCurrentBlocker(this); - w.parking = 1; // enable unpark - while ((p = w.phase) != activePhase) { - boolean trimmable = false; int trim; - Thread.interrupted(); // clear status + int activePhase = phase + IDLE; + for (long deadline = 0L;;) { + Thread.interrupted(); // clear status if ((runState & STOP) != 0L) break; - if (deadline != 0L) { - if ((trim = tryTrim(w, p, deadline)) > 0) - break; - else if (trim < 0) - deadline = 0L; - else - trimmable = true; + boolean trimmable = false; // use timed wait if trimmable + long d = 0L, c; + if (((c = ctl) & RC_MASK) == 0L && (int)c == activePhase) { + long now = System.currentTimeMillis(); + if (deadline == 0L) + deadline = waitTime + now; + if (deadline - now <= TIMEOUT_SLOP) { + if (tryTrim(w, c, activePhase)) + break; + continue; // lost race to trim + } + d = deadline; + trimmable = true; } - U.park(trimmable, deadline); + w.parking = 1; // enable unpark and recheck + if ((inactive = w.phase & IDLE) != 0) + U.park(trimmable, d); + w.parking = 0; // close unpark window + if (inactive == 0 || (inactive = w.phase & IDLE) == 0) + break; } - w.parking = 0; LockSupport.setCurrentBlocker(null); } } - return p; + return inactive; } /** * Tries to remove and deregister worker after timeout, and release - * another to do the same. - * @return > 0: trimmed, < 0 : not trimmable, else 0 + * another to do the same unless new tasks are found. */ - private int tryTrim(WorkQueue w, int phase, long deadline) { - long c, nc; int stat, activePhase, vp, i; WorkQueue[] vs; WorkQueue v; - if ((activePhase = phase + IDLE) != (int)(c = ctl) || w == null) - stat = -1; // no longer ctl top - else if (deadline - System.currentTimeMillis() >= TIMEOUT_SLOP) - stat = 0; // spurious wakeup - else if (!compareAndSetCtl( - c, nc = ((w.stackPred & LMASK) | (RC_MASK & c) | - (TC_MASK & (c - TC_UNIT))))) - stat = -1; // lost race to signaller - else { - stat = 1; - w.source = DROPPED; - w.phase = activePhase; - if ((vp = (int)nc) != 0 && (vs = queues) != null && - vs.length > (i = vp & SMASK) && (v = vs[i]) != null && - compareAndSetCtl( // try to wake up next waiter - nc, ((UMASK & (nc + RC_UNIT)) | - (nc & TC_MASK) | (v.stackPred & LMASK)))) { - v.source = INVALID_ID; // enable cascaded timeouts - v.phase = vp; - U.unpark(v.owner); + private boolean tryTrim(WorkQueue w, long c, int activePhase) { + if (w != null) { + int vp, i; WorkQueue[] vs; WorkQueue v; + long nc = ((w.stackPred & LMASK) | + ((RC_MASK & c) | (TC_MASK & (c - TC_UNIT)))); + if (compareAndSetCtl(c, nc)) { + w.source = DROPPED; + w.phase = activePhase; + if ((vp = (int)nc) != 0 && (vs = queues) != null && + vs.length > (i = vp & SMASK) && (v = vs[i]) != null && + compareAndSetCtl( // try to wake up next waiter + nc, ((v.stackPred & LMASK) | + ((UMASK & (nc + RC_UNIT)) | (nc & TC_MASK))))) { + v.source = INVALID_ID; // enable cascaded timeouts + v.phase = vp; + U.unpark(v.owner); + } + return true; } } - return stat; + return false; } /** @@ -2561,52 +2569,35 @@ public class ForkJoinPool extends AbstractExecutorService /** * Finds and locks a WorkQueue for an external submitter, or - * throws RejectedExecutionException if shutdown or terminating. - * @param r current ThreadLocalRandom.getProbe() value + * throws RejectedExecutionException if shutdown * @param rejectOnShutdown true if RejectedExecutionException - * should be thrown when shutdown (else only if terminating) + * should be thrown when shutdown */ - private WorkQueue submissionQueue(int r, boolean rejectOnShutdown) { - int reuse; // nonzero if prefer create - if ((reuse = r) == 0) { - ThreadLocalRandom.localInit(); // initialize caller's probe + final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) { + int r; + if ((r = ThreadLocalRandom.getProbe()) == 0) { + ThreadLocalRandom.localInit(); // initialize caller's probe r = ThreadLocalRandom.getProbe(); } - for (int probes = 0; ; ++probes) { - int n, i, id; WorkQueue[] qs; WorkQueue q; - if ((qs = queues) == null) - break; - if ((n = qs.length) <= 0) + for (;;) { + WorkQueue q; WorkQueue[] qs; int n, id, i; + if ((qs = queues) == null || (n = qs.length) <= 0) break; if ((q = qs[i = (id = r & EXTERNAL_ID_MASK) & (n - 1)]) == null) { - WorkQueue w = new WorkQueue(null, id, 0, false); - w.phase = id; - boolean reject = ((lockRunState() & SHUTDOWN) != 0 && - rejectOnShutdown); - if (!reject && queues == qs && qs[i] == null) - q = qs[i] = w; // else lost race to install + WorkQueue newq = new WorkQueue(null, id, 0, false); + lockRunState(); + if (qs[i] == null && queues == qs) + q = qs[i] = newq; // else lost race to install unlockRunState(); - if (q != null) - return q; - if (reject) + } + if (q != null && q.tryLockPhase()) { + if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) { + q.unlockPhase(); // check while q lock held break; - reuse = 0; - } - if (reuse == 0 || !q.tryLockPhase()) { // move index - if (reuse == 0) { - if (probes >= n >> 1) - reuse = r; // stop prefering free slot } - else if (q != null) - reuse = 0; // probe on collision - r = ThreadLocalRandom.advanceProbe(r); - } - else if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) { - q.unlockPhase(); // check while q lock held - break; - } - else return q; + } + r = ThreadLocalRandom.advanceProbe(r); // move } throw new RejectedExecutionException(); } @@ -2620,24 +2611,12 @@ public class ForkJoinPool extends AbstractExecutorService } else { // find and lock queue internal = false; - q = submissionQueue(ThreadLocalRandom.getProbe(), true); + q = externalSubmissionQueue(true); } q.push(task, signalIfEmpty ? this : null, internal); return task; } - /** - * Returns queue for an external submission, bypassing call to - * submissionQueue if already established and unlocked. - */ - final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) { - WorkQueue[] qs; WorkQueue q; int n; - int r = ThreadLocalRandom.getProbe(); - return (((qs = queues) != null && (n = qs.length) > 0 && - (q = qs[r & EXTERNAL_ID_MASK & (n - 1)]) != null && r != 0 && - q.tryLockPhase()) ? q : submissionQueue(r, rejectOnShutdown)); - } - /** * Returns queue for an external thread, if one exists that has * possibly ever submitted to the given pool (nonzero probe), or @@ -3310,11 +3289,14 @@ public class ForkJoinPool extends AbstractExecutorService * @since 19 */ public int setParallelism(int size) { + int prevSize; if (size < 1 || size > MAX_CAP) throw new IllegalArgumentException(); if ((config & PRESET_SIZE) != 0) throw new UnsupportedOperationException("Cannot override System property"); - return getAndSetParallelism(size); + if ((prevSize = getAndSetParallelism(size)) < size) + signalWork(null, 0); // trigger worker activation + return prevSize; } /** diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java index 118d648c7a2..787d8d5fecd 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -588,13 +588,15 @@ public class LinkedTransferQueue extends AbstractQueue do { m = p.item; q = p.next; - if (p.isData != haveData && haveData != (m != null) && - p.cmpExItem(m, e) == m) { - Thread w = p.waiter; // matched complementary node - if (p != h && h == cmpExHead(h, (q == null) ? p : q)) - h.next = h; // advance head; self-link old - LockSupport.unpark(w); - return m; + if (p.isData != haveData && haveData != (m != null)) { + if (p.cmpExItem(m, e) == m) { + Thread w = p.waiter; // matched complementary node + if (p != h && h == cmpExHead(h, (q == null) ? p : q)) + h.next = h; // advance head; self-link old + LockSupport.unpark(w); + return m; + } + continue restart; } else if (q == null) { if (ns == 0L) // try to append unless immediate break restart; diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java index 941d6bd55cb..01bf1158bf6 100644 --- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java @@ -914,8 +914,8 @@ public sealed interface StructuredTaskScope * forking subtasks will create an unnamed virtual thread for each subtask. * *

If a {@linkplain Configuration#withTimeout(Duration) timeout} is set then it - * starts when the scope is opened. If the timeout expires before the scope has - * {@linkplain #join() joined} then the scope is {@linkplain ##Cancellation cancelled} + * starts when the scope is opened. If the timeout expires before or while waiting in + * {@link #join()} then the scope is {@linkplain ##Cancellation cancelled} * and the {@code Joiner}'s {@link Joiner#onTimeout() onTimeout()} method is invoked * to optionally throw {@link TimeoutException TimeoutException}. * diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java index 3713d616a3a..deed7f018c3 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -128,11 +128,6 @@ public final class ThreadLocalRandom extends Random { * Implementations of non-core methods are mostly the same as in * SplittableRandom, that were in part derived from a previous * version of this class. - * - * This implementation of ThreadLocalRandom overrides the - * definition of the nextGaussian() method in the class Random, - * and instead uses the ziggurat-based algorithm that is the - * default for the RandomGenerator interface. */ private static int mix32(long z) { @@ -499,6 +494,23 @@ public final class ThreadLocalRandom extends Random { return super.nextLong(origin, bound); } + /** + * Returns a {@code double} value pseudorandomly chosen from a Gaussian + * (normal) distribution whose mean is 0 and whose standard deviation is 1. + * + * @return a {@code double} value pseudorandomly chosen from a + * Gaussian distribution + * + * @implNote This implementation invokes the default implementation of + * {@link java.util.random.RandomGenerator#nextGaussian()}, + * and so it uses McFarland's fast modified ziggurat algorithm + * rather than the polar method described in the superclass. + */ + @Override + public double nextGaussian() { + return RandomSupport.computeNextGaussian(this); + } + /** * {@inheritDoc} */ @@ -510,7 +522,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} * * @since 17 */ @@ -522,7 +533,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} * * @since 17 */ @@ -542,7 +552,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} */ @Override public double nextDouble(double bound) { @@ -552,7 +561,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} */ @Override public double nextDouble(double origin, double bound) { diff --git a/src/java.base/share/classes/java/util/random/RandomGenerator.java b/src/java.base/share/classes/java/util/random/RandomGenerator.java index e019e073a2d..2195774e591 100644 --- a/src/java.base/share/classes/java/util/random/RandomGenerator.java +++ b/src/java.base/share/classes/java/util/random/RandomGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -917,7 +917,6 @@ public interface RandomGenerator { * a discrete distribution also plays a role. */ default double nextGaussian() { - // See Knuth, TAOCP, Vol. 2, 3rd edition, Section 3.4.1 Algorithm C. return RandomSupport.computeNextGaussian(this); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java index 5be14f42baa..e4e67afb17f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,11 @@ */ package jdk.internal.classfile.impl; -import java.io.BufferedInputStream; -import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.lang.classfile.ClassHierarchyResolver; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.Collection; import java.util.HashMap; @@ -38,7 +37,6 @@ import java.util.Map; import java.util.function.Function; import static java.lang.classfile.ClassFile.ACC_INTERFACE; -import static java.lang.classfile.constantpool.PoolEntry.*; import static java.lang.constant.ConstantDescs.CD_Object; import static java.util.Objects.requireNonNull; import static jdk.internal.constant.ConstantUtils.referenceClassDesc; @@ -164,31 +162,12 @@ public final class ClassHierarchyImpl { public ClassHierarchyResolver.ClassHierarchyInfo getClassInfo(ClassDesc classDesc) { var ci = streamProvider.apply(classDesc); if (ci == null) return null; - try (var in = new DataInputStream(new BufferedInputStream(ci))) { - in.skipBytes(8); - int cpLength = in.readUnsignedShort(); - String[] cpStrings = new String[cpLength]; - int[] cpClasses = new int[cpLength]; - for (int i = 1; i < cpLength; i++) { - int tag; - switch (tag = in.readUnsignedByte()) { - case TAG_UTF8 -> cpStrings[i] = in.readUTF(); - case TAG_CLASS -> cpClasses[i] = in.readUnsignedShort(); - case TAG_STRING, TAG_METHOD_TYPE, TAG_MODULE, TAG_PACKAGE -> in.skipBytes(2); - case TAG_METHOD_HANDLE -> in.skipBytes(3); - case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, TAG_INTERFACE_METHODREF, - TAG_NAME_AND_TYPE, TAG_DYNAMIC, TAG_INVOKE_DYNAMIC -> in.skipBytes(4); - case TAG_LONG, TAG_DOUBLE -> { - in.skipBytes(8); - i++; - } - default -> throw new IllegalStateException("Bad tag (" + tag + ") at index (" + i + ")"); - } - } - boolean isInterface = (in.readUnsignedShort() & ACC_INTERFACE) != 0; - in.skipBytes(2); - int superIndex = in.readUnsignedShort(); - var superClass = superIndex > 0 ? ClassDesc.ofInternalName(cpStrings[cpClasses[superIndex]]) : null; + try (ci) { + var reader = new ClassReaderImpl(ci.readAllBytes(), ClassFileImpl.DEFAULT_CONTEXT); + boolean isInterface = (reader.flags() & ACC_INTERFACE) != 0; + ClassDesc superClass = reader.superclassEntry() + .map(ClassEntry::asSymbol) + .orElse(null); return new ClassHierarchyInfoImpl(superClass, isInterface); } catch (IOException ioe) { throw new UncheckedIOException(ioe); diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index 3edcac2e44c..728ee235547 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -212,7 +212,9 @@ public class SegmentFactories { allocationBase = allocateMemoryWrapper(allocationSize); result = Utils.alignUp(allocationBase, byteAlignment); } else { - allocationSize = alignedSize; + // always allocate at least 'byteAlignment' bytes, so that malloc is guaranteed to + // return a pointer aligned to that alignment, for cases where byteAlignment > alignedSize + allocationSize = Math.max(alignedSize, byteAlignment); if (shouldReserve) { AbstractMemorySegmentImpl.NIO_ACCESS.reserveMemory(allocationSize, byteSize); } diff --git a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java index d24cc77600c..eb3f25ceca7 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java +++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -225,6 +225,7 @@ public final class ModulePatcher { private final ModuleReference mref; private final URL delegateCodeSourceURL; private volatile ModuleReader delegate; + private volatile boolean closed; /** * Creates the ModuleReader to reads resources in a patched module. @@ -291,6 +292,15 @@ public final class ModulePatcher { return r; } + /** + * Throws an IOException if the ModuleReader is closed. + */ + private void ensureOpen() throws IOException { + if (closed) { + throw new IOException("ModuleReader is closed"); + } + } + /** * Finds a resources in the patch locations. Returns null if not found * or the name is "module-info.class" as that cannot be overridden. @@ -310,7 +320,7 @@ public final class ModulePatcher { * Finds a resource of the given name in the patched module. */ public Resource findResource(String name) throws IOException { - + assert !closed : "module reader is closed"; // patch locations Resource r = findResourceInPatch(name); if (r != null) @@ -354,6 +364,7 @@ public final class ModulePatcher { @Override public Optional find(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { URI uri = URI.create(r.getURL().toString()); @@ -365,6 +376,7 @@ public final class ModulePatcher { @Override public Optional open(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { return Optional.of(r.getInputStream()); @@ -375,6 +387,7 @@ public final class ModulePatcher { @Override public Optional read(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { ByteBuffer bb = r.getByteBuffer(); @@ -398,6 +411,7 @@ public final class ModulePatcher { @Override public Stream list() throws IOException { + ensureOpen(); Stream s = delegate().list(); for (ResourceFinder finder : finders) { s = Stream.concat(s, finder.list()); @@ -407,6 +421,10 @@ public final class ModulePatcher { @Override public void close() throws IOException { + if (closed) { + return; + } + closed = true; closeAll(finders); delegate().close(); } diff --git a/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java b/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java index 5cf0c999fb9..15b3c450d03 100644 --- a/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java +++ b/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java @@ -74,7 +74,7 @@ public final class QuicTLSContext { /** * {@return {@code true} if protocols of the given {@code parameters} support QUIC TLS, {@code false} otherwise} */ - public static boolean isQuicCompatible(SSLParameters parameters) { + private static boolean isQuicCompatible(SSLParameters parameters) { String[] protocols = parameters.getProtocols(); return protocols != null && Arrays.asList(protocols).contains("TLSv1.3"); } diff --git a/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java b/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java index 75750d38f2f..560e9a4f7c9 100644 --- a/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java +++ b/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ import java.lang.reflect.TypeVariable; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; + +import jdk.internal.reflect.ReflectionFactory; import sun.reflect.annotation.AnnotationSupport; import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.annotation.AnnotationType; @@ -125,18 +127,24 @@ public class TypeVariableImpl } /** - * Returns the {@code GenericDeclaration} object representing the + * Returns a {@code GenericDeclaration} object representing the * generic declaration that declared this type variable. * - * @return the generic declaration that declared this type variable. + * @return a generic declaration that declared this type variable. * * @since 1.5 */ + @SuppressWarnings("unchecked") public D getGenericDeclaration() { assert genericDeclaration instanceof Class || genericDeclaration instanceof Method || genericDeclaration instanceof Constructor : "Unexpected kind of GenericDeclaration"; - return genericDeclaration; + // If the `genericDeclaration` instance is mutable, we need to make a copy. + return switch (genericDeclaration) { + case Method method -> (D) ReflectionFactory.getReflectionFactory().copyMethod(method); + case Constructor ctor -> (D) ReflectionFactory.getReflectionFactory().copyConstructor(ctor); + default -> genericDeclaration; + }; } diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 462baa5a4a0..8517e161e3f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2455,8 +2455,7 @@ Java HotSpot VM. `-XX:InitialRAMPercentage=`*percent* : Sets the initial amount of memory that the JVM will use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount - determined as described in the `-XX:MaxRAM` option. The default value is - 0.2 percent. + determined as described in the `-XX:MaxRAM` option. The following example shows how to set the percentage of the initial amount of memory used for the Java heap: diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java index a3098bd9684..63cc1464460 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,7 @@ public class BMPImageReaderSpi extends ImageReaderSpi { null, null); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -69,10 +70,12 @@ public class BMPImageReaderSpi extends ImageReaderSpi { registered = true; } + @Override public String getDescription(Locale locale) { return "Standard BMP Image Reader"; } + @Override public boolean canDecodeInput(Object source) throws IOException { if (!(source instanceof ImageInputStream)) { return false; @@ -87,6 +90,7 @@ public class BMPImageReaderSpi extends ImageReaderSpi { return full && (b[0] == 0x42) && (b[1] == 0x4d); } + @Override public ImageReader createReaderInstance(Object extension) throws IIOException { return new BMPImageReader(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java index ae6a7f65a3b..736a1c2194e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,10 +66,12 @@ public class BMPImageWriterSpi extends ImageWriterSpi { null, null); } + @Override public String getDescription(Locale locale) { return "Standard BMP Image Writer"; } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -79,6 +81,7 @@ public class BMPImageWriterSpi extends ImageWriterSpi { registered = true; } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { int dataType= type.getSampleModel().getDataType(); if (dataType < DataBuffer.TYPE_BYTE || dataType > DataBuffer.TYPE_INT) @@ -99,6 +102,7 @@ public class BMPImageWriterSpi extends ImageWriterSpi { return true; } + @Override public ImageWriter createWriterInstance(Object extension) throws IIOException { return new BMPImageWriter(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java index 5e5a4a52d35..48d3bb12f1c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,10 +94,12 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { null, null); } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -177,6 +179,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { } // Standard tree node methods + @Override protected IIOMetadataNode getStandardChromaNode() { if ((palette != null) && (paletteSize > 0)) { @@ -202,6 +205,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return null; } + @Override protected IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode node = new IIOMetadataNode("Compression"); @@ -212,6 +216,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return node; } + @Override protected IIOMetadataNode getStandardDataNode() { IIOMetadataNode node = new IIOMetadataNode("Data"); @@ -230,6 +235,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return node; } + @Override protected IIOMetadataNode getStandardDimensionNode() { if (yPixelsPerMeter > 0.0F && xPixelsPerMeter > 0.0F) { IIOMetadataNode node = new IIOMetadataNode("Dimension"); @@ -251,14 +257,17 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return null; } + @Override public void setFromTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("BMPMetadata1")); } + @Override public void mergeTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("BMPMetadata1")); } + @Override public void reset() { throw new IllegalStateException(I18N.getString("BMPMetadata1")); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java index b9ea0ee0fe3..277169a34e0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -194,6 +194,7 @@ public class BMPMetadataFormat extends IIOMetadataFormatImpl { DATATYPE_STRING, true, null); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java index 1f2f444acd7..4d6c4fe49ec 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ public class BMPMetadataFormatResources extends ListResourceBundle { public BMPMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java index 5a064f4f4c5..107ee313b70 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,6 +79,7 @@ public class BogusColorSpace extends ColorSpace { // specified behavior of the methods vis-a-vis exceptions. // + @Override public float[] toRGB(float[] colorvalue) { if(colorvalue.length < getNumComponents()) { throw new ArrayIndexOutOfBoundsException @@ -93,6 +94,7 @@ public class BogusColorSpace extends ColorSpace { return rgbvalue; } + @Override public float[] fromRGB(float[] rgbvalue) { if(rgbvalue.length < 3) { throw new ArrayIndexOutOfBoundsException @@ -107,6 +109,7 @@ public class BogusColorSpace extends ColorSpace { return colorvalue; } + @Override public float[] toCIEXYZ(float[] colorvalue) { if(colorvalue.length < getNumComponents()) { throw new ArrayIndexOutOfBoundsException @@ -121,6 +124,7 @@ public class BogusColorSpace extends ColorSpace { return xyzvalue; } + @Override public float[] fromCIEXYZ(float[] xyzvalue) { if(xyzvalue.length < 3) { throw new ArrayIndexOutOfBoundsException diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java index 1b63a54d8ff..b11ffeb6287 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,10 +39,12 @@ public class InputStreamAdapter extends InputStream { this.stream = stream; } + @Override public int read() throws IOException { return stream.read(); } + @Override public int read(byte[] b, int off, int len) throws IOException { return stream.read(b, off, len); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java index a5c283e6c9c..1662d09984d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,14 +58,17 @@ public final class SimpleCMYKColorSpace extends ColorSpace { csRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); } + @Override public boolean equals(Object o) { return o instanceof SimpleCMYKColorSpace; } + @Override public int hashCode() { return System.identityHashCode(theInstance); } + @Override public float[] toRGB(float[] colorvalue) { float C = colorvalue[0]; float M = colorvalue[1]; @@ -97,6 +100,7 @@ public final class SimpleCMYKColorSpace extends ColorSpace { return rgbvalue; } + @Override public float[] fromRGB(float[] rgbvalue) { // Convert from sRGB to linear RGB. for (int i = 0; i < 3; i++) { @@ -128,10 +132,12 @@ public final class SimpleCMYKColorSpace extends ColorSpace { return new float[] {C, M, Y, K}; } + @Override public float[] toCIEXYZ(float[] colorvalue) { return csRGB.toCIEXYZ(toRGB(colorvalue)); } + @Override public float[] fromCIEXYZ(float[] xyzvalue) { return fromRGB(csRGB.fromCIEXYZ(xyzvalue)); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java index 1d8c850b4a9..f598aeb06a1 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,6 +74,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { protected Hashtable properties = new Hashtable(); /** Returns the X coordinate of the leftmost column of the image. */ + @Override public int getMinX() { return minX; } @@ -89,6 +90,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { } /** Returns the X coordinate of the uppermost row of the image. */ + @Override public int getMinY() { return minY; } @@ -104,11 +106,13 @@ public abstract class SimpleRenderedImage implements RenderedImage { } /** Returns the width of the image. */ + @Override public int getWidth() { return width; } /** Returns the height of the image. */ + @Override public int getHeight() { return height; } @@ -119,11 +123,13 @@ public abstract class SimpleRenderedImage implements RenderedImage { } /** Returns the width of a tile. */ + @Override public int getTileWidth() { return tileWidth; } /** Returns the height of a tile. */ + @Override public int getTileHeight() { return tileHeight; } @@ -131,6 +137,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { /** * Returns the X coordinate of the upper-left pixel of tile (0, 0). */ + @Override public int getTileGridXOffset() { return tileGridXOffset; } @@ -138,6 +145,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { /** * Returns the Y coordinate of the upper-left pixel of tile (0, 0). */ + @Override public int getTileGridYOffset() { return tileGridYOffset; } @@ -147,6 +155,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * getMinTileX() is implemented in terms of getMinX() * and so does not need to be implemented by subclasses. */ + @Override public int getMinTileX() { return XToTileX(getMinX()); } @@ -166,6 +175,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * of getMinTileX() and getMaxTileX() and so does not need to be * implemented by subclasses. */ + @Override public int getNumXTiles() { return getMaxTileX() - getMinTileX() + 1; } @@ -175,6 +185,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * is implemented in terms of getMinY() and so does not need to be * implemented by subclasses. */ + @Override public int getMinTileY() { return YToTileY(getMinY()); } @@ -194,16 +205,19 @@ public abstract class SimpleRenderedImage implements RenderedImage { * of getMinTileY() and getMaxTileY() and so does not need to be * implemented by subclasses. */ + @Override public int getNumYTiles() { return getMaxTileY() - getMinTileY() + 1; } /** Returns the SampleModel of the image. */ + @Override public SampleModel getSampleModel() { return sampleModel; } /** Returns the ColorModel of the image. */ + @Override public ColorModel getColorModel() { return colorModel; } @@ -218,6 +232,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * Object, or the value * java.awt.Image.UndefinedProperty. */ + @Override public Object getProperty(String name) { name = name.toLowerCase(); Object value = properties.get(name); @@ -232,6 +247,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * @return an array of Strings representing valid * property names. */ + @Override public String[] getPropertyNames() { String[] names = null; @@ -379,6 +395,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { return ty*tileHeight + tileGridYOffset; } + @Override public Vector getSources() { return null; } @@ -399,6 +416,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * * @return a Raster containing a copy of this image's data. */ + @Override public Raster getData() { Rectangle rect = new Rectangle(getMinX(), getMinY(), getWidth(), getHeight()); @@ -422,6 +440,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * * @param bounds the region of the RenderedImage to be returned. */ + @Override public Raster getData(Rectangle bounds) { // Get the image bounds. Rectangle imageBounds = getBounds(); @@ -511,6 +530,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * @return a reference to the supplied WritableRaster, or to a * new WritableRaster if the supplied one was null. */ + @Override public WritableRaster copyData(WritableRaster dest) { // Get the image bounds. Rectangle imageBounds = getBounds(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java index 0cbdefa9127..315270e5916 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,7 @@ public class SingleTileRenderedImage extends SimpleRenderedImage { /** * Returns the image's Raster as tile (0, 0). */ + @Override public Raster getTile(int tileX, int tileY) { if (tileX != 0 || tileY != 0) { throw new IllegalArgumentException("tileX != 0 || tileY != 0"); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java index d880c507cba..05fa72f24ae 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -492,6 +492,7 @@ public class StandardMetadataFormat extends IIOMetadataFormatImpl { null); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java index 4a94450d003..20e81dd76fa 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class StandardMetadataFormatResources extends ListResourceBundle { public StandardMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java index 5d6bd401dc6..487f678c1eb 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ public final class SubImageInputStream extends ImageInputStreamImpl { this.startingLength = this.length = length; } + @Override public int read() throws IOException { if (length == 0) { // Local EOF return -1; @@ -52,6 +53,7 @@ public final class SubImageInputStream extends ImageInputStreamImpl { } } + @Override public int read(byte[] b, int off, int len) throws IOException { if (length == 0) { // Local EOF return -1; @@ -63,10 +65,12 @@ public final class SubImageInputStream extends ImageInputStreamImpl { return bytes; } + @Override public long length() { return startingLength; } + @Override public void seek(long pos) throws IOException { stream.seek(pos - startingPos); streamPos = pos; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java index 061f3b1eaf0..bf2768af4e1 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,10 +115,12 @@ public class GIFImageMetadata extends GIFMetadata { null, null); } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -252,6 +254,7 @@ public class GIFImageMetadata extends GIFMetadata { return root; } + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -294,6 +297,7 @@ public class GIFImageMetadata extends GIFMetadata { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -315,6 +319,7 @@ public class GIFImageMetadata extends GIFMetadata { return compression_node; } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -332,6 +337,7 @@ public class GIFImageMetadata extends GIFMetadata { return data_node; } + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -365,6 +371,7 @@ public class GIFImageMetadata extends GIFMetadata { // Document not in image + @Override public IIOMetadataNode getStandardTextNode() { if (comments == null) { return null; @@ -391,6 +398,7 @@ public class GIFImageMetadata extends GIFMetadata { return text_node; } + @Override public IIOMetadataNode getStandardTransparencyNode() { if (!transparentColorFlag) { return null; @@ -414,22 +422,26 @@ public class GIFImageMetadata extends GIFMetadata { return transparency_node; } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override public void reset() { throw new IllegalStateException("Metadata is read-only!"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java index fa55d72bbda..5a6a85a2b57 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,6 +157,7 @@ public class GIFImageMetadataFormat extends IIOMetadataFormatImpl { DATATYPE_STRING, true, null); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java index aa9697a8ee9..f9a29cdebba 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class GIFImageMetadataFormatResources extends ListResourceBundle { public GIFImageMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java index 96a5ba436aa..9484484abf8 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,10 +71,12 @@ public class GIFImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard GIF image reader"; } + @Override public boolean canDecodeInput(Object input) throws IOException { if (!(input instanceof ImageInputStream)) { return false; @@ -91,6 +93,7 @@ public class GIFImageReaderSpi extends ImageReaderSpi { (b[4] == '7' || b[4] == '9') && b[5] == 'a'; } + @Override public ImageReader createReaderInstance(Object extension) { return new GIFImageReader(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java index 0f1b8aec102..6da6332eb50 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,6 +73,7 @@ public class GIFImageWriterSpi extends ImageWriterSpi { ); } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { if (type == null) { throw new IllegalArgumentException("type == null!"); @@ -94,10 +95,12 @@ public class GIFImageWriterSpi extends ImageWriterSpi { } } + @Override public String getDescription(Locale locale) { return "Standard GIF image writer"; } + @Override public ImageWriter createWriterInstance(Object extension) { return new GIFImageWriter(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java index 5fb4dc007b7..dca232352d9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,6 +242,7 @@ abstract class GIFMetadata extends IIOMetadata { extraMetadataFormatClassNames); } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java index 31c1305b58a..b34e96907ee 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,10 +77,12 @@ public class GIFStreamMetadata extends GIFMetadata { } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -149,6 +151,7 @@ public class GIFStreamMetadata extends GIFMetadata { return root; } + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -190,6 +193,7 @@ public class GIFStreamMetadata extends GIFMetadata { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -208,6 +212,7 @@ public class GIFStreamMetadata extends GIFMetadata { return compression_node; } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -230,6 +235,7 @@ public class GIFStreamMetadata extends GIFMetadata { return data_node; } + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -270,6 +276,7 @@ public class GIFStreamMetadata extends GIFMetadata { return dimension_node; } + @Override public IIOMetadataNode getStandardDocumentNode() { IIOMetadataNode document_node = new IIOMetadataNode("Document"); IIOMetadataNode node = null; // scratch node @@ -285,32 +292,38 @@ public class GIFStreamMetadata extends GIFMetadata { return document_node; } + @Override public IIOMetadataNode getStandardTextNode() { // Not in stream return null; } + @Override public IIOMetadataNode getStandardTransparencyNode() { // Not in stream return null; } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override public void reset() { throw new IllegalStateException("Metadata is read-only!"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java index b598674ccb3..fcdb8b0d13e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,6 +92,7 @@ public class GIFStreamMetadataFormat extends IIOMetadataFormatImpl { "0", "255", true, true); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java index 0404b2c88da..65e9f89c557 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class GIFStreamMetadataFormatResources extends ListResourceBundle { public GIFStreamMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java index a3e8a769490..cec4f354ee0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,10 +49,12 @@ class GIFWritableImageMetadata extends GIFImageMetadata { null, null); } + @Override public boolean isReadOnly() { return false; } + @Override public void reset() { // Fields from Image Descriptor imageLeftPosition = 0; @@ -96,6 +98,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { return data.getBytes(ISO_8859_1); } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { Node node = root; if (!node.getNodeName().equals(nativeMetadataFormatName)) { @@ -292,6 +295,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { } } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { Node node = root; @@ -389,6 +393,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { } } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java index 8a9a6d865a8..d8863cb4a2d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,10 +55,12 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { reset(); } + @Override public boolean isReadOnly() { return false; } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { @@ -77,6 +79,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { } } + @Override public void reset() { version = null; @@ -90,6 +93,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { globalColorTable = null; } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { Node node = root; if (!node.getNodeName().equals(nativeMetadataFormatName)) { @@ -164,6 +168,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { } } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { Node node = root; @@ -258,6 +263,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { } } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java index 551f4dc4d72..9b1fbd27fc4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,6 +73,7 @@ class AdobeMarkerSegment extends MarkerSegment { updateFromNativeNode(node, true); } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("app14Adobe"); node.setAttribute("version", Integer.toString(version)); @@ -108,6 +109,7 @@ class AdobeMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format. */ + @Override void write(ImageOutputStream ios) throws IOException { length = 14; writeTag(ios); @@ -124,6 +126,7 @@ class AdobeMarkerSegment extends MarkerSegment { (new AdobeMarkerSegment(transform)).write(ios); } + @Override void print () { printTag("Adobe APP14"); System.out.print("Version: "); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java index f28e7b35658..f45bded991a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,6 +104,7 @@ class COMMarkerSegment extends MarkerSegment { * as a user object and a string encoded using ISO-8895-1, as an * attribute. */ + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("com"); node.setAttribute("comment", getComment()); @@ -117,12 +118,14 @@ class COMMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format, directly from the data array. */ + @Override void write(ImageOutputStream ios) throws IOException { length = 2 + data.length; writeTag(ios); ios.write(data); } + @Override void print() { printTag("COM"); System.out.println("<" + getComment() + ">"); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java index c14402522db..634a266354d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,7 @@ class DHTMarkerSegment extends MarkerSegment { } } + @Override protected Object clone() { DHTMarkerSegment newGuy = (DHTMarkerSegment) super.clone(); newGuy.tables = new ArrayList<>(tables.size()); @@ -99,6 +100,7 @@ class DHTMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("dht"); for (int i= 0; i(tables.size()); @@ -92,6 +93,7 @@ class DQTMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("dqt"); for (int i= 0; i MAX_THUMB_WIDTH) @@ -949,6 +960,7 @@ class JFIFMarkerSegment extends MarkerSegment { writeThumbnailData(ios, data, writer); } + @Override void print() { System.out.print(name + " width: "); System.out.println(thumbWidth); @@ -978,10 +990,12 @@ class JFIFMarkerSegment extends MarkerSegment { super(thumb); } + @Override int getLength() { return (thumbWidth*thumbHeight*3); } + @Override BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { @@ -1014,6 +1028,7 @@ class JFIFMarkerSegment extends MarkerSegment { null); } + @Override void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { super.write(ios, writer); // width and height @@ -1050,10 +1065,12 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override int getLength() { return (thumbWidth*thumbHeight + PALETTE_SIZE); } + @Override BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { @@ -1091,6 +1108,7 @@ class JFIFMarkerSegment extends MarkerSegment { null); } + @Override void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { super.write(ios, writer); // width and height @@ -1221,6 +1239,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override int getWidth() { int retval = 0; SOFMarkerSegment sof = @@ -1232,6 +1251,7 @@ class JFIFMarkerSegment extends MarkerSegment { return retval; } + @Override int getHeight() { int retval = 0; SOFMarkerSegment sof = @@ -1249,21 +1269,31 @@ class JFIFMarkerSegment extends MarkerSegment { ThumbnailReadListener (JPEGImageReader reader) { this.reader = reader; } + @Override public void sequenceStarted(ImageReader source, int minIndex) {} + @Override public void sequenceComplete(ImageReader source) {} + @Override public void imageStarted(ImageReader source, int imageIndex) {} + @Override public void imageProgress(ImageReader source, float percentageDone) { reader.thumbnailProgress(percentageDone); } + @Override public void imageComplete(ImageReader source) {} + @Override public void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex) {} + @Override public void thumbnailProgress(ImageReader source, float percentageDone) {} + @Override public void thumbnailComplete(ImageReader source) {} + @Override public void readAborted(ImageReader source) {} } + @Override BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { @@ -1279,6 +1309,7 @@ class JFIFMarkerSegment extends MarkerSegment { return ret; } + @Override protected Object clone() { JFIFThumbJPEG newGuy = (JFIFThumbJPEG) super.clone(); if (thumbMetadata != null) { @@ -1287,6 +1318,7 @@ class JFIFMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("JFIFthumbJPEG"); if (thumbMetadata != null) { @@ -1295,6 +1327,7 @@ class JFIFMarkerSegment extends MarkerSegment { return node; } + @Override int getLength() { if (data == null) { return 0; @@ -1303,6 +1336,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { int progInterval = data.length / 20; // approx. every 5% @@ -1322,6 +1356,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override void print () { System.out.println("JFIF thumbnail stored as JPEG"); } @@ -1445,6 +1480,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override protected Object clone () { ICCMarkerSegment newGuy = (ICCMarkerSegment) super.clone(); if (profile != null) { @@ -1541,6 +1577,7 @@ class JFIFMarkerSegment extends MarkerSegment { return retval; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("app2ICC"); if (profile != null) { @@ -1553,10 +1590,12 @@ class JFIFMarkerSegment extends MarkerSegment { * No-op. Profiles are never written from metadata. * They are written from the ColorSpace of the image. */ + @Override void write(ImageOutputStream ios) throws IOException { // No-op } + @Override void print () { printTag("ICC Profile APP2"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java index 4c858a47ab1..20b94fb339b 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -337,6 +337,7 @@ public class JPEGImageMetadataFormat extends JPEGMetadataFormat { tabids); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { // All images can have these diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java index e242a355a17..3cbc0054c85 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,6 +122,7 @@ public class JPEGImageMetadataFormatResources public JPEGImageMetadataFormatResources() {} + @Override protected Object[][] getContents() { // return a copy of the combined commonContents and imageContents; // in theory we want a deep clone of the combined arrays, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java index e4b09197aa7..be6fc32a761 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class JPEGImageReaderResources extends ListResourceBundle { public JPEGImageReaderResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java index 450dd89b6f4..ab942ea8de2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,10 +59,12 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard JPEG Image Reader"; } + @Override public boolean canDecodeInput(Object source) throws IOException { if (!(source instanceof ImageInputStream)) { return false; @@ -80,6 +82,7 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { return false; } + @Override public ImageReader createReaderInstance(Object extension) throws IIOException { return new JPEGImageReader(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java index 3db20b3d39d..3b2a149f6b4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class JPEGImageWriterResources extends ListResourceBundle { public JPEGImageWriterResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java index bd6bcc8d784..d6f5abbbccb 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,14 +63,17 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard JPEG Image Writer"; } + @Override public boolean isFormatLossless() { return false; } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { SampleModel sampleModel = type.getSampleModel(); ColorModel cm = type.getColorModel(); @@ -95,6 +98,7 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { return true; } + @Override public ImageWriter createWriterInstance(Object extension) throws IIOException { return new JPEGImageWriter(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index c7ad982b35a..3081fd43404 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -725,6 +725,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Implement Cloneable, but restrict access + @Override protected Object clone() { JPEGMetadata newGuy = null; try { @@ -755,6 +756,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Tree methods + @Override public Node getAsTree(String formatName) { if (formatName == null) { throw new IllegalArgumentException("null formatName!"); @@ -810,6 +812,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Standard tree node methods + @Override protected IIOMetadataNode getStandardChromaNode() { hasAlpha = false; // Unless we find otherwise @@ -950,6 +953,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return chroma; } + @Override protected IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression = new IIOMetadataNode("Compression"); @@ -980,6 +984,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return compression; } + @Override protected IIOMetadataNode getStandardDimensionNode() { // If we have a JFIF marker segment, we know a little // otherwise all we know is the orientation, which is always normal @@ -1055,6 +1060,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return doc; } + @Override protected IIOMetadataNode getStandardTextNode() { IIOMetadataNode text = null; // Add a text entry for each COM Marker Segment @@ -1073,6 +1079,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return text; } + @Override protected IIOMetadataNode getStandardTransparencyNode() { IIOMetadataNode trans = null; if (hasAlpha == true) { @@ -1086,10 +1093,12 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Editing + @Override public boolean isReadOnly() { return false; } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName == null) { @@ -2160,6 +2169,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName == null) { @@ -2404,6 +2414,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { //// End of writer support + @Override public void reset() { if (resetSequence != null) { // Otherwise no need to reset markerSequence = resetSequence; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java index 475cc36359e..53b30f333f0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,6 +123,7 @@ abstract class JPEGMetadataFormat extends IIOMetadataFormatImpl { addObjectValue("unknown", byte[].class, 1, MAX_JPEG_DATA_SIZE); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { // Just check if it appears in the format diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java index ea6d2b70138..5e29101e83b 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ public class JPEGStreamMetadataFormatResources public JPEGStreamMetadataFormatResources() {} + @Override protected Object[][] getContents() { // return a copy of commonContents; in theory we want a deep clone // of commonContents, but since it only contains (immutable) Strings, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java index f4ba27b0fcd..74bf598c4d5 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java @@ -110,6 +110,7 @@ class MarkerSegment implements Cloneable { /** * Deep copy of data array. */ + @Override protected Object clone() { MarkerSegment newGuy = null; try { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java index e5b7e861924..fa7acba3325 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,6 +95,7 @@ class SOFMarkerSegment extends MarkerSegment { updateFromNativeNode(node, true); } + @Override protected Object clone() { SOFMarkerSegment newGuy = (SOFMarkerSegment) super.clone(); if (componentSpecs != null) { @@ -107,6 +108,7 @@ class SOFMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("sof"); node.setAttribute("process", Integer.toString(tag-JPEG.SOF0)); @@ -154,10 +156,12 @@ class SOFMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format. */ + @Override void write(ImageOutputStream ios) throws IOException { // We don't write SOF segments; the IJG library does. } + @Override void print () { printTag("SOF"); System.out.print("Sample precision: "); @@ -231,6 +235,7 @@ class SOFMarkerSegment extends MarkerSegment { 0, 3, true); } + @Override protected Object clone() { try { return super.clone(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java index f40acdd0375..a34fc43486a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,6 +89,7 @@ class SOSMarkerSegment extends MarkerSegment { updateFromNativeNode(node, true); } + @Override protected Object clone () { SOSMarkerSegment newGuy = (SOSMarkerSegment) super.clone(); if (componentSpecs != null) { @@ -101,6 +102,7 @@ class SOSMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("sos"); node.setAttribute("numScanComponents", @@ -152,10 +154,12 @@ class SOSMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format. */ + @Override void write(ImageOutputStream ios) throws IOException { // We don't write SOS segments; the IJG library does. } + @Override void print () { printTag("SOS"); System.out.print("Start spectral selection: "); @@ -208,6 +212,7 @@ class SOSMarkerSegment extends MarkerSegment { 0, 3, true); } + @Override protected Object clone() { try { return super.clone(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java index 60105e30f8a..bf0576ecb74 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,10 +70,12 @@ public class PNGImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard PNG image reader"; } + @Override public boolean canDecodeInput(Object input) throws IOException { if (!(input instanceof ImageInputStream)) { return false; @@ -96,6 +98,7 @@ public class PNGImageReaderSpi extends ImageReaderSpi { b[7] == (byte)10); } + @Override public ImageReader createReaderInstance(Object extension) { return new PNGImageReader(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java index 44080a05a16..3ce07aa4ba5 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,6 +74,7 @@ public class PNGImageWriterSpi extends ImageWriterSpi { ); } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { SampleModel sampleModel = type.getSampleModel(); ColorModel colorModel = type.getColorModel(); @@ -116,10 +117,12 @@ public class PNGImageWriterSpi extends ImageWriterSpi { return true; } + @Override public String getDescription(Locale locale) { return "Standard PNG image writer"; } + @Override public ImageWriter createWriterInstance(Object extension) { return new PNGImageWriter(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java index 03d00f7ae8e..730294c9f01 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -463,6 +463,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { IHDR_present = true; } + @Override public boolean isReadOnly() { return false; } @@ -480,6 +481,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } // Deep clone + @Override public Object clone() { PNGMetadata metadata; try { @@ -495,6 +497,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return metadata; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -847,6 +850,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return numChannels; } + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -919,6 +923,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -952,6 +957,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return sb.toString(); } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -998,6 +1004,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return data_node; } + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -1027,6 +1034,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return dimension_node; } + @Override public IIOMetadataNode getStandardDocumentNode() { IIOMetadataNode document_node = null; @@ -1067,6 +1075,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return document_node; } + @Override public IIOMetadataNode getStandardTextNode() { int numEntries = tEXt_keyword.size() + iTXt_keyword.size() + zTXt_keyword.size(); @@ -1114,6 +1123,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return text_node; } + @Override public IIOMetadataNode getStandardTransparencyNode() { IIOMetadataNode transparency_node = new IIOMetadataNode("Transparency"); @@ -1285,6 +1295,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return getAttribute(node, name, null, true); } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { @@ -2267,6 +2278,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } // Reset all instance variables to their initial state + @Override public void reset() { IHDR_present = false; PLTE_present = false; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java index b7d96dc3f2b..1518d097903 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -486,6 +486,7 @@ public class PNGMetadataFormat extends IIOMetadataFormatImpl { addObjectValue("UnknownChunk", byte.class, 0, Integer.MAX_VALUE); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java index d99946bd890..818a2364e23 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class PNGMetadataFormatResources extends ListResourceBundle { public PNGMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java index d5adb4e8d35..31806941e35 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -335,6 +335,7 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { return JPEGImageMetadata; } + @Override public final int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java index bc20c57da69..dbddc94516e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ public class TIFFCIELabColorConverter extends TIFFColorConverter { } } + @Override public void fromRGB(float r, float g, float b, float[] result) { float X = 0.412453f*r + 0.357580f*g + 0.180423f*b; float Y = 0.212671f*r + 0.715160f*g + 0.072169f*b; @@ -100,6 +101,7 @@ public class TIFFCIELabColorConverter extends TIFFColorConverter { result[2] = clamp2(bStar); } + @Override public void toRGB(float x0, float x1, float x2, float[] rgb) { float LStar = x0*100.0f/255.0f; float aStar = (x1 > 128.0f) ? (x1 - 256.0f) : x1; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java index 1ce7d56c1c7..5ade4bacfb4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ public class TIFFDeflateDecompressor extends TIFFDecompressor { this.predictor = predictor; } + @Override public synchronized void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java index 0fde32a229f..3a5a10245df 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,7 @@ public class TIFFDeflater extends TIFFCompressor { this.deflater = new Deflater(deflateLevel); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java index 3541ce110db..992cba6cbe5 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ public class TIFFExifJPEGCompressor extends TIFFBaseJPEGCompressor { param); } + @Override public void setMetadata(IIOMetadata metadata) { // Set the metadata. super.setMetadata(metadata); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java index 5c126acab53..2af59c682c4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,6 +242,7 @@ abstract class TIFFFaxCompressor extends TIFFCompressor { * * @see #getMetadata() */ + @Override public void setMetadata(IIOMetadata metadata) { super.setMetadata(metadata); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java index a1947dc6b72..64839c033da 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -591,6 +591,7 @@ class TIFFFaxDecompressor extends TIFFDecompressor { * Invokes the superclass method and then sets instance variables on * the basis of the metadata set on this decompressor. */ + @Override public void beginDecoding() { super.beginDecoding(); @@ -627,6 +628,7 @@ class TIFFFaxDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] b, int dstOffset, int pixelBitStride, // will always be 1 int scanlineStride) throws IOException { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java index 6f23fbad4f2..e8878d93315 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -162,6 +162,7 @@ public class TIFFFieldNode extends IIOMetadataNode { // Need to override this method to avoid a stack overflow exception // which will occur if super.appendChild is called from initialize(). + @Override public Node appendChild(Node newChild) { if (newChild == null) { throw new NullPointerException("newChild == null!"); @@ -172,53 +173,63 @@ public class TIFFFieldNode extends IIOMetadataNode { // Override all methods which refer to child nodes. + @Override public boolean hasChildNodes() { initialize(); return super.hasChildNodes(); } + @Override public int getLength() { initialize(); return super.getLength(); } + @Override public Node getFirstChild() { initialize(); return super.getFirstChild(); } + @Override public Node getLastChild() { initialize(); return super.getLastChild(); } + @Override public Node getPreviousSibling() { initialize(); return super.getPreviousSibling(); } + @Override public Node getNextSibling() { initialize(); return super.getNextSibling(); } + @Override public Node insertBefore(Node newChild, Node refChild) { initialize(); return super.insertBefore(newChild, refChild); } + @Override public Node replaceChild(Node newChild, Node oldChild) { initialize(); return super.replaceChild(newChild, oldChild); } + @Override public Node removeChild(Node oldChild) { initialize(); return super.removeChild(oldChild); } + @Override public Node cloneNode(boolean deep) { initialize(); return super.cloneNode(deep); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java index 82ae068d7e4..a3cf39505e6 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,6 +93,7 @@ public class TIFFImageMetadata extends IIOMetadata { rootIFD.addTIFFField(field); } + @Override public boolean isReadOnly() { return false; } @@ -149,6 +150,7 @@ public class TIFFImageMetadata extends IIOMetadata { return IFDRoot; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -181,6 +183,7 @@ public class TIFFImageMetadata extends IIOMetadata { "Lab", // ICCLab }; + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -278,6 +281,7 @@ public class TIFFImageMetadata extends IIOMetadata { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -336,6 +340,7 @@ public class TIFFImageMetadata extends IIOMetadata { return sb.toString(); } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -476,6 +481,7 @@ public class TIFFImageMetadata extends IIOMetadata { "Rotate90", }; + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -604,6 +610,7 @@ public class TIFFImageMetadata extends IIOMetadata { return dimension_node; } + @Override public IIOMetadataNode getStandardDocumentNode() { IIOMetadataNode document_node = new IIOMetadataNode("Document"); IIOMetadataNode node = null; // scratch node @@ -669,6 +676,7 @@ public class TIFFImageMetadata extends IIOMetadata { return document_node; } + @Override public IIOMetadataNode getStandardTextNode() { IIOMetadataNode text_node = null; IIOMetadataNode node = null; // scratch node @@ -705,6 +713,7 @@ public class TIFFImageMetadata extends IIOMetadata { return text_node; } + @Override public IIOMetadataNode getStandardTransparencyNode() { IIOMetadataNode transparency_node = new IIOMetadataNode("Transparency"); @@ -1579,6 +1588,7 @@ public class TIFFImageMetadata extends IIOMetadata { } } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException{ if (formatName.equals(nativeMetadataFormatName)) { @@ -1597,6 +1607,7 @@ public class TIFFImageMetadata extends IIOMetadata { } } + @Override public void reset() { rootIFD = new TIFFIFD(tagSets); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java index 59c425ec517..edfa3a5be9c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ public class TIFFImageMetadataFormat extends TIFFMetadataFormat { static { } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return false; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java index 070836e8854..59e68d0dfe2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,6 +96,7 @@ public class TIFFImageMetadataFormatResources extends ListResourceBundle { public TIFFImageMetadataFormatResources() { } + @Override public Object[][] getContents() { return contents.clone(); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java index 2332e4be2d1..ef21e0b2042 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,10 +56,12 @@ public class TIFFImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard TIFF image reader"; } + @Override public boolean canDecodeInput(Object input) throws IOException { if (!(input instanceof ImageInputStream)) { return false; @@ -78,10 +80,12 @@ public class TIFFImageReaderSpi extends ImageReaderSpi { b[2] == (byte)0x00 && b[3] == (byte)0x2a)); } + @Override public ImageReader createReaderInstance(Object extension) { return new TIFFImageReader(this); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java index 0b93cbedc0b..a742db6f6bb 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,18 +55,22 @@ public class TIFFImageWriterSpi extends ImageWriterSpi { ); } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { return true; } + @Override public String getDescription(Locale locale) { return "Standard TIFF image writer"; } + @Override public ImageWriter createWriterInstance(Object extension) { return new TIFFImageWriter(this); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java index f524f34e32e..e73ccb2b282 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,7 @@ public class TIFFJPEGCompressor extends TIFFBaseJPEGCompressor { private static class JPEGSPIFilter implements ServiceRegistry.Filter { JPEGSPIFilter() {} + @Override public boolean filter(Object provider) { ImageReaderSpi readerSPI = (ImageReaderSpi)provider; @@ -112,6 +113,7 @@ public class TIFFJPEGCompressor extends TIFFBaseJPEGCompressor { * * @see #getMetadata() */ + @Override public void setMetadata(IIOMetadata metadata) { super.setMetadata(metadata); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java index 3c2ce905958..7353ccea56f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,7 @@ public class TIFFJPEGDecompressor extends TIFFDecompressor { public TIFFJPEGDecompressor() {} + @Override public void beginDecoding() { // Initialize the JPEG reader if needed. if(this.JPEGReader == null) { @@ -90,6 +91,7 @@ public class TIFFJPEGDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java index b7bceb89ae4..5052ffedbff 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ public class TIFFLSBCompressor extends TIFFCompressor { super("", BaselineTIFFTagSet.COMPRESSION_NONE, true); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java index d871b6a3e86..6724b779334 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ public class TIFFLSBDecompressor extends TIFFDecompressor { public TIFFLSBDecompressor() {} + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java index 4b2b945acb7..6780d65053f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,10 +41,12 @@ public class TIFFLZWCompressor extends TIFFCompressor { this.predictor = predictorValue; } + @Override public void setStream(ImageOutputStream stream) { super.setStream(stream); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java index fc682589ce2..dcf5b2a7f71 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,6 +76,7 @@ class TIFFLZWDecompressor extends TIFFDecompressor { flipBits = fillOrder == BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT; } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java index 1091cab9bb2..92d15bfdcb4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { protected String resourceBaseName; protected String rootName; + @Override public String getRootName() { return rootName; } @@ -85,16 +86,19 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info; } + @Override public int getElementMinChildren(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.minChildren; } + @Override public int getElementMaxChildren(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.maxChildren; } + @Override public String getElementDescription(String elementName, Locale locale) { if (!elementInfoMap.containsKey(elementName)) { throw new IllegalArgumentException("No such element: " + @@ -103,64 +107,77 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return getResource(elementName, locale); } + @Override public int getChildPolicy(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.childPolicy; } + @Override public String[] getChildNames(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.childNames; } + @Override public String[] getAttributeNames(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.attributeNames; } + @Override public int getAttributeValueType(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.valueType; } + @Override public int getAttributeDataType(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.dataType; } + @Override public boolean isAttributeRequired(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.isRequired; } + @Override public String getAttributeDefaultValue(String elementName, String attrName) { return null; } + @Override public String[] getAttributeEnumerations(String elementName, String attrName) { throw new IllegalArgumentException("The attribute is not an enumeration."); } + @Override public String getAttributeMinValue(String elementName, String attrName) { throw new IllegalArgumentException("The attribute is not a range."); } + @Override public String getAttributeMaxValue(String elementName, String attrName) { throw new IllegalArgumentException("The attribute is not a range."); } + @Override public int getAttributeListMinLength(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.listMinLength; } + @Override public int getAttributeListMaxLength(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.listMaxLength; } + @Override public String getAttributeDescription(String elementName, String attrName, Locale locale) { String key = elementName + "/" + attrName; @@ -170,11 +187,13 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return getResource(key, locale); } + @Override public int getObjectValueType(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.objectValueType; } + @Override public Class getObjectClass(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -184,6 +203,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectClass; } + @Override public Object getObjectDefaultValue(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -193,6 +213,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectDefaultValue; } + @Override public Object[] getObjectEnumerations(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -202,6 +223,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectEnumerations; } + @Override public Comparable getObjectMinValue(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -211,6 +233,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectMinValue; } + @Override public Comparable getObjectMaxValue(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -220,6 +243,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectMaxValue; } + @Override public int getObjectArrayMinLength(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -229,6 +253,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectArrayMinLength; } + @Override public int getObjectArrayMaxLength(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java index fc366f791f7..8f6428035d9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ public class TIFFNullCompressor extends TIFFCompressor { super("", BaselineTIFFTagSet.COMPRESSION_NONE, true); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java index 9b5a746eec1..b73580ef823 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { // change beginDecoding() and decode() to use the active region values // when random access is easy and the entire region values otherwise. // + @Override public void beginDecoding() { // Determine number of bits per pixel. int bitsPerPixel = 0; @@ -89,6 +90,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { super.beginDecoding(); } + @Override public void decode() throws IOException { super.decode(); @@ -105,6 +107,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java index 2935ca5caf8..77594ea8086 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -545,6 +545,7 @@ public class TIFFOldJPEGDecompressor extends TIFFJPEGDecompressor { // The strategy for cases 4-5 is to concatenate a tables stream created // in initialize() with the entropy coded data in each strip or tile. // + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java index 119e4ad4906..b2341f12ed7 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,6 +86,7 @@ public class TIFFPackBitsCompressor extends TIFFCompressor { return outOffset; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java index 0a5dfe8308e..61026f57fed 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,6 +72,7 @@ public class TIFFPackBitsDecompressor extends TIFFDecompressor { return dstIndex - dstOffset; } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java index 0bf59da81da..1e0270c6ecc 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,7 @@ public class TIFFRLECompressor extends TIFFFaxCompressor { return outIndex; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java index 77e0c9a109c..dadabac3d68 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,74 +130,92 @@ public class TIFFRenderedImage implements RenderedImage { return newParam; } + @Override public Vector getSources() { return null; } + @Override public Object getProperty(String name) { return java.awt.Image.UndefinedProperty; } + @Override public String[] getPropertyNames() { return null; } + @Override public ColorModel getColorModel() { return its.getColorModel(); } + @Override public SampleModel getSampleModel() { return its.getSampleModel(); } + @Override public int getWidth() { return width; } + @Override public int getHeight() { return height; } + @Override public int getMinX() { return 0; } + @Override public int getMinY() { return 0; } + @Override public int getNumXTiles() { return (width + tileWidth - 1)/tileWidth; } + @Override public int getNumYTiles() { return (height + tileHeight - 1)/tileHeight; } + @Override public int getMinTileX() { return 0; } + @Override public int getMinTileY() { return 0; } + @Override public int getTileWidth() { return tileWidth; } + @Override public int getTileHeight() { return tileHeight; } + @Override public int getTileGridXOffset() { return 0; } + @Override public int getTileGridYOffset() { return 0; } + @Override public Raster getTile(int tileX, int tileY) { Rectangle tileRect = new Rectangle(tileX*tileWidth, tileY*tileHeight, @@ -206,10 +224,12 @@ public class TIFFRenderedImage implements RenderedImage { return getData(tileRect); } + @Override public Raster getData() { return read(new Rectangle(0, 0, getWidth(), getHeight())); } + @Override public Raster getData(Rectangle rect) { return read(rect); } @@ -236,6 +256,7 @@ public class TIFFRenderedImage implements RenderedImage { } } + @Override public WritableRaster copyData(WritableRaster raster) { if (raster == null) { return read(new Rectangle(0, 0, getWidth(), getHeight())); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java index 96592cc62fb..ac9398fd6e9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,7 @@ public class TIFFStreamMetadata extends IIOMetadata { null, null); } + @Override public boolean isReadOnly() { return false; } @@ -64,6 +65,7 @@ public class TIFFStreamMetadata extends IIOMetadata { throw new IIOInvalidTreeException(reason, node); } + @Override public Node getAsTree(String formatName) { IIOMetadataNode root = new IIOMetadataNode(nativeMetadataFormatName); @@ -103,6 +105,7 @@ public class TIFFStreamMetadata extends IIOMetadata { } } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { @@ -115,6 +118,7 @@ public class TIFFStreamMetadata extends IIOMetadata { } } + @Override public void reset() { this.byteOrder = ByteOrder.BIG_ENDIAN; } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java index bf35133811e..50a3d32e239 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class TIFFStreamMetadataFormat extends TIFFMetadataFormat { private static TIFFStreamMetadataFormat theInstance = null; + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return false; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java index 1e0ea272200..75977c15a41 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ public class TIFFStreamMetadataFormatResources extends ListResourceBundle { public TIFFStreamMetadataFormatResources() { } + @Override public Object[][] getContents() { return contents.clone(); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java index 55088e34dfe..99d45ce4866 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { * * @see #getMetadata() */ + @Override public void setMetadata(IIOMetadata metadata) { super.setMetadata(metadata); @@ -214,6 +215,7 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { return outIndex; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java index 517c23bde54..7e2625d87e2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,6 +146,7 @@ public class TIFFT6Compressor extends TIFFFaxCompressor { return outIndex; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java index a006a3a1e38..b5dae8a9298 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,6 +80,7 @@ public class TIFFYCbCrColorConverter extends TIFFColorConverter { / CodingRange) + ReferenceBlack; */ + @Override public void fromRGB(float r, float g, float b, float[] result) { // Convert RGB to full-range YCbCr. float Y = (lumaRed*r + lumaGreen*g + lumaBlue*b); @@ -95,6 +96,7 @@ public class TIFFYCbCrColorConverter extends TIFFColorConverter { referenceBlackCr; } + @Override public void toRGB(float x0, float x1, float x2, float[] rgb) { // Convert YCbCr code to full-range YCbCr. float Y = (x0 - referenceBlackY)*CODING_RANGE_Y/ diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java index 0f10904cab4..c0623885d34 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,6 +95,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { // "Chained" decompressor methods. // + @Override public void setReader(ImageReader reader) { if(decompressor != null) { decompressor.setReader(reader); @@ -102,6 +103,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setReader(reader); } + @Override public void setMetadata(IIOMetadata metadata) { if(decompressor != null) { decompressor.setMetadata(metadata); @@ -109,6 +111,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setMetadata(metadata); } + @Override public void setPhotometricInterpretation(int photometricInterpretation) { if(decompressor != null) { decompressor.setPhotometricInterpretation(photometricInterpretation); @@ -116,6 +119,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setPhotometricInterpretation(photometricInterpretation); } + @Override public void setCompression(int compression) { if(decompressor != null) { decompressor.setCompression(compression); @@ -123,6 +127,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setCompression(compression); } + @Override public void setPlanar(boolean planar) { if(decompressor != null) { decompressor.setPlanar(planar); @@ -130,6 +135,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setPlanar(planar); } + @Override public void setSamplesPerPixel(int samplesPerPixel) { if(decompressor != null) { decompressor.setSamplesPerPixel(samplesPerPixel); @@ -137,6 +143,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSamplesPerPixel(samplesPerPixel); } + @Override public void setBitsPerSample(int[] bitsPerSample) { if(decompressor != null) { decompressor.setBitsPerSample(bitsPerSample); @@ -144,6 +151,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setBitsPerSample(bitsPerSample); } + @Override public void setSampleFormat(int[] sampleFormat) { if(decompressor != null) { decompressor.setSampleFormat(sampleFormat); @@ -151,6 +159,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSampleFormat(sampleFormat); } + @Override public void setExtraSamples(int[] extraSamples) { if(decompressor != null) { decompressor.setExtraSamples(extraSamples); @@ -158,6 +167,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setExtraSamples(extraSamples); } + @Override public void setColorMap(char[] colorMap) { if(decompressor != null) { decompressor.setColorMap(colorMap); @@ -165,6 +175,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setColorMap(colorMap); } + @Override public void setStream(ImageInputStream stream) { if(decompressor != null) { decompressor.setStream(stream); @@ -173,6 +184,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } } + @Override public void setOffset(long offset) { if(decompressor != null) { decompressor.setOffset(offset); @@ -180,6 +192,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setOffset(offset); } + @Override public void setByteCount(int byteCount) throws IOException { if(decompressor != null) { decompressor.setByteCount(byteCount); @@ -187,6 +200,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setByteCount(byteCount); } + @Override public void setSrcMinX(int srcMinX) { if(decompressor != null) { decompressor.setSrcMinX(srcMinX); @@ -194,6 +208,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcMinX(srcMinX); } + @Override public void setSrcMinY(int srcMinY) { if(decompressor != null) { decompressor.setSrcMinY(srcMinY); @@ -201,6 +216,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcMinY(srcMinY); } + @Override public void setSrcWidth(int srcWidth) { if(decompressor != null) { decompressor.setSrcWidth(srcWidth); @@ -208,6 +224,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcWidth(srcWidth); } + @Override public void setSrcHeight(int srcHeight) { if(decompressor != null) { decompressor.setSrcHeight(srcHeight); @@ -215,6 +232,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcHeight(srcHeight); } + @Override public void setSourceXOffset(int sourceXOffset) { if(decompressor != null) { decompressor.setSourceXOffset(sourceXOffset); @@ -222,6 +240,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSourceXOffset(sourceXOffset); } + @Override public void setDstXOffset(int dstXOffset) { if(decompressor != null) { decompressor.setDstXOffset(dstXOffset); @@ -229,6 +248,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstXOffset(dstXOffset); } + @Override public void setSourceYOffset(int sourceYOffset) { if(decompressor != null) { decompressor.setSourceYOffset(sourceYOffset); @@ -236,6 +256,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSourceYOffset(sourceYOffset); } + @Override public void setDstYOffset(int dstYOffset) { if(decompressor != null) { decompressor.setDstYOffset(dstYOffset); @@ -260,6 +281,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } */ + @Override public void setSourceBands(int[] sourceBands) { if(decompressor != null) { decompressor.setSourceBands(sourceBands); @@ -267,6 +289,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSourceBands(sourceBands); } + @Override public void setDestinationBands(int[] destinationBands) { if(decompressor != null) { decompressor.setDestinationBands(destinationBands); @@ -274,6 +297,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDestinationBands(destinationBands); } + @Override public void setImage(BufferedImage image) { if(decompressor != null) { ColorModel cm = image.getColorModel(); @@ -287,6 +311,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setImage(image); } + @Override public void setDstMinX(int dstMinX) { if(decompressor != null) { decompressor.setDstMinX(dstMinX); @@ -294,6 +319,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstMinX(dstMinX); } + @Override public void setDstMinY(int dstMinY) { if(decompressor != null) { decompressor.setDstMinY(dstMinY); @@ -301,6 +327,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstMinY(dstMinY); } + @Override public void setDstWidth(int dstWidth) { if(decompressor != null) { decompressor.setDstWidth(dstWidth); @@ -308,6 +335,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstWidth(dstWidth); } + @Override public void setDstHeight(int dstHeight) { if(decompressor != null) { decompressor.setDstHeight(dstHeight); @@ -315,6 +343,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstHeight(dstHeight); } + @Override public void setActiveSrcMinX(int activeSrcMinX) { if(decompressor != null) { decompressor.setActiveSrcMinX(activeSrcMinX); @@ -322,6 +351,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setActiveSrcMinX(activeSrcMinX); } + @Override public void setActiveSrcMinY(int activeSrcMinY) { if(decompressor != null) { decompressor.setActiveSrcMinY(activeSrcMinY); @@ -329,6 +359,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setActiveSrcMinY(activeSrcMinY); } + @Override public void setActiveSrcWidth(int activeSrcWidth) { if(decompressor != null) { decompressor.setActiveSrcWidth(activeSrcWidth); @@ -336,6 +367,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setActiveSrcWidth(activeSrcWidth); } + @Override public void setActiveSrcHeight(int activeSrcHeight) { if(decompressor != null) { decompressor.setActiveSrcHeight(activeSrcHeight); @@ -353,6 +385,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } } + @Override public void beginDecoding() { if(decompressor != null) { decompressor.beginDecoding(); @@ -445,6 +478,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] buf, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java index acff45d5b72..9cd967140c9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,7 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { null, null); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -71,10 +72,12 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { registered = true; } + @Override public String getDescription(Locale locale) { return "Standard WBMP Image Reader"; } + @Override public boolean canDecodeInput(Object source) throws IOException { if (!(source instanceof ImageInputStream)) { return false; @@ -149,6 +152,7 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { return result; } + @Override public ImageReader createReaderInstance(Object extension) throws IIOException { return new WBMPImageReader(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java index be2f2d96a38..d6d723c0110 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,10 +63,12 @@ public class WBMPImageWriterSpi extends ImageWriterSpi { null, null, null, null); } + @Override public String getDescription(Locale locale) { return "Standard WBMP Image Writer"; } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -76,6 +78,7 @@ public class WBMPImageWriterSpi extends ImageWriterSpi { registered = true; } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { SampleModel sm = type.getSampleModel(); if (!(sm instanceof MultiPixelPackedSampleModel)) @@ -86,6 +89,7 @@ public class WBMPImageWriterSpi extends ImageWriterSpi { return true; } + @Override public ImageWriter createWriterInstance(Object extension) throws IIOException { return new WBMPImageWriter(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java index 3a13bcca94f..f3a63ff7b13 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,10 +50,12 @@ public class WBMPMetadata extends IIOMetadata { null, null); } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -76,14 +78,17 @@ public class WBMPMetadata extends IIOMetadata { return root; } + @Override public void setFromTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("WBMPMetadata1")); } + @Override public void mergeTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("WBMPMetadata1")); } + @Override public void reset() { throw new IllegalStateException(I18N.getString("WBMPMetadata1")); } @@ -101,6 +106,7 @@ public class WBMPMetadata extends IIOMetadata { } + @Override protected IIOMetadataNode getStandardChromaNode() { IIOMetadataNode node = new IIOMetadataNode("Chroma"); @@ -112,6 +118,7 @@ public class WBMPMetadata extends IIOMetadata { } + @Override protected IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java index 49bce89164a..0aabaa132a3 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ public class WBMPMetadataFormat extends IIOMetadataFormatImpl { + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java index 81070ff1cb6..3b52fb2b0f0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,10 +43,12 @@ public class FileImageInputStreamSpi extends ImageInputStreamSpi { super(vendorName, version, inputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageInputStream from a File"; } + @Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java index 1ca08005fa1..aa906197d37 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,10 +43,12 @@ public class FileImageOutputStreamSpi extends ImageOutputStreamSpi { super(vendorName, version, outputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageOutputStream from a File"; } + @Override public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java index 2591f77a697..266b09c6d9d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,18 +46,22 @@ public class InputStreamImageInputStreamSpi extends ImageInputStreamSpi { super(vendorName, version, inputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileCacheImageInputStream or MemoryCacheImageInputStream from an InputStream"; } + @Override public boolean canUseCacheFile() { return true; } + @Override public boolean needsCacheFile() { return false; } + @Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java index 391e00feb46..01c7df2145d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,18 +46,22 @@ public class OutputStreamImageOutputStreamSpi extends ImageOutputStreamSpi { super(vendorName, version, outputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates an OutputStreamImageOutputStream from an OutputStream"; } + @Override public boolean canUseCacheFile() { return true; } + @Override public boolean needsCacheFile() { return false; } + @Override public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java index b5c5112c14e..43498b30dbf 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,10 +44,12 @@ public class RAFImageInputStreamSpi extends ImageInputStreamSpi { super(vendorName, version, inputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageInputStream from a RandomAccessFile"; } + @Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java index 373f8754f08..1fe6438b27d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,10 +44,12 @@ public class RAFImageOutputStreamSpi extends ImageOutputStreamSpi { super(vendorName, version, outputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageOutputStream from a RandomAccessFile"; } + @Override public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java b/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java index 5ea52def657..370606ea08f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java +++ b/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ public class CloseableDisposerRecord implements DisposerRecord { this.closeable = closeable; } + @Override public synchronized void dispose() { if (closeable != null) { try { diff --git a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java index 229c470335b..7de400ad199 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java +++ b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,6 +60,7 @@ public class StreamCloser { if (streamCloser == null) { final Runnable streamCloserRunnable = new Runnable() { + @Override public void run() { if (toCloseQueue != null) { synchronized (StreamCloser.class) { diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java index 63a1359323f..24b50003e3c 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,8 +136,7 @@ final class LCMS implements PCMM { static native void colorConvert(long trans, int width, int height, int srcOffset, int srcNextRowOffset, int dstOffset, int dstNextRowOffset, - Object srcData, Object dstData, - int srcType, int dstType); + Object srcData, Object dstData); private LCMS() {} diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java index 663e11ff172..c7bae875282 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java @@ -31,7 +31,6 @@ import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.ComponentSampleModel; import java.awt.image.Raster; -import java.lang.annotation.Native; import java.nio.ByteOrder; import sun.awt.image.ByteComponentRaster; @@ -69,14 +68,7 @@ final class LCMSImageLayout { // private static final int PT_BGRA_8 = PT_ABGR_8 | SWAPFIRST; private static final int SWAP_ENDIAN = ByteOrder.nativeOrder() == LITTLE_ENDIAN ? DOSWAP : 0; - @Native - private static final int DT_BYTE = 0; - @Native - private static final int DT_SHORT = 1; - @Native - private static final int DT_INT = 2; int pixelType; - int dataType; int width; int height; int nextRowOffset; @@ -93,12 +85,10 @@ final class LCMSImageLayout { * @param data the storage of pixels: {@code byte[], short[] or int[]} * @param length the length of the data array * @param nc the number of color components - * @param dt the type of data array: DT_BYTE, DT_SHORT or DT_INT * @param size the size of one color component in bytes */ - private LCMSImageLayout(Object data, int length, int nc, int dt, int size) { + private LCMSImageLayout(Object data, int length, int nc, int size) { dataArray = data; - dataType = dt; dataArrayLength = length * size; pixelType = CHANNELS_SH(nc) | BYTES_SH(size); width = length / nc; @@ -109,11 +99,11 @@ final class LCMSImageLayout { } LCMSImageLayout(byte[] data, int nc) { - this(data, data.length, nc, DT_BYTE, Byte.BYTES); + this(data, data.length, nc, Byte.BYTES); } LCMSImageLayout(short[] data, int nc) { - this(data, data.length, nc, DT_SHORT, Short.BYTES); + this(data, data.length, nc, Short.BYTES); } private LCMSImageLayout() { @@ -186,7 +176,6 @@ final class LCMSImageLayout { l.offset = safeMult(4, intRaster.getDataOffset(0)); l.dataArray = intRaster.getDataStorage(); l.dataArrayLength = 4 * intRaster.getDataStorage().length; - l.dataType = DT_INT; } case BufferedImage.TYPE_BYTE_GRAY, BufferedImage.TYPE_3BYTE_BGR, BufferedImage.TYPE_4BYTE_ABGR, @@ -201,7 +190,6 @@ final class LCMSImageLayout { l.offset = byteRaster.getDataOffset(firstBand); l.dataArray = byteRaster.getDataStorage(); l.dataArrayLength = byteRaster.getDataStorage().length; - l.dataType = DT_BYTE; } case BufferedImage.TYPE_USHORT_GRAY -> { if (!(raster instanceof ShortComponentRaster shortRaster)) { @@ -212,7 +200,6 @@ final class LCMSImageLayout { l.offset = safeMult(2, shortRaster.getDataOffset(0)); l.dataArray = shortRaster.getDataStorage(); l.dataArrayLength = 2 * shortRaster.getDataStorage().length; - l.dataType = DT_SHORT; } default -> { return null; @@ -319,7 +306,6 @@ final class LCMSImageLayout { l.nextPixelOffset = br.getPixelStride(); l.offset = br.getDataOffset(firstBand); - l.dataType = DT_BYTE; byte[] data = br.getDataStorage(); l.dataArray = data; l.dataArrayLength = data.length; diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java index 881a6556ace..3f4f510cf94 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java @@ -121,8 +121,7 @@ final class LCMSTransform implements ColorTransform { } LCMS.colorConvert(tfm.ID, in.width, in.height, in.offset, in.nextRowOffset, out.offset, out.nextRowOffset, - in.dataArray, out.dataArray, - in.dataType, out.dataType); + in.dataArray, out.dataArray); Reference.reachabilityFence(tfm); // prevent deallocation of "tfm.ID" } diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index d43ccf2e8e4..8899491c6c0 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.47 +## libpng v1.6.51 ### libpng License
@@ -9,7 +9,7 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
 PNG Reference Library License version 2
 ---------------------------------------
 
-Copyright (c) 1995-2025 The PNG Reference Library Authors.
+Copyright (C) 1995-2025 The PNG Reference Library Authors.
 Copyright (C) 2018-2025 Cosmin Truta
 Copyright (C) 1998-2018 Glenn Randers-Pehrson
 Copyright (C) 1996-1997 Andreas Dilger
@@ -173,6 +173,7 @@ Authors, for copyright and licensing purposes.
  * Lucas Chollet
  * Magnus Holmgren
  * Mandar Sahastrabuddhe
+ * Manfred Schlaegl
  * Mans Rullgard
  * Matt Sarett
  * Mike Klein
@@ -184,6 +185,7 @@ Authors, for copyright and licensing purposes.
  * Samuel Williams
  * Simon-Pierre Cadieux
  * Tim Wegner
+ * Tobias Stoeckmann
  * Tom Lane
  * Tom Tanner
  * Vadim Barkov
@@ -193,8 +195,9 @@ Authors, for copyright and licensing purposes.
     - Zixu Wang (王子旭)
  * Arm Holdings
     - Richard Townsend
- * Google Inc.
+ * Google LLC
     - Dan Field
+    - Dragoș Tiselice
     - Leon Scroggins III
     - Matt Sarett
     - Mike Klein
@@ -204,6 +207,8 @@ Authors, for copyright and licensing purposes.
     - GuXiWei (顾希伟)
     - JinBo (金波)
     - ZhangLixia (张利霞)
+ * Samsung Group
+    - Filip Wasil
 
 The build projects, the build scripts, the test scripts, and other
 files in the "projects", "scripts" and "tests" directories, have
@@ -214,3 +219,4 @@ of the tools-generated files that are distributed with libpng, have
 other copyright owners, and are released under other open source
 licenses.
 ```
+
diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c
index 5cf7ee6c436..5d4ace7a624 100644
--- a/src/java.desktop/share/native/liblcms/LCMS.c
+++ b/src/java.desktop/share/native/liblcms/LCMS.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@
 #include 
 #include 
 #include "sun_java2d_cmm_lcms_LCMS.h"
-#include "sun_java2d_cmm_lcms_LCMSImageLayout.h"
 #include "jni_util.h"
 #include "Trace.h"
 #include "Disposer.h"
@@ -46,10 +45,6 @@
 
 #define SigHead TagIdConst('h','e','a','d')
 
-#define DT_BYTE     sun_java2d_cmm_lcms_LCMSImageLayout_DT_BYTE
-#define DT_SHORT    sun_java2d_cmm_lcms_LCMSImageLayout_DT_SHORT
-#define DT_INT      sun_java2d_cmm_lcms_LCMSImageLayout_DT_INT
-
 /* Default temp profile list size */
 #define DF_ICC_BUF_SIZE 32
 
@@ -464,46 +459,17 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative
     }
 }
 
-static void *getILData(JNIEnv *env, jobject data, jint type) {
-    switch (type) {
-        case DT_BYTE:
-            return (*env)->GetByteArrayElements(env, data, 0);
-        case DT_SHORT:
-            return (*env)->GetShortArrayElements(env, data, 0);
-        case DT_INT:
-            return (*env)->GetIntArrayElements(env, data, 0);
-        default:
-            return NULL;
-    }
-}
-
-static void releaseILData(JNIEnv *env, void *pData, jint type, jobject data,
-                          jint mode) {
-    switch (type) {
-        case DT_BYTE:
-            (*env)->ReleaseByteArrayElements(env, data, (jbyte *) pData, mode);
-            break;
-        case DT_SHORT:
-            (*env)->ReleaseShortArrayElements(env, data, (jshort *) pData, mode);
-            break;
-        case DT_INT:
-            (*env)->ReleaseIntArrayElements(env, data, (jint *) pData, mode);
-            break;
-    }
-}
-
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
  * Method:    colorConvert
- * Signature: (JIIIIIIZZLjava/lang/Object;Ljava/lang/Object;)V
+ * Signature: (JIIIIIILjava/lang/Object;Ljava/lang/Object;)V
  */
 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert
   (JNIEnv *env, jclass cls, jlong ID, jint width, jint height, jint srcOffset,
    jint srcNextRowOffset, jint dstOffset, jint dstNextRowOffset,
-   jobject srcData, jobject dstData, jint srcDType, jint dstDType)
+   jobject srcData, jobject dstData)
 {
     cmsHTRANSFORM sTrans = jlong_to_ptr(ID);
-
     if (sTrans == NULL) {
         J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL");
         JNU_ThrowByName(env, "java/awt/color/CMMException",
@@ -511,28 +477,22 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert
         return;
     }
 
-    void *inputBuffer = getILData(env, srcData, srcDType);
+    void *inputBuffer = (*env)->GetPrimitiveArrayCritical(env, srcData, NULL);
     if (inputBuffer == NULL) {
-        J2dRlsTraceLn(J2D_TRACE_ERROR, "");
         // An exception should have already been thrown.
         return;
     }
+    void *outputBuffer = (*env)->GetPrimitiveArrayCritical(env, dstData, NULL);
+    if (outputBuffer != NULL) {
+        char *input = (char *) inputBuffer + srcOffset;
+        char *output = (char *) outputBuffer + dstOffset;
 
-    void *outputBuffer = getILData(env, dstData, dstDType);
-    if (outputBuffer == NULL) {
-        releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT);
-        // An exception should have already been thrown.
-        return;
+        cmsDoTransformLineStride(sTrans, input, output, width, height,
+                                 srcNextRowOffset, dstNextRowOffset, 0, 0);
+
+        (*env)->ReleasePrimitiveArrayCritical(env, dstData, outputBuffer, 0);
     }
-
-    char *input = (char *) inputBuffer + srcOffset;
-    char *output = (char *) outputBuffer + dstOffset;
-
-    cmsDoTransformLineStride(sTrans, input, output, width, height,
-                             srcNextRowOffset, dstNextRowOffset, 0, 0);
-
-    releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT);
-    releaseILData(env, outputBuffer, dstDType, dstData, 0);
+    (*env)->ReleasePrimitiveArrayCritical(env, srcData, inputBuffer, JNI_ABORT);
 }
 
 static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
index 834b5e19277..2478fd0fc08 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
@@ -6251,6 +6251,59 @@ Version 1.6.47 [February 18, 2025]
     colorspace precedence rules, due to pre-existing colorspace checks.
     (Reported by Bob Friesenhahn; fixed by John Bowler)
 
+Version 1.6.48 [April 30, 2025]
+  Fixed the floating-point version of the mDCv setter `png_set_mDCv`.
+    (Reported by Mohit Bakshi; fixed by John Bowler)
+  Added #error directives to discourage the inclusion of private
+    libpng implementation header files in PNG-supporting applications.
+  Added the CMake build option `PNG_LIBCONF_HEADER`, to be used as an
+    alternative to `DFA_XTRA`.
+  Removed the Travis CI configuration files, with heartfelt thanks for
+    their generous support of our project over the past five years!
+
+Version 1.6.49 [June 12, 2025]
+  Added SIMD-optimized code for the RISC-V Vector Extension (RVV).
+    (Contributed by Manfred Schlaegl, Dragos Tiselice and Filip Wasil)
+  Added various fixes and improvements to the build scripts and to
+    the sample code.
+
+Version 1.6.50 [July 1, 2025]
+  Improved the detection of the RVV Extension on the RISC-V platform.
+    (Contributed by Filip Wasil)
+  Replaced inline ASM with C intrinsics in the RVV code.
+    (Contributed by Filip Wasil)
+  Fixed a decoder defect in which unknown chunks trailing IDAT, set
+    to go through the unknown chunk handler, incorrectly triggered
+    out-of-place IEND errors.
+    (Contributed by John Bowler)
+  Fixed the CMake file for cross-platform builds that require `libm`.
+
+Version 1.6.51 [November 21, 2025]
+  Fixed CVE-2025-64505 (moderate severity):
+    Heap buffer overflow in `png_do_quantize` via malformed palette index.
+    (Reported by Samsung; analyzed by Fabio Gritti.)
+  Fixed CVE-2025-64506 (moderate severity):
+    Heap buffer over-read in `png_write_image_8bit` with 8-bit input and
+    `convert_to_8bit` enabled.
+    (Reported by Samsung and ;
+    analyzed by Fabio Gritti.)
+  Fixed CVE-2025-64720 (high severity):
+    Buffer overflow in `png_image_read_composite` via incorrect palette
+    premultiplication.
+    (Reported by Samsung; analyzed by John Bowler.)
+  Fixed CVE-2025-65018 (high severity):
+    Heap buffer overflow in `png_combine_row` triggered via
+    `png_image_finish_read`.
+    (Reported by .)
+  Fixed a memory leak in `png_set_quantize`.
+    (Reported by Samsung; analyzed by Fabio Gritti.)
+  Removed the experimental and incomplete ERROR_NUMBERS code.
+    (Contributed by Tobias Stoeckmann.)
+  Improved the RISC-V vector extension support; required RVV 1.0 or newer.
+    (Contributed by Filip Wasil.)
+  Added GitHub Actions workflows for automated testing.
+  Performed various refactorings and cleanups.
+
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
 Subscription is required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
index 57952fb215a..5ea329ee3da 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/README
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.47
+README for libpng version 1.6.51
 ================================
 
 See the note about version numbers near the top of `png.h`.
@@ -147,6 +147,7 @@ Files included in this distribution
     loongarch/    =>  Optimized code for LoongArch LSX
     mips/         =>  Optimized code for MIPS MSA and MIPS MMI
     powerpc/      =>  Optimized code for PowerPC VSX
+    riscv/        =>  Optimized code for the RISC-V platform
     ci/           =>  Scripts for continuous integration
     contrib/      =>  External contributions
         arm-neon/     =>  Optimized code for the ARM-NEON platform
@@ -162,6 +163,7 @@ Files included in this distribution
                           programs demonstrating the use of pngusr.dfa
         pngminus/     =>  Simple pnm2png and png2pnm programs
         pngsuite/     =>  Test images
+        riscv-rvv/    =>  Optimized code for the RISC-V Vector platform
         testpngs/     =>  Test images
         tools/        =>  Various tools
         visupng/      =>  VisualPng, a Windows viewer for PNG images
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
index 7b6de2f8ec3..7d85e7c8d5f 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
@@ -42,7 +42,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_47 Your_png_h_is_not_version_1_6_47;
+typedef png_libpng_version_1_6_51 Your_png_h_is_not_version_1_6_51;
 
 /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
  * corresponding macro definitions.  This causes a compile time failure if
@@ -137,10 +137,16 @@ png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
    if (png_ptr == NULL)
       return NULL;
 
-   if (items >= (~(png_alloc_size_t)0)/size)
+   /* This check against overflow is vestigial, dating back from
+    * the old times when png_zalloc used to be an exported function.
+    * We're still keeping it here for now, as an extra-cautious
+    * prevention against programming errors inside zlib, although it
+    * should rather be a debug-time assertion instead.
+    */
+   if (size != 0 && items >= (~(png_alloc_size_t)0) / size)
    {
-      png_warning (png_voidcast(png_structrp, png_ptr),
-          "Potential overflow in png_zalloc()");
+      png_warning(png_voidcast(png_structrp, png_ptr),
+                  "Potential overflow in png_zalloc()");
       return NULL;
    }
 
@@ -267,10 +273,6 @@ png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver)
       png_warning(png_ptr, m);
 #endif
 
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
-      png_ptr->flags = 0;
-#endif
-
       return 0;
    }
 
@@ -729,7 +731,7 @@ png_get_io_ptr(png_const_structrp png_ptr)
  * function of your own because "FILE *" isn't necessarily available.
  */
 void PNGAPI
-png_init_io(png_structrp png_ptr, png_FILE_p fp)
+png_init_io(png_structrp png_ptr, FILE *fp)
 {
    png_debug(1, "in png_init_io");
 
@@ -844,7 +846,7 @@ png_get_copyright(png_const_structrp png_ptr)
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.47" PNG_STRING_NEWLINE \
+      "libpng version 1.6.51" PNG_STRING_NEWLINE \
       "Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
@@ -1520,7 +1522,7 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
 }
 #endif /* COLORSPACE */
 
-#ifdef PNG_iCCP_SUPPORTED
+#ifdef PNG_READ_iCCP_SUPPORTED
 /* Error message generation */
 static char
 png_icc_tag_char(png_uint_32 byte)
@@ -1596,9 +1598,7 @@ png_icc_profile_error(png_const_structrp png_ptr, png_const_charp name,
 
    return 0;
 }
-#endif /* iCCP */
 
-#ifdef PNG_READ_iCCP_SUPPORTED
 /* Encoded value of D50 as an ICC XYZNumber.  From the ICC 2010 spec the value
  * is XYZ(0.9642,1.0,0.8249), which scales to:
  *
@@ -3998,7 +3998,7 @@ png_image_free_function(png_voidp argument)
 #  ifdef PNG_STDIO_SUPPORTED
       if (cp->owned_file != 0)
       {
-         FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr);
+         FILE *fp = png_voidcast(FILE *, cp->png_ptr->io_ptr);
          cp->owned_file = 0;
 
          /* Ignore errors here. */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
index ede12c34fe6..d39ff73552c 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.47
+ * libpng version 1.6.51
  *
  * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
@@ -43,7 +43,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.47, February 2025:
+ *   libpng versions 1.6.36, December 2018, through 1.6.51, November 2025:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -267,7 +267,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.47                  16    10647  16.so.16.47[.0]
+ *    1.6.51                  16    10651  16.so.16.51[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -303,7 +303,7 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.47"
+#define PNG_LIBPNG_VER_STRING "1.6.51"
 #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
 
 /* The versions of shared library builds should stay in sync, going forward */
@@ -314,7 +314,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 47
+#define PNG_LIBPNG_VER_RELEASE 51
 
 /* This should be zero for a public release, or non-zero for a
  * development version.
@@ -345,7 +345,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10647 /* 1.6.47 */
+#define PNG_LIBPNG_VER 10651 /* 1.6.51 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -455,7 +455,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_6_47;
+typedef char* png_libpng_version_1_6_51;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
@@ -1599,7 +1599,7 @@ PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
 
 #ifdef PNG_STDIO_SUPPORTED
 /* Initialize the input/output for the PNG file to the default functions. */
-PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
+PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, FILE *fp));
 #endif
 
 /* Replace the (error and abort), and warning functions with user
@@ -3117,7 +3117,7 @@ PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,
     */
 
 PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image,
-   FILE* file));
+   FILE *file));
    /* The PNG header is read from the stdio FILE object. */
 #endif /* STDIO */
 
@@ -3192,7 +3192,7 @@ PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,
 PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,
    int convert_to_8_bit, const void *buffer, png_int_32 row_stride,
    const void *colormap));
-   /* Write the image to the given (FILE*). */
+   /* Write the image to the given FILE object. */
 #endif /* SIMPLIFIED_WRITE_STDIO */
 
 /* With all write APIs if image is in one of the linear formats with 16-bit
@@ -3332,26 +3332,45 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
  *           selected at run time.
  */
 #ifdef PNG_SET_OPTION_SUPPORTED
+
+/* HARDWARE: ARM Neon SIMD instructions supported */
 #ifdef PNG_ARM_NEON_API_SUPPORTED
-#  define PNG_ARM_NEON   0 /* HARDWARE: ARM Neon SIMD instructions supported */
-#endif
-#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */
-#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */
-#ifdef PNG_MIPS_MSA_API_SUPPORTED
-#  define PNG_MIPS_MSA   6 /* HARDWARE: MIPS Msa SIMD instructions supported */
-#endif
-#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
-#  define PNG_IGNORE_ADLER32 8 /* SOFTWARE: disable Adler32 check on IDAT */
-#endif
-#ifdef PNG_POWERPC_VSX_API_SUPPORTED
-#  define PNG_POWERPC_VSX   10 /* HARDWARE: PowerPC VSX SIMD instructions
-                                * supported */
-#endif
-#ifdef PNG_MIPS_MMI_API_SUPPORTED
-#  define PNG_MIPS_MMI   12 /* HARDWARE: MIPS MMI SIMD instructions supported */
+#  define PNG_ARM_NEON 0
 #endif
 
-#define PNG_OPTION_NEXT  14 /* Next option - numbers must be even */
+/* SOFTWARE: Force maximum window */
+#define PNG_MAXIMUM_INFLATE_WINDOW 2
+
+/* SOFTWARE: Check ICC profile for sRGB */
+#define PNG_SKIP_sRGB_CHECK_PROFILE 4
+
+/* HARDWARE: MIPS MSA SIMD instructions supported */
+#ifdef PNG_MIPS_MSA_API_SUPPORTED
+#  define PNG_MIPS_MSA 6
+#endif
+
+/* SOFTWARE: Disable Adler32 check on IDAT */
+#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
+#  define PNG_IGNORE_ADLER32 8
+#endif
+
+/* HARDWARE: PowerPC VSX SIMD instructions supported */
+#ifdef PNG_POWERPC_VSX_API_SUPPORTED
+#  define PNG_POWERPC_VSX 10
+#endif
+
+/* HARDWARE: MIPS MMI SIMD instructions supported */
+#ifdef PNG_MIPS_MMI_API_SUPPORTED
+#  define PNG_MIPS_MMI 12
+#endif
+
+/* HARDWARE: RISC-V RVV SIMD instructions supported */
+#ifdef PNG_RISCV_RVV_API_SUPPORTED
+#  define PNG_RISCV_RVV 14
+#endif
+
+/* Next option - numbers must be even */
+#define PNG_OPTION_NEXT 16
 
 /* Return values: NOTE: there are four values and 'off' is *not* zero */
 #define PNG_OPTION_UNSET   0 /* Unset - defaults to off */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
index 70bca6fa1c9..4bc5f7bb468 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.47
+ * libpng version 1.6.51
  *
  * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
@@ -248,25 +248,13 @@
   /* NOTE: PNGCBAPI always defaults to PNGCAPI. */
 
 #  if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD)
-#     error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed"
+#     error PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed
 #  endif
 
-#  if (defined(_MSC_VER) && _MSC_VER < 800) ||\
-      (defined(__BORLANDC__) && __BORLANDC__ < 0x500)
-   /* older Borland and MSC
-    * compilers used '__export' and required this to be after
-    * the type.
-    */
-#    ifndef PNG_EXPORT_TYPE
-#      define PNG_EXPORT_TYPE(type) type PNG_IMPEXP
-#    endif
-#    define PNG_DLL_EXPORT __export
-#  else /* newer compiler */
-#    define PNG_DLL_EXPORT __declspec(dllexport)
-#    ifndef PNG_DLL_IMPORT
-#      define PNG_DLL_IMPORT __declspec(dllimport)
-#    endif
-#  endif /* compiler */
+#  define PNG_DLL_EXPORT __declspec(dllexport)
+#  ifndef PNG_DLL_IMPORT
+#    define PNG_DLL_IMPORT __declspec(dllimport)
+#  endif
 
 #else /* !Windows */
 #  if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
@@ -508,7 +496,7 @@
 #if CHAR_BIT == 8 && UCHAR_MAX == 255
    typedef unsigned char png_byte;
 #else
-#  error "libpng requires 8-bit bytes"
+#  error libpng requires 8-bit bytes
 #endif
 
 #if INT_MIN == -32768 && INT_MAX == 32767
@@ -516,7 +504,7 @@
 #elif SHRT_MIN == -32768 && SHRT_MAX == 32767
    typedef short png_int_16;
 #else
-#  error "libpng requires a signed 16-bit type"
+#  error libpng requires a signed 16-bit integer type
 #endif
 
 #if UINT_MAX == 65535
@@ -524,7 +512,7 @@
 #elif USHRT_MAX == 65535
    typedef unsigned short png_uint_16;
 #else
-#  error "libpng requires an unsigned 16-bit type"
+#  error libpng requires an unsigned 16-bit integer type
 #endif
 
 #if INT_MIN < -2147483646 && INT_MAX > 2147483646
@@ -532,7 +520,7 @@
 #elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646
    typedef long int png_int_32;
 #else
-#  error "libpng requires a signed 32-bit (or more) type"
+#  error libpng requires a signed 32-bit (or longer) integer type
 #endif
 
 #if UINT_MAX > 4294967294U
@@ -540,7 +528,7 @@
 #elif ULONG_MAX > 4294967294U
    typedef unsigned long int png_uint_32;
 #else
-#  error "libpng requires an unsigned 32-bit (or more) type"
+#  error libpng requires an unsigned 32-bit (or longer) integer type
 #endif
 
 /* Prior to 1.6.0, it was possible to disable the use of size_t and ptrdiff_t.
@@ -621,10 +609,6 @@ typedef const png_fixed_point * png_const_fixed_point_p;
 typedef size_t                * png_size_tp;
 typedef const size_t          * png_const_size_tp;
 
-#ifdef PNG_STDIO_SUPPORTED
-typedef FILE            * png_FILE_p;
-#endif
-
 #ifdef PNG_FLOATING_POINT_SUPPORTED
 typedef double       * png_doublep;
 typedef const double * png_const_doublep;
@@ -646,6 +630,15 @@ typedef double          * * png_doublepp;
 /* Pointers to pointers to pointers; i.e., pointer to array */
 typedef char            * * * png_charppp;
 
+#ifdef PNG_STDIO_SUPPORTED
+/* With PNG_STDIO_SUPPORTED it was possible to use I/O streams that were
+ * not necessarily stdio FILE streams, to allow building Windows applications
+ * before Win32 and Windows CE applications before WinCE 3.0, but that kind
+ * of support has long been discontinued.
+ */
+typedef FILE            * png_FILE_p; /* [Deprecated] */
+#endif
+
 #endif /* PNG_BUILDING_SYMBOL_TABLE */
 
 #endif /* PNGCONF_H */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h
index 8eb5400ea9a..6ea2644dfcd 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h
@@ -22,14 +22,14 @@
  * questions.
  */
 
-/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c
+/* pngdebug.h - internal debugging macros for libpng
  *
  * This file is available under and governed by the GNU General Public
  * License version 2 only, as published by the Free Software Foundation.
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -39,6 +39,10 @@
  * and license in png.h
  */
 
+#ifndef PNGPRIV_H
+#  error This file must not be included by applications; please include 
+#endif
+
 /* Define PNG_DEBUG at compile time for debugging information.  Higher
  * numbers for PNG_DEBUG mean more debugging information.  This has
  * only been added since version 0.95 so it is not implemented throughout
@@ -63,9 +67,6 @@
 #define PNGDEBUG_H
 /* These settings control the formatting of messages in png.c and pngerror.c */
 /* Moved to pngdebug.h at 1.5.0 */
-#  ifndef PNG_LITERAL_SHARP
-#    define PNG_LITERAL_SHARP 0x23
-#  endif
 #  ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET
 #    define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b
 #  endif
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
index ea0103331d3..44c86ebfef9 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -68,46 +68,6 @@ PNG_FUNCTION(void,PNGAPI
 png_error,(png_const_structrp png_ptr, png_const_charp error_message),
     PNG_NORETURN)
 {
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
-   char msg[16];
-   if (png_ptr != NULL)
-   {
-      if ((png_ptr->flags &
-         (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
-      {
-         if (*error_message == PNG_LITERAL_SHARP)
-         {
-            /* Strip "#nnnn " from beginning of error message. */
-            int offset;
-            for (offset = 1; offset<15; offset++)
-               if (error_message[offset] == ' ')
-                  break;
-
-            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
-            {
-               int i;
-               for (i = 0; i < offset - 1; i++)
-                  msg[i] = error_message[i + 1];
-               msg[i - 1] = '\0';
-               error_message = msg;
-            }
-
-            else
-               error_message += offset;
-         }
-
-         else
-         {
-            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
-            {
-               msg[0] = '0';
-               msg[1] = '\0';
-               error_message = msg;
-            }
-         }
-      }
-   }
-#endif
    if (png_ptr != NULL && png_ptr->error_fn != NULL)
       (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),
           error_message);
@@ -245,21 +205,6 @@ void PNGAPI
 png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
 {
    int offset = 0;
-   if (png_ptr != NULL)
-   {
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
-   if ((png_ptr->flags &
-       (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
-#endif
-      {
-         if (*warning_message == PNG_LITERAL_SHARP)
-         {
-            for (offset = 1; offset < 15; offset++)
-               if (warning_message[offset] == ' ')
-                  break;
-         }
-      }
-   }
    if (png_ptr != NULL && png_ptr->warning_fn != NULL)
       (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),
           warning_message + offset);
@@ -741,42 +686,9 @@ png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
     PNG_NORETURN)
 {
 #ifdef PNG_CONSOLE_IO_SUPPORTED
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
-   /* Check on NULL only added in 1.5.4 */
-   if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
-   {
-      /* Strip "#nnnn " from beginning of error message. */
-      int offset;
-      char error_number[16];
-      for (offset = 0; offset<15; offset++)
-      {
-         error_number[offset] = error_message[offset + 1];
-         if (error_message[offset] == ' ')
-            break;
-      }
-
-      if ((offset > 1) && (offset < 15))
-      {
-         error_number[offset - 1] = '\0';
-         fprintf(stderr, "libpng error no. %s: %s",
-             error_number, error_message + offset + 1);
-         fprintf(stderr, PNG_STRING_NEWLINE);
-      }
-
-      else
-      {
-         fprintf(stderr, "libpng error: %s, offset=%d",
-             error_message, offset);
-         fprintf(stderr, PNG_STRING_NEWLINE);
-      }
-   }
-   else
-#endif
-   {
-      fprintf(stderr, "libpng error: %s", error_message ? error_message :
-         "undefined");
-      fprintf(stderr, PNG_STRING_NEWLINE);
-   }
+   fprintf(stderr, "libpng error: %s", error_message ? error_message :
+      "undefined");
+   fprintf(stderr, PNG_STRING_NEWLINE);
 #else
    PNG_UNUSED(error_message) /* Make compiler happy */
 #endif
@@ -814,40 +726,8 @@ static void /* PRIVATE */
 png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
 {
 #ifdef PNG_CONSOLE_IO_SUPPORTED
-#  ifdef PNG_ERROR_NUMBERS_SUPPORTED
-   if (*warning_message == PNG_LITERAL_SHARP)
-   {
-      int offset;
-      char warning_number[16];
-      for (offset = 0; offset < 15; offset++)
-      {
-         warning_number[offset] = warning_message[offset + 1];
-         if (warning_message[offset] == ' ')
-            break;
-      }
-
-      if ((offset > 1) && (offset < 15))
-      {
-         warning_number[offset + 1] = '\0';
-         fprintf(stderr, "libpng warning no. %s: %s",
-             warning_number, warning_message + offset);
-         fprintf(stderr, PNG_STRING_NEWLINE);
-      }
-
-      else
-      {
-         fprintf(stderr, "libpng warning: %s",
-             warning_message);
-         fprintf(stderr, PNG_STRING_NEWLINE);
-      }
-   }
-   else
-#  endif
-
-   {
-      fprintf(stderr, "libpng warning: %s", warning_message);
-      fprintf(stderr, PNG_STRING_NEWLINE);
-   }
+   fprintf(stderr, "libpng warning: %s", warning_message);
+   fprintf(stderr, PNG_STRING_NEWLINE);
 #else
    PNG_UNUSED(warning_message) /* Make compiler happy */
 #endif
@@ -895,12 +775,8 @@ png_get_error_ptr(png_const_structrp png_ptr)
 void PNGAPI
 png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
 {
-   if (png_ptr != NULL)
-   {
-      png_ptr->flags &=
-         ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
-         PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
-   }
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(strip_mode)
 }
 #endif
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
index d67adbae247..ed2e7f886f5 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h
index bc6ed3d09c9..c79c6cc780f 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h
@@ -22,14 +22,14 @@
  * questions.
  */
 
-/* pnginfo.h - header file for PNG reference library
+/* pnginfo.h - internal structures for libpng
  *
  * This file is available under and governed by the GNU General Public
  * License version 2 only, as published by the Free Software Foundation.
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2013,2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -39,43 +39,20 @@
  * and license in png.h
  */
 
- /* png_info is a structure that holds the information in a PNG file so
- * that the application can find out the characteristics of the image.
- * If you are reading the file, this structure will tell you what is
- * in the PNG file.  If you are writing the file, fill in the information
- * you want to put into the PNG file, using png_set_*() functions, then
- * call png_write_info().
+#ifndef PNGPRIV_H
+#  error This file must not be included by applications; please include 
+#endif
+
+/* INTERNAL, PRIVATE definition of a PNG.
  *
- * The names chosen should be very close to the PNG specification, so
- * consult that document for information about the meaning of each field.
+ * png_info is a modifiable description of a PNG datastream.  The fields inside
+ * this structure are accessed through png_get_() functions and modified
+ * using png_set_() functions.
  *
- * With libpng < 0.95, it was only possible to directly set and read the
- * the values in the png_info_struct, which meant that the contents and
- * order of the values had to remain fixed.  With libpng 0.95 and later,
- * however, there are now functions that abstract the contents of
- * png_info_struct from the application, so this makes it easier to use
- * libpng with dynamic libraries, and even makes it possible to use
- * libraries that don't have all of the libpng ancillary chunk-handing
- * functionality.  In libpng-1.5.0 this was moved into a separate private
- * file that is not visible to applications.
- *
- * The following members may have allocated storage attached that should be
- * cleaned up before the structure is discarded: palette, trans, text,
- * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile,
- * splt_palettes, scal_unit, row_pointers, and unknowns.   By default, these
- * are automatically freed when the info structure is deallocated, if they were
- * allocated internally by libpng.  This behavior can be changed by means
- * of the png_data_freer() function.
- *
- * More allocation details: all the chunk-reading functions that
- * change these members go through the corresponding png_set_*
- * functions.  A function to clear these members is available: see
- * png_free_data().  The png_set_* functions do not depend on being
- * able to point info structure members to any of the storage they are
- * passed (they make their own copies), EXCEPT that the png_set_text
- * functions use the same storage passed to them in the text_ptr or
- * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns
- * functions do not make their own copies.
+ * Some functions in libpng do directly access members of png_info.  However,
+ * this should be avoided.  png_struct objects contain members which hold
+ * caches, sometimes optimised, of the values from png_info objects, and
+ * png_info is not passed to the functions which read and write image data.
  */
 #ifndef PNGINFO_H
 #define PNGINFO_H
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
index 906f855db0e..4cfae474751 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
@@ -31,7 +31,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  */
-/* libpng version 1.6.47 */
+/* libpng version 1.6.51 */
 
 /* Copyright (c) 2018-2025 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
index ba9eb4df402..12b71bcbc02 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
index 86d0c7aaa64..3bfa913000f 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -258,6 +258,14 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
          png_benign_error(png_ptr, "Too many IDATs found");
    }
 
+   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
+   {
+      /* These flags must be set consistently for all non-IDAT chunks,
+       * including the unknown chunks.
+       */
+      png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT;
+   }
+
    if (chunk_name == png_IHDR)
    {
       if (png_ptr->push_length != 13)
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
index 25bac4b9e69..dcd005efb34 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -48,8 +48,20 @@
  * they should be well aware of the issues that may arise from doing so.
  */
 
+
+/* pngpriv.h must be included first in each translation unit inside libpng.
+ * On the other hand, it must not be included at all, directly or indirectly,
+ * by any application code that uses the libpng API.
+ */
 #ifndef PNGPRIV_H
-#define PNGPRIV_H
+#  define PNGPRIV_H
+#else
+#  error Duplicate inclusion of pngpriv.h; please check the libpng source files
+#endif
+
+#if defined(PNG_H) || defined(PNGCONF_H) || defined(PNGLCONF_H)
+#  error This file must not be included by applications; please include 
+#endif
 
 /* Feature Test Macros.  The following are defined here to ensure that correctly
  * implemented libraries reveal the APIs libpng needs to build and hide those
@@ -86,7 +98,6 @@
  */
 #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
 #  include 
-
    /* Pick up the definition of 'restrict' from config.h if it was read: */
 #  define PNG_RESTRICT restrict
 #endif
@@ -96,9 +107,7 @@
  * are not internal definitions may be required.  This is handled below just
  * before png.h is included, but load the configuration now if it is available.
  */
-#ifndef PNGLCONF_H
-#  include "pnglibconf.h"
-#endif
+#include "pnglibconf.h"
 
 /* Local renames may change non-exported API functions from png.h */
 #if defined(PNG_PREFIX) && !defined(PNGPREFIX_H)
@@ -163,6 +172,20 @@
 #  endif
 #endif
 
+#ifndef PNG_RISCV_RVV_OPT
+   /* RISCV_RVV optimizations are being controlled by the compiler settings,
+    * typically the target compiler will define __riscv but the rvv extension
+    * availability has to be explicitly stated. This is why if no
+    * PNG_RISCV_RVV_OPT was defined then a runtime check will be executed.
+    *
+    * To enable RISCV_RVV optimizations unconditionally, and compile the
+    * associated code, pass --enable-riscv-rvv=yes or --enable-riscv-rvv=on
+    * to configure or put -DPNG_RISCV_RVV_OPT=2 in CPPFLAGS.
+    */
+
+#  define PNG_RISCV_RVV_OPT 0
+#endif
+
 #if PNG_ARM_NEON_OPT > 0
    /* NEON optimizations are to be at least considered by libpng, so enable the
     * callbacks to do this.
@@ -308,6 +331,16 @@
 #   define PNG_LOONGARCH_LSX_IMPLEMENTATION 0
 #endif
 
+#if PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000
+#  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_rvv
+#  ifndef PNG_RISCV_RVV_IMPLEMENTATION
+      /* Use the intrinsics code by default. */
+#     define PNG_RISCV_RVV_IMPLEMENTATION 1
+#  endif
+#else
+#  define PNG_RISCV_RVV_IMPLEMENTATION 0
+#endif /* PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000 */
+
 /* Is this a build of a DLL where compilation of the object modules requires
  * different preprocessor settings to those required for a simple library?  If
  * so PNG_BUILD_DLL must be set.
@@ -706,7 +739,7 @@
 /* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS      0x8000U */
 /* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS      0x10000U */
 #define PNG_FLAG_LIBRARY_MISMATCH        0x20000U
-#define PNG_FLAG_STRIP_ERROR_NUMBERS     0x40000U
+                                  /*     0x40000U    unused */
 #define PNG_FLAG_STRIP_ERROR_TEXT        0x80000U
 #define PNG_FLAG_BENIGN_ERRORS_WARN     0x100000U /* Added to libpng-1.4.0 */
 #define PNG_FLAG_APP_WARNINGS_WARN      0x200000U /* Added to libpng-1.6.0 */
@@ -1020,17 +1053,15 @@
  * must match that used in the build, or we must be using pnglibconf.h.prebuilt:
  */
 #if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM
-#  error ZLIB_VERNUM != PNG_ZLIB_VERNUM \
-      "-I (include path) error: see the notes in pngpriv.h"
-   /* This means that when pnglibconf.h was built the copy of zlib.h that it
-    * used is not the same as the one being used here.  Because the build of
-    * libpng makes decisions to use inflateInit2 and inflateReset2 based on the
-    * zlib version number and because this affects handling of certain broken
-    * PNG files the -I directives must match.
+#  error The include path of  is incorrect
+   /* When pnglibconf.h was built, the copy of zlib.h that it used was not the
+    * same as the one being used here.  Considering how libpng makes decisions
+    * to use the zlib API based on the zlib version number, the -I options must
+    * match.
     *
-    * The most likely explanation is that you passed a -I in CFLAGS. This will
-    * not work; all the preprocessor directives and in particular all the -I
-    * directives must be in CPPFLAGS.
+    * A possible cause of this mismatch is that you passed an -I option in
+    * CFLAGS, which is unlikely to work.  All the preprocessor options, and all
+    * the -I options in particular, should be in CPPFLAGS.
     */
 #endif
 
@@ -1544,6 +1575,23 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_lsx,(png_row_infop
     row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
 #endif
 
+#if PNG_RISCV_RVV_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_rvv,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_rvv,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_rvv,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_rvv,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_rvv,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_rvv,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_rvv,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
 /* Choose the best filter to use and filter the row data */
 PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,
     png_row_infop row_info),PNG_EMPTY);
@@ -2156,6 +2204,11 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx,
     (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
 #endif
 
+#  if PNG_RISCV_RVV_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_rvv,
+   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+#endif
+
 PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
    png_const_charp key, png_bytep new_key), PNG_EMPTY);
 
@@ -2191,4 +2244,3 @@ PNG_INTERNAL_FUNCTION(int,
 #endif
 
 #endif /* PNG_VERSION_INFO_ONLY */
-#endif /* PNGPRIV_H */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
index 8a6381e1b3e..b53668a09ce 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
@@ -731,7 +731,12 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
       png_uint_32 chunk_name = png_ptr->chunk_name;
 
       if (chunk_name != png_IDAT)
-         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
+      {
+         /* These flags must be set consistently for all non-IDAT chunks,
+          * including the unknown chunks.
+          */
+         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT;
+      }
 
       if (chunk_name == png_IEND)
          png_handle_chunk(png_ptr, info_ptr, length);
@@ -838,7 +843,8 @@ png_read_destroy(png_structrp png_ptr)
 #endif
 
 #if defined(PNG_READ_EXPAND_SUPPORTED) && \
-    defined(PNG_ARM_NEON_IMPLEMENTATION)
+    (defined(PNG_ARM_NEON_IMPLEMENTATION) || \
+     defined(PNG_RISCV_RVV_IMPLEMENTATION))
    png_free(png_ptr, png_ptr->riffled_palette);
    png_ptr->riffled_palette = NULL;
 #endif
@@ -1357,7 +1363,7 @@ png_image_read_header(png_voidp argument)
 
 #ifdef PNG_STDIO_SUPPORTED
 int PNGAPI
-png_image_begin_read_from_stdio(png_imagep image, FILE* file)
+png_image_begin_read_from_stdio(png_imagep image, FILE *file)
 {
    if (image != NULL && image->version == PNG_IMAGE_VERSION)
    {
@@ -3152,6 +3158,54 @@ png_image_read_colormapped(png_voidp argument)
    }
 }
 
+/* Row reading for interlaced 16-to-8 bit depth conversion with local buffer. */
+static int
+png_image_read_direct_scaled(png_voidp argument)
+{
+   png_image_read_control *display = png_voidcast(png_image_read_control*,
+       argument);
+   png_imagep image = display->image;
+   png_structrp png_ptr = image->opaque->png_ptr;
+   png_bytep local_row = png_voidcast(png_bytep, display->local_row);
+   png_bytep first_row = png_voidcast(png_bytep, display->first_row);
+   ptrdiff_t row_bytes = display->row_bytes;
+   int passes;
+
+   /* Handle interlacing. */
+   switch (png_ptr->interlaced)
+   {
+      case PNG_INTERLACE_NONE:
+         passes = 1;
+         break;
+
+      case PNG_INTERLACE_ADAM7:
+         passes = PNG_INTERLACE_ADAM7_PASSES;
+         break;
+
+      default:
+         png_error(png_ptr, "unknown interlace type");
+   }
+
+   /* Read each pass using local_row as intermediate buffer. */
+   while (--passes >= 0)
+   {
+      png_uint_32 y = image->height;
+      png_bytep output_row = first_row;
+
+      for (; y > 0; --y)
+      {
+         /* Read into local_row (gets transformed 8-bit data). */
+         png_read_row(png_ptr, local_row, NULL);
+
+         /* Copy from local_row to user buffer. */
+         memcpy(output_row, local_row, (size_t)row_bytes);
+         output_row += row_bytes;
+      }
+   }
+
+   return 1;
+}
+
 /* Just the row reading part of png_image_read. */
 static int
 png_image_read_composite(png_voidp argument)
@@ -3570,6 +3624,7 @@ png_image_read_direct(png_voidp argument)
    int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0;
    int do_local_compose = 0;
    int do_local_background = 0; /* to avoid double gamma correction bug */
+   int do_local_scale = 0; /* for interlaced 16-to-8 bit conversion */
    int passes = 0;
 
    /* Add transforms to ensure the correct output format is produced then check
@@ -3703,8 +3758,16 @@ png_image_read_direct(png_voidp argument)
             png_set_expand_16(png_ptr);
 
          else /* 8-bit output */
+         {
             png_set_scale_16(png_ptr);
 
+            /* For interlaced images, use local_row buffer to avoid overflow
+             * in png_combine_row() which writes using IHDR bit-depth.
+             */
+            if (png_ptr->interlaced != 0)
+               do_local_scale = 1;
+         }
+
          change &= ~PNG_FORMAT_FLAG_LINEAR;
       }
 
@@ -3980,6 +4043,24 @@ png_image_read_direct(png_voidp argument)
       return result;
    }
 
+   else if (do_local_scale != 0)
+   {
+      /* For interlaced 16-to-8 conversion, use an intermediate row buffer
+       * to avoid buffer overflows in png_combine_row. The local_row is sized
+       * for the transformed (8-bit) output, preventing the overflow that would
+       * occur if png_combine_row wrote 16-bit data directly to the user buffer.
+       */
+      int result;
+      png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
+
+      display->local_row = row;
+      result = png_safe_execute(image, png_image_read_direct_scaled, display);
+      display->local_row = NULL;
+      png_free(png_ptr, row);
+
+      return result;
+   }
+
    else
    {
       png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c
index 961d010df42..50a424d0912 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -85,7 +85,7 @@ png_default_read_data(png_structp png_ptr, png_bytep data, size_t length)
    /* fread() returns 0 on error, so it is OK to store this in a size_t
     * instead of an int, which is what fread() actually returns.
     */
-   check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr));
+   check = fread(data, 1, length, png_voidcast(FILE *, png_ptr->io_ptr));
 
    if (check != length)
       png_error(png_ptr, "Read Error");
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
index 4f31f8f07bc..a19615f49fe 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -57,6 +57,12 @@
 #  endif
 #endif
 
+#ifdef PNG_RISCV_RVV_IMPLEMENTATION
+#  if PNG_RISCV_RVV_IMPLEMENTATION == 1
+#    define PNG_RISCV_RVV_INTRINSICS_AVAILABLE
+#  endif
+#endif
+
 #ifdef PNG_READ_SUPPORTED
 
 /* Set the action on getting a CRC error for an ancillary or critical chunk. */
@@ -524,9 +530,19 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
    {
       int i;
 
+      /* Initialize the array to index colors.
+       *
+       * Ensure quantize_index can fit 256 elements (PNG_MAX_PALETTE_LENGTH)
+       * rather than num_palette elements. This is to prevent buffer overflows
+       * caused by malformed PNG files with out-of-range palette indices.
+       *
+       * Be careful to avoid leaking memory. Applications are allowed to call
+       * this function more than once per png_struct.
+       */
+      png_free(png_ptr, png_ptr->quantize_index);
       png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
-          (png_alloc_size_t)num_palette);
-      for (i = 0; i < num_palette; i++)
+          PNG_MAX_PALETTE_LENGTH);
+      for (i = 0; i < PNG_MAX_PALETTE_LENGTH; i++)
          png_ptr->quantize_index[i] = (png_byte)i;
    }
 
@@ -538,15 +554,14 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
           * Perhaps not the best solution, but good enough.
           */
 
-         int i;
+         png_bytep quantize_sort;
+         int i, j;
 
-         /* Initialize an array to sort colors */
-         png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
+         /* Initialize the local array to sort colors. */
+         quantize_sort = (png_bytep)png_malloc(png_ptr,
              (png_alloc_size_t)num_palette);
-
-         /* Initialize the quantize_sort array */
          for (i = 0; i < num_palette; i++)
-            png_ptr->quantize_sort[i] = (png_byte)i;
+            quantize_sort[i] = (png_byte)i;
 
          /* Find the least used palette entries by starting a
           * bubble sort, and running it until we have sorted
@@ -558,19 +573,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
          for (i = num_palette - 1; i >= maximum_colors; i--)
          {
             int done; /* To stop early if the list is pre-sorted */
-            int j;
 
             done = 1;
             for (j = 0; j < i; j++)
             {
-               if (histogram[png_ptr->quantize_sort[j]]
-                   < histogram[png_ptr->quantize_sort[j + 1]])
+               if (histogram[quantize_sort[j]]
+                   < histogram[quantize_sort[j + 1]])
                {
                   png_byte t;
 
-                  t = png_ptr->quantize_sort[j];
-                  png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
-                  png_ptr->quantize_sort[j + 1] = t;
+                  t = quantize_sort[j];
+                  quantize_sort[j] = quantize_sort[j + 1];
+                  quantize_sort[j + 1] = t;
                   done = 0;
                }
             }
@@ -582,18 +596,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
          /* Swap the palette around, and set up a table, if necessary */
          if (full_quantize != 0)
          {
-            int j = num_palette;
+            j = num_palette;
 
             /* Put all the useful colors within the max, but don't
              * move the others.
              */
             for (i = 0; i < maximum_colors; i++)
             {
-               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
+               if ((int)quantize_sort[i] >= maximum_colors)
                {
                   do
                      j--;
-                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
+                  while ((int)quantize_sort[j] >= maximum_colors);
 
                   palette[i] = palette[j];
                }
@@ -601,7 +615,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
          }
          else
          {
-            int j = num_palette;
+            j = num_palette;
 
             /* Move all the used colors inside the max limit, and
              * develop a translation table.
@@ -609,13 +623,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
             for (i = 0; i < maximum_colors; i++)
             {
                /* Only move the colors we need to */
-               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
+               if ((int)quantize_sort[i] >= maximum_colors)
                {
                   png_color tmp_color;
 
                   do
                      j--;
-                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
+                  while ((int)quantize_sort[j] >= maximum_colors);
 
                   tmp_color = palette[j];
                   palette[j] = palette[i];
@@ -653,8 +667,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
                }
             }
          }
-         png_free(png_ptr, png_ptr->quantize_sort);
-         png_ptr->quantize_sort = NULL;
+         png_free(png_ptr, quantize_sort);
       }
       else
       {
@@ -1797,19 +1810,51 @@ png_init_read_transformations(png_structrp png_ptr)
                   }
                   else /* if (png_ptr->trans_alpha[i] != 0xff) */
                   {
-                     png_byte v, w;
+                     if ((png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0)
+                     {
+                        /* Premultiply only:
+                         * component = round((component * alpha) / 255)
+                         */
+                        png_uint_32 component;
 
-                     v = png_ptr->gamma_to_1[palette[i].red];
-                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
-                     palette[i].red = png_ptr->gamma_from_1[w];
+                        component = png_ptr->gamma_to_1[palette[i].red];
+                        component =
+                            (component * png_ptr->trans_alpha[i] + 128) / 255;
+                        palette[i].red = png_ptr->gamma_from_1[component];
 
-                     v = png_ptr->gamma_to_1[palette[i].green];
-                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
-                     palette[i].green = png_ptr->gamma_from_1[w];
+                        component = png_ptr->gamma_to_1[palette[i].green];
+                        component =
+                            (component * png_ptr->trans_alpha[i] + 128) / 255;
+                        palette[i].green = png_ptr->gamma_from_1[component];
 
-                     v = png_ptr->gamma_to_1[palette[i].blue];
-                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
-                     palette[i].blue = png_ptr->gamma_from_1[w];
+                        component = png_ptr->gamma_to_1[palette[i].blue];
+                        component =
+                            (component * png_ptr->trans_alpha[i] + 128) / 255;
+                        palette[i].blue = png_ptr->gamma_from_1[component];
+                     }
+                     else
+                     {
+                        /* Composite with background color:
+                         * component =
+                         *    alpha * component + (1 - alpha) * background
+                         */
+                        png_byte v, w;
+
+                        v = png_ptr->gamma_to_1[palette[i].red];
+                        png_composite(w, v,
+                            png_ptr->trans_alpha[i], back_1.red);
+                        palette[i].red = png_ptr->gamma_from_1[w];
+
+                        v = png_ptr->gamma_to_1[palette[i].green];
+                        png_composite(w, v,
+                            png_ptr->trans_alpha[i], back_1.green);
+                        palette[i].green = png_ptr->gamma_from_1[w];
+
+                        v = png_ptr->gamma_to_1[palette[i].blue];
+                        png_composite(w, v,
+                            png_ptr->trans_alpha[i], back_1.blue);
+                        palette[i].blue = png_ptr->gamma_from_1[w];
+                     }
                   }
                }
                else
@@ -5032,13 +5077,8 @@ png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
 
 #ifdef PNG_READ_QUANTIZE_SUPPORTED
    if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
-   {
       png_do_quantize(row_info, png_ptr->row_buf + 1,
           png_ptr->palette_lookup, png_ptr->quantize_index);
-
-      if (row_info->rowbytes == 0)
-         png_error(png_ptr, "png_do_quantize returned rowbytes=0");
-   }
 #endif /* READ_QUANTIZE */
 
 #ifdef PNG_READ_EXPAND_16_SUPPORTED
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
index 6cf466d182a..07d53cb2c76 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -2441,10 +2441,6 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
    }
 #endif
 
-   /* TODO: this doesn't work and shouldn't be necessary. */
-   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-      png_ptr->mode |= PNG_AFTER_IDAT;
-
    buffer = png_read_buffer(png_ptr, length+1);
 
    if (buffer == NULL)
@@ -2515,10 +2511,6 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
    }
 #endif
 
-   /* TODO: should not be necessary. */
-   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-      png_ptr->mode |= PNG_AFTER_IDAT;
-
    /* Note, "length" is sufficient here; we won't be adding
     * a null terminator later.  The limit check in png_handle_chunk should be
     * sufficient.
@@ -2635,10 +2627,6 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
    }
 #endif
 
-   /* TODO: should not be necessary. */
-   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
-      png_ptr->mode |= PNG_AFTER_IDAT;
-
    buffer = png_read_buffer(png_ptr, length+1);
 
    if (buffer == NULL)
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
index 1bfd292bd46..0b2844f1864 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
@@ -329,17 +329,14 @@ png_set_mDCV(png_const_structrp png_ptr, png_inforp info_ptr,
     double maxDL, double minDL)
 {
    png_set_mDCV_fixed(png_ptr, info_ptr,
-      /* The ITU approach is to scale by 50,000, not 100,000 so just divide
-       * the input values by 2 and use png_fixed:
-       */
-      png_fixed(png_ptr, white_x / 2, "png_set_mDCV(white(x))"),
-      png_fixed(png_ptr, white_y / 2, "png_set_mDCV(white(y))"),
-      png_fixed(png_ptr, red_x / 2, "png_set_mDCV(red(x))"),
-      png_fixed(png_ptr, red_y / 2, "png_set_mDCV(red(y))"),
-      png_fixed(png_ptr, green_x / 2, "png_set_mDCV(green(x))"),
-      png_fixed(png_ptr, green_y / 2, "png_set_mDCV(green(y))"),
-      png_fixed(png_ptr, blue_x / 2, "png_set_mDCV(blue(x))"),
-      png_fixed(png_ptr, blue_y / 2, "png_set_mDCV(blue(y))"),
+      png_fixed(png_ptr, white_x, "png_set_mDCV(white(x))"),
+      png_fixed(png_ptr, white_y, "png_set_mDCV(white(y))"),
+      png_fixed(png_ptr, red_x, "png_set_mDCV(red(x))"),
+      png_fixed(png_ptr, red_y, "png_set_mDCV(red(y))"),
+      png_fixed(png_ptr, green_x, "png_set_mDCV(green(x))"),
+      png_fixed(png_ptr, green_y, "png_set_mDCV(green(y))"),
+      png_fixed(png_ptr, blue_x, "png_set_mDCV(blue(x))"),
+      png_fixed(png_ptr, blue_y, "png_set_mDCV(blue(y))"),
       png_fixed_ITU(png_ptr, maxDL, "png_set_mDCV(maxDL)"),
       png_fixed_ITU(png_ptr, minDL, "png_set_mDCV(minDL)"));
 }
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
index d6c446564d1..8edb4bc393a 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
@@ -22,14 +22,14 @@
  * questions.
  */
 
-/* pngstruct.h - header file for PNG reference library
+/* pngstruct.h - internal structures for libpng
  *
  * This file is available under and governed by the GNU General Public
  * License version 2 only, as published by the Free Software Foundation.
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2025 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -39,11 +39,9 @@
  * and license in png.h
  */
 
-/* The structure that holds the information to read and write PNG files.
- * The only people who need to care about what is inside of this are the
- * people who will be modifying the library for their own special needs.
- * It should NOT be accessed directly by an application.
- */
+#ifndef PNGPRIV_H
+#  error This file must not be included by applications; please include 
+#endif
 
 #ifndef PNGSTRUCT_H
 #define PNGSTRUCT_H
@@ -406,7 +404,8 @@ struct png_struct_def
 
 /* New member added in libpng-1.6.36 */
 #if defined(PNG_READ_EXPAND_SUPPORTED) && \
-    defined(PNG_ARM_NEON_IMPLEMENTATION)
+    (defined(PNG_ARM_NEON_IMPLEMENTATION) || \
+     defined(PNG_RISCV_RVV_IMPLEMENTATION))
    png_bytep riffled_palette; /* buffer for accelerated palette expansion */
 #endif
 
@@ -435,7 +434,6 @@ struct png_struct_def
 
 #ifdef PNG_READ_QUANTIZE_SUPPORTED
 /* The following three members were added at version 1.0.14 and 1.2.4 */
-   png_bytep quantize_sort;          /* working sort array */
    png_bytep index_to_palette;       /* where the original index currently is
                                         in the palette */
    png_bytep palette_to_index;       /* which original index points to this
diff --git a/src/java.management/share/classes/sun/management/ThreadImpl.java b/src/java.management/share/classes/sun/management/ThreadImpl.java
index be54ced066d..a246e01dd63 100644
--- a/src/java.management/share/classes/sun/management/ThreadImpl.java
+++ b/src/java.management/share/classes/sun/management/ThreadImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -308,7 +308,7 @@ public class ThreadImpl implements ThreadMXBean {
                 long id = ids[0];
                 Thread thread = Thread.currentThread();
                 if (id == thread.threadId()) {
-                    times[0] = thread.isVirtual() ? -1L : getThreadTotalCpuTime0(0);
+                    times[0] = thread.isVirtual() ? -1L : getThreadUserCpuTime0(0);
                 } else {
                     times[0] = getThreadUserCpuTime0(id);
                 }
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java
index 1d8cb013295..e1725aa92d5 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java
@@ -205,32 +205,38 @@ final class ConnectionPool {
 
         // it's possible that cleanup may have been called.
         HttpConnection toClose = null;
+        boolean stopping = false;
         stateLock.lock();
         try {
             if (cleanup.isDone()) {
                 return;
-            } else if (stopped) {
-                conn.close();
-                return;
-            }
-            if (MAX_POOL_SIZE > 0 && expiryList.size() >= MAX_POOL_SIZE) {
-                toClose = expiryList.removeOldest();
-                if (toClose != null) removeFromPool(toClose);
-            }
-            if (conn instanceof PlainHttpConnection) {
-                putConnection(conn, plainPool);
+            } else if (stopping = stopped) {
+                toClose = conn;
             } else {
-                assert conn.isSecure();
-                putConnection(conn, sslPool);
+                if (MAX_POOL_SIZE > 0 && expiryList.size() >= MAX_POOL_SIZE) {
+                    toClose = expiryList.removeOldest();
+                    if (toClose != null) removeFromPool(toClose);
+                }
+                if (conn instanceof PlainHttpConnection) {
+                    putConnection(conn, plainPool);
+                } else {
+                    assert conn.isSecure();
+                    putConnection(conn, sslPool);
+                }
+                expiryList.add(conn, now, keepAlive);
             }
-            expiryList.add(conn, now, keepAlive);
         } finally {
             stateLock.unlock();
         }
         if (toClose != null) {
             if (debug.on()) {
-                debug.log("Maximum pool size reached: removing oldest connection %s",
-                          toClose.dbgString());
+                if (stopping) {
+                    debug.log("Stopping: close connection %s",
+                            toClose.dbgString());
+                } else {
+                    debug.log("Maximum pool size reached: removing oldest connection %s",
+                            toClose.dbgString());
+                }
             }
             close(toClose);
         }
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java
index b97a441881d..6bf1b9184f8 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java
@@ -126,11 +126,16 @@ public final class Http3Connection implements AutoCloseable {
     // as per spec
     // -1 is used to imply no GOAWAY received so far
     private final AtomicLong lowestGoAwayReceipt = new AtomicLong(-1);
+
+    private final Duration idleTimeoutDuration;
     private volatile IdleConnectionTimeoutEvent idleConnectionTimeoutEvent;
     // value of true implies no more streams will be initiated on this connection,
     // and the connection will be closed once the in-progress streams complete.
     private volatile boolean finalStream;
     private volatile boolean allowOnlyOneStream;
+    // true if this connection has been placed in the HTTP/3 connection pool of the HttpClient.
+    // false otherwise.
+    private volatile boolean presentInConnPool;
     // set to true if we decide to open a new connection
     // due to stream limit reached
     private volatile boolean streamLimitReached;
@@ -220,6 +225,17 @@ public final class Http3Connection implements AutoCloseable {
                 // in case of exception. Throws in the dependent
                 // action after wrapping the exception if needed.
                 .exceptionally(this::exceptionallyAndClose);
+
+        this.idleTimeoutDuration = client.client().idleConnectionTimeout(HTTP_3).orElse(null);
+        if (idleTimeoutDuration == null) {
+            // The absence of HTTP/3 idle timeout duration is considered to mean
+            // never idle terminating the connection
+            quicConnection.connectionTerminator().appLayerMaxIdle(Duration.MAX,
+                    this::isQUICTrafficGenerationRequired);
+        } else {
+            quicConnection.connectionTerminator().appLayerMaxIdle(idleTimeoutDuration,
+                    this::isQUICTrafficGenerationRequired);
+        }
         if (Log.http3()) {
             Log.logHttp3("HTTP/3 connection created for " + quicConnectionTag() + " - local address: "
                     + quicConnection.localAddress());
@@ -545,7 +561,28 @@ public final class Http3Connection implements AutoCloseable {
         if (debug.on()) debug.log("Reference h3 stream: " + streamId);
         client.client.h3StreamReference();
         exchanges.put(streamId, exchange);
-        exchange.start();
+        // It's possible that the connection will have been closed
+        // by the time we reach here.
+        // We need to double-check that the connection is still opened
+        // after having put the exchange to the exchanges map.
+        if (isOpen()) {
+            // only start the exchange if the connection is
+            // still open
+            exchange.start();
+        } else {
+            // Otherwise mark the exchange as unprocessed since we haven't
+            // sent the headers yet and the connection got closed
+            // before we started the exchange.
+            TerminationCause tc = quicConnection.terminationCause();
+            if (Log.http3()) {
+                Log.logHttp3("HTTP/3 exchange for {0}/streamId={1} unprocessed due to {2}",
+                        quicConnectionTag(), Long.toString(streamId), tc.getCloseCause());
+            }
+            exchange.exchange.markUnprocessedByPeer();
+            exchange.cancelImpl(tc.getCloseCause(),
+                    Http3Error.fromCode(tc.getCloseCode()).orElse(H3_NO_ERROR));
+        }
+        // OK to return the exchange even if already closed
         return exchange;
     }
 
@@ -732,9 +769,8 @@ public final class Http3Connection implements AutoCloseable {
             try {
                 var te = idleConnectionTimeoutEvent;
                 if (te == null && exchangeStreams.isEmpty()) {
-                    te = idleConnectionTimeoutEvent = client.client().idleConnectionTimeout(HTTP_3)
-                            .map(IdleConnectionTimeoutEvent::new).orElse(null);
-                    if (te != null) {
+                    if (idleTimeoutDuration != null) {
+                        te = idleConnectionTimeoutEvent = new IdleConnectionTimeoutEvent();
                         client.client().registerTimer(te);
                     }
                 }
@@ -873,6 +909,48 @@ public final class Http3Connection implements AutoCloseable {
         }
     }
 
+    /**
+     * Mark this connection as being present or absent from the connection pool.
+     */
+    void setPooled(final boolean present) {
+        this.presentInConnPool = present;
+    }
+
+    /**
+     * This callback method is invoked by the QUIC layer when it notices that this
+     * connection hasn't seen any traffic for certain period of time. QUIC
+     * invokes this method to ask HTTP/3 whether the QUIC layer
+     * should generate traffic to keep this connection active.
+     * This method returns true, indicating that the traffic must be generated,
+     * if this HTTP/3 connection is in pool and there's no current request/response
+     * in progress over this connection (i.e. the HTTP/3 connection is idle in the
+     * pool waiting for any new requests to be issued by the application).
+     */
+    private boolean isQUICTrafficGenerationRequired() {
+        if (!isOpen()) {
+            return false;
+        }
+        lock();
+        try {
+            // if there's no HTTP/3 request/responses in progress and the connection is
+            // in the pool (thus idle), then we instruct QUIC to generate traffic on the
+            // QUIC connection to prevent it from being idle terminated.
+            final boolean generateTraffic = this.presentInConnPool
+                    && this.exchanges.isEmpty()
+                    && this.reservedStreamCount.get() == 0
+                    // a connection in the pool could be marked as
+                    // finalStream (for example when it receives a GOAWAY). we don't want
+                    // to generate explicit QUIC traffic for such connections too.
+                    && !this.finalStream;
+            if (debug.on()) {
+                debug.log("QUIC traffic generation required = " + generateTraffic);
+            }
+            return generateTraffic;
+        } finally {
+            unlock();
+        }
+    }
+
     /**
      * Cancels any event that might have been scheduled to shutdown this connection. Must be called
      * with the stateLock held.
@@ -893,8 +971,9 @@ public final class Http3Connection implements AutoCloseable {
         private boolean cancelled;
         private boolean idleShutDownInitiated;
 
-        IdleConnectionTimeoutEvent(Duration duration) {
-            super(duration);
+        IdleConnectionTimeoutEvent() {
+            assert idleTimeoutDuration != null : "idle timeout duration is null";
+            super(idleTimeoutDuration);
         }
 
         @Override
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java
index eaacd8213cb..0f1fe2b7abf 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java
@@ -155,23 +155,34 @@ class Http3ConnectionPool {
         assert key.equals(c.key());
         var altService = c.connection().getSourceAltService().orElse(null);
         if (altService != null && altService.wasAdvertised()) {
-            return advertised.putIfAbsent(key, c);
+            final var prev = advertised.putIfAbsent(key, c);
+            if (prev == null) {
+                c.setPooled(true); // mark the newly pooled connection as pooled
+            }
+            return prev;
         }
         assert altService == null || altService.originHasSameAuthority();
-        return unadvertised.putIfAbsent(key, c);
+        final var prev = unadvertised.putIfAbsent(key, c);
+        if (prev == null) {
+            c.setPooled(true); // mark the newly pooled connection as pooled
+        }
+        return prev;
     }
 
-    Http3Connection put(String key, Http3Connection c) {
+    void put(String key, Http3Connection c) {
         Objects.requireNonNull(key);
         Objects.requireNonNull(c);
         assert key.equals(c.key()) : "key mismatch %s -> %s"
                 .formatted(key, c.key());
         var altService = c.connection().getSourceAltService().orElse(null);
         if (altService != null && altService.wasAdvertised()) {
-            return advertised.put(key, c);
+            advertised.put(key, c);
+            c.setPooled(true);
+            return;
         }
         assert altService == null || altService.originHasSameAuthority();
-        return unadvertised.put(key, c);
+        unadvertised.put(key, c);
+        c.setPooled(true);
     }
 
     boolean remove(String key, Http3Connection c) {
@@ -189,11 +200,17 @@ class Http3ConnectionPool {
         }
 
         assert altService == null || altService.originHasSameAuthority();
-        return unadvertised.remove(key, c);
+        final boolean removed = unadvertised.remove(key, c);
+        if (removed) {
+            c.setPooled(false);
+        }
+        return removed;
     }
 
     void clear() {
+        advertised.values().forEach((c) -> c.setPooled(false));
         advertised.clear();
+        unadvertised.values().forEach((c) -> c.setPooled(false));
         unadvertised.clear();
     }
 
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java
index af9fd3b96ba..d02930f4f31 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java
@@ -53,6 +53,7 @@ import java.security.NoSuchAlgorithmException;
 import java.time.Duration;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -126,6 +127,8 @@ final class HttpClientImpl extends HttpClient implements Trackable {
     // Defaults to value used for HTTP/1 Keep-Alive Timeout. Can be overridden by jdk.httpclient.keepalive.timeout.h2 property.
     static final long IDLE_CONNECTION_TIMEOUT_H2 = getTimeoutProp("jdk.httpclient.keepalive.timeout.h2", KEEP_ALIVE_TIMEOUT);
     static final long IDLE_CONNECTION_TIMEOUT_H3 = getTimeoutProp("jdk.httpclient.keepalive.timeout.h3", IDLE_CONNECTION_TIMEOUT_H2);
+    private final boolean hasRequiredH3TLS;
+    private final boolean hasRequiredH2TLS;
 
     static final UseVTForSelector USE_VT_FOR_SELECTOR =
         Utils.useVTForSelector("jdk.internal.httpclient.tcp.selector.useVirtualThreads", "default");
@@ -477,10 +480,17 @@ final class HttpClientImpl extends HttpClient implements Trackable {
                     "HTTP3 is not supported"));
         }
         sslParams = requireNonNullElseGet(builder.sslParams, sslContext::getDefaultSSLParameters);
-        boolean sslParamsSupportedForH3 = sslParams.getProtocols() == null
-                || sslParams.getProtocols().length == 0
-                || isQuicCompatible(sslParams);
-        if (version == Version.HTTP_3 && !sslParamsSupportedForH3) {
+        String[] sslProtocols = sslParams.getProtocols();
+        if (sslProtocols == null) {
+            sslProtocols = requireNonNullElseGet(sslContext.getDefaultSSLParameters().getProtocols(),
+                    () -> new String[0]);
+        }
+        // HTTP/3 MUST use TLS version 1.3 or higher
+        hasRequiredH3TLS = Arrays.asList(sslProtocols).contains("TLSv1.3");
+        // HTTP/2 MUST use TLS version 1.2 or higher for HTTP/2 over TLS
+        hasRequiredH2TLS = hasRequiredH3TLS || Arrays.asList(sslProtocols).contains("TLSv1.2");
+
+        if (version == Version.HTTP_3 && !hasRequiredH3TLS) {
             throw new UncheckedIOException(new UnsupportedProtocolVersionException(
                     "HTTP3 is not supported - TLSv1.3 isn't configured on SSLParameters"));
         }
@@ -507,7 +517,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
             debug.log("proxySelector is %s (user-supplied=%s)",
                       this.proxySelector, userProxySelector != null);
         authenticator = builder.authenticator;
-        boolean h3Supported = sslCtxSupportedForH3 && sslParamsSupportedForH3;
+        boolean h3Supported = sslCtxSupportedForH3 && hasRequiredH3TLS;
         registry = new AltServicesRegistry(id);
         connections = new ConnectionPool(id);
         client2 = new Http2ClientImpl(this);
@@ -530,6 +540,22 @@ final class HttpClientImpl extends HttpClient implements Trackable {
         assert facadeRef.get() != null;
     }
 
+    /**
+     * Returns true if the SSL parameter protocols contains at
+     * least one TLS version that HTTP/3 requires.
+     */
+    boolean hasRequiredHTTP3TLSVersion() {
+        return hasRequiredH3TLS;
+    }
+
+    /**
+     * Returns true if the SSL parameter protocols contains at
+     * least one TLS version that HTTP/2 requires.
+     */
+    boolean hasRequiredHTTP2TLSVersion() {
+        return hasRequiredH2TLS;
+    }
+
     // called when the facade is GC'ed.
     // Just wakes up the selector to cleanup...
     void facadeCleanup() {
@@ -1333,6 +1359,13 @@ final class HttpClientImpl extends HttpClient implements Trackable {
 
         // Only called by the selector manager thread
         private void shutdown() {
+            // first stop the client to avoid seeing exceptions
+            // about "selector manager closed"
+            Log.logTrace("{0}: stopping", owner.dbgTag);
+            try {
+                owner.stop();
+            } catch (Throwable ignored) {
+            }
             try {
                 lock.lock();
                 try {
@@ -1345,6 +1378,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
                 }
             } catch (IOException ignored) {
             } finally {
+                // cleanup anything that might have been left behind
                 owner.stop();
             }
         }
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java
index 115bc56f804..0c1388cec8a 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java
@@ -32,7 +32,6 @@ import java.net.http.HttpResponse;
 import java.nio.ByteBuffer;
 import java.nio.channels.NetworkChannel;
 import java.nio.channels.SocketChannel;
-import java.util.Arrays;
 import java.util.Comparator;
 import java.util.IdentityHashMap;
 import java.util.List;
@@ -43,8 +42,6 @@ import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.Flow;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.BiPredicate;
-import java.util.function.Predicate;
-import java.net.http.HttpClient;
 import java.net.http.HttpClient.Version;
 import java.net.http.HttpHeaders;
 
@@ -285,23 +282,6 @@ abstract class HttpConnection implements Closeable {
      */
     abstract HttpPublisher publisher();
 
-    // HTTP/2 MUST use TLS version 1.2 or higher for HTTP/2 over TLS
-    private static final Predicate testRequiredHTTP2TLSVersion = proto ->
-            proto.equals("TLSv1.2") || proto.equals("TLSv1.3");
-
-   /**
-    * Returns true if the given client's SSL parameter protocols contains at
-    * least one TLS version that HTTP/2 requires.
-    */
-   private static final boolean hasRequiredHTTP2TLSVersion(HttpClient client) {
-       String[] protos = client.sslParameters().getProtocols();
-       if (protos != null) {
-           return Arrays.stream(protos).filter(testRequiredHTTP2TLSVersion).findAny().isPresent();
-       } else {
-           return false;
-       }
-   }
-
     /**
      * Factory for retrieving HttpConnections. A connection can be retrieved
      * from the connection pool, or a new one created if none available.
@@ -359,7 +339,7 @@ abstract class HttpConnection implements Closeable {
             } else {
                 assert !request.isHttp3Only(version); // should have failed before
                 String[] alpn = null;
-                if (version == HTTP_2 && hasRequiredHTTP2TLSVersion(client)) {
+                if (version == HTTP_2 && client.hasRequiredHTTP2TLSVersion()) {
                     // We only come here after we have checked the HTTP/2 connection pool.
                     // We will not negotiate HTTP/2 if we don't have the appropriate TLS version
                     alpn = new String[] { Alpns.H2, Alpns.HTTP_1_1 };
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java
index 0a22256f6c6..36f191fbd67 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java
@@ -31,11 +31,9 @@ import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.net.SocketOption;
 import java.net.URI;
-import java.net.http.HttpClient;
 import java.net.http.HttpConnectTimeoutException;
 import java.nio.channels.NetworkChannel;
 import java.time.Duration;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -43,7 +41,6 @@ import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
-import java.util.function.Predicate;
 
 import javax.net.ssl.SNIServerName;
 import javax.net.ssl.SSLParameters;
@@ -81,9 +78,6 @@ abstract class HttpQuicConnection extends HttpConnection {
     // the alt-service which was advertised, from some origin, for this connection co-ordinates.
     // can be null, which indicates this wasn't created because of an alt-service
     private final AltService sourceAltService;
-    // HTTP/2 MUST use TLS version 1.3 or higher for HTTP/3 over TLS
-    private static final Predicate testRequiredHTTP3TLSVersion = proto ->
-            proto.equals("TLSv1.3");
 
 
     HttpQuicConnection(Origin originServer, InetSocketAddress address, HttpClientImpl client,
@@ -178,19 +172,6 @@ abstract class HttpQuicConnection extends HttpConnection {
         return quicConnection;
     }
 
-    /**
-     * Returns true if the given client's SSL parameter protocols contains at
-     * least one TLS version that HTTP/3 requires.
-     */
-    private static boolean hasRequiredHTTP3TLSVersion(HttpClient client) {
-        String[] protos = client.sslParameters().getProtocols();
-        if (protos != null) {
-            return Arrays.stream(protos).anyMatch(testRequiredHTTP3TLSVersion);
-        } else {
-            return false;
-        }
-    }
-
     /**
      * Called when the HTTP/3 connection is established, either successfully or
      * unsuccessfully
@@ -260,7 +241,7 @@ abstract class HttpQuicConnection extends HttpConnection {
         // to using HTTP/2
         var debug = h3client.debug();
         var where = "HttpQuicConnection.getHttpQuicConnection";
-        if (proxy != null || !hasRequiredHTTP3TLSVersion(client)) {
+        if (proxy != null || !client.hasRequiredHTTP3TLSVersion()) {
             if (debug.on())
                 debug.log("%s: proxy required or SSL version mismatch", where);
             return null;
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java
index e705aae72a1..45d242df671 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java
@@ -311,20 +311,20 @@ class PlainHttpConnection extends HttpConnection {
             var connectTimerEvent = this.connectTimerEvent;
             if (connectTimerEvent != null)
                 client().cancelTimer(connectTimerEvent);
-            if (Log.channel()) {
-                Log.logChannel("Closing channel: " + chan);
-            }
-            try {
-                tube.signalClosed(errorRef.get());
-                chan.close();
-            } finally {
-                client().connectionClosed(this);
-            }
+        } finally {
+            stateLock.unlock();
+        }
+        if (Log.channel()) {
+            Log.logChannel("Closing channel: " + chan);
+        }
+        try {
+            tube.signalClosed(errorRef.get());
+            chan.close();
         } catch (IOException e) {
             debug.log("Closing resulted in " + e);
             Log.logTrace("Closing resulted in " + e);
         } finally {
-            stateLock.unlock();
+            client().connectionClosed(this);
         }
     }
 
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java
index 4b59a777de2..9a7ccd8f3a1 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java
@@ -31,7 +31,6 @@ import java.io.UncheckedIOException;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
 import java.net.ProtocolException;
-import java.net.URI;
 import java.net.http.HttpResponse.BodyHandler;
 import java.net.http.HttpResponse.ResponseInfo;
 import java.nio.ByteBuffer;
@@ -973,36 +972,6 @@ class Stream extends ExchangeImpl {
         return headers;
     }
 
-    private static HttpHeaders createPseudoHeaders(HttpRequest request) {
-        HttpHeadersBuilder hdrs = new HttpHeadersBuilder();
-        String method = request.method();
-        hdrs.setHeader(":method", method);
-        URI uri = request.uri();
-        hdrs.setHeader(":scheme", uri.getScheme());
-        String host = uri.getHost();
-        int port = uri.getPort();
-        assert host != null;
-        if (port != -1) {
-            hdrs.setHeader(":authority", host + ":" + port);
-        } else {
-            hdrs.setHeader(":authority", host);
-        }
-        String query = uri.getRawQuery();
-        String path = uri.getRawPath();
-        if (path == null || path.isEmpty()) {
-            if (method.equalsIgnoreCase("OPTIONS")) {
-                path = "*";
-            } else {
-                path = "/";
-            }
-        }
-        if (query != null) {
-            path += "?" + query;
-        }
-        hdrs.setHeader(":path", Utils.encode(path));
-        return hdrs.build();
-    }
-
     HttpHeaders getRequestPseudoHeaders() {
         return requestPseudoHeaders;
     }
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java
index 24230a0883d..14559db4a11 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java
@@ -24,15 +24,77 @@
  */
 package jdk.internal.net.http.quic;
 
-// responsible for managing the connection termination of a QUIC connection
+import java.time.Duration;
+import java.util.function.Supplier;
+
+/**
+ * Responsible for managing the connection termination of a QUIC connection
+ */
 public sealed interface ConnectionTerminator permits ConnectionTerminatorImpl {
 
-    // lets the terminator know that the connection is still alive and should not be
-    // idle timed out
-    void keepAlive();
+    /**
+     * Instructs the connection terminator to consider the connection as active
+     * at the present point in time. The connection terminator will then restart its
+     * idle timeout timer from this point in time.
+     * 

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

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

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

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

+ * If the application layer wishes to never idle terminate the connection, then + * a {@code maxIdle} duration of {@linkplain Duration#MAX Duration.MAX} is recommended. + * + * @param maxIdle the maximum idle duration of the connection, + * at the application layer + * @param trafficGenerationCheck the callback that will be invoked by the connection + * terminator to decide if the QUIC layer should generate + * any traffic to prevent the connection from idle terminating + * @throws NullPointerException if either {@code maxIdle} or {@code trafficGenerationCheck} + * is null + * @throws IllegalArgumentException if {@code maxIdle} is + * {@linkplain Duration#isNegative() negative} or + * {@linkplain Duration#isZero() zero} + */ + void appLayerMaxIdle(Duration maxIdle, Supplier trafficGenerationCheck); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java index 0f5aa4cb7ac..7870f4f1d8e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java @@ -25,11 +25,13 @@ package jdk.internal.net.http.quic; import java.nio.ByteBuffer; +import java.time.Duration; import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import java.util.function.Supplier; import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; @@ -52,7 +54,6 @@ import static jdk.internal.net.http.quic.QuicConnectionImpl.QuicConnectionState. import static jdk.internal.net.http.quic.TerminationCause.appLayerClose; import static jdk.internal.net.http.quic.TerminationCause.forSilentTermination; import static jdk.internal.net.http.quic.TerminationCause.forTransportError; -import static jdk.internal.net.quic.QuicTransportErrors.INTERNAL_ERROR; import static jdk.internal.net.quic.QuicTransportErrors.NO_ERROR; final class ConnectionTerminatorImpl implements ConnectionTerminator { @@ -70,8 +71,8 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator { } @Override - public void keepAlive() { - this.connection.idleTimeoutManager.keepAlive(); + public void markActive() { + this.connection.idleTimeoutManager.markActive(); } @Override @@ -79,6 +80,11 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator { return this.connection.idleTimeoutManager.tryReserveForUse(); } + @Override + public void appLayerMaxIdle(final Duration maxIdle, final Supplier trafficGenerationCheck) { + this.connection.idleTimeoutManager.appLayerMaxIdle(maxIdle, trafficGenerationCheck); + } + @Override public void terminate(final TerminationCause cause) { Objects.requireNonNull(cause); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java index 72ce0290038..375a0dc8e16 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java @@ -24,12 +24,15 @@ */ package jdk.internal.net.http.quic; +import java.time.Duration; import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; import jdk.internal.net.http.common.Deadline; import jdk.internal.net.http.common.Log; @@ -58,17 +61,21 @@ final class IdleTimeoutManager { private IdleTimeoutEvent idleTimeoutEvent; // must be accessed only when holding stateLock private StreamDataBlockedEvent streamDataBlockedEvent; - // the time at which the last outgoing packet was sent or an + // the time (in nanos) at which the last outgoing packet was sent or an // incoming packet processed on the connection - private volatile long lastPacketActivityAt; + private volatile long lastPacketActivityNanos; private final ReentrantLock idleTerminationLock = new ReentrantLock(); // true if it has been decided to terminate the connection due to being idle, // false otherwise. should be accessed only when holding the idleTerminationLock private boolean chosenForIdleTermination; - // the time at which the connection was last reserved for use. + // the time (in nanos) at which the connection was last reserved for use. // should be accessed only when holding the idleTerminationLock - private long lastUsageReservationAt; + private long lastUsageReservationNanos; + + private final AtomicReference> trafficGenerationCheck = new AtomicReference<>(); + // must be accessed only when holding stateLock + private PingEvent pingEvent; IdleTimeoutManager(final QuicConnectionImpl connection) { this.connection = Objects.requireNonNull(connection, "connection"); @@ -79,28 +86,12 @@ final class IdleTimeoutManager { * Starts the idle timeout management for the connection. This should be called * after the handshake is complete for the connection. * - * @throw IllegalStateException if handshake hasn't yet completed or if the handshake - * has failed for the connection + * @throws IllegalStateException if handshake hasn't yet completed or if the handshake + * has failed for the connection */ void start() { - final CompletableFuture handshakeCF = - this.connection.handshakeFlow().handshakeCF(); // start idle management only for successfully completed handshake - if (!handshakeCF.isDone()) { - throw new IllegalStateException("handshake isn't yet complete," - + " cannot start idle connection management"); - } - if (handshakeCF.isCompletedExceptionally()) { - throw new IllegalStateException("cannot start idle connection management for a failed" - + " connection"); - } - startTimers(); - } - - /** - * Starts the idle timeout timer of the QUIC connection, if not already started. - */ - private void startTimers() { + requireSuccessfulHandshake(); if (shutdown.get()) { return; } @@ -116,6 +107,19 @@ final class IdleTimeoutManager { } } + private void requireSuccessfulHandshake() { + final CompletableFuture handshakeCF = + this.connection.handshakeFlow().handshakeCF(); + if (!handshakeCF.isDone()) { + throw new IllegalStateException("handshake isn't yet complete," + + " cannot use idle connection management"); + } + if (handshakeCF.isCompletedExceptionally()) { + throw new IllegalStateException("cannot use idle connection management for a failed" + + " connection"); + } + } + private void startIdleTerminationTimer() { assert stateLock.isHeldByCurrentThread() : "not holding state lock"; final Optional idleTimeoutMillis = getIdleTimeout(); @@ -154,18 +158,14 @@ final class IdleTimeoutManager { } final QuicEndpoint endpoint = this.connection.endpoint(); assert endpoint != null : "QUIC endpoint is null"; - // disable the event (refreshDeadline() of IdleTimeoutEvent will return Deadline.MAX) - final Deadline nextDeadline = this.idleTimeoutEvent.nextDeadline; - if (!nextDeadline.equals(Deadline.MAX)) { - this.idleTimeoutEvent.nextDeadline = Deadline.MAX; - endpoint.timer().reschedule(this.idleTimeoutEvent, Deadline.MIN); - } + // disable the idle timeout timer event + disableTimedEvent(endpoint.timer(), this.idleTimeoutEvent); this.idleTimeoutEvent = null; } private void startStreamDataBlockedTimer() { assert stateLock.isHeldByCurrentThread() : "not holding state lock"; - // 75% of idle timeout or if idle timeout is not configured, then 30 seconds + // 75% of QUIC idle timeout or if QUIC idle timeout is not configured, then 30 seconds final long timeoutMillis = getIdleTimeout() .map((v) -> (long) (0.75 * v)) .orElse(30000L); @@ -194,22 +194,95 @@ final class IdleTimeoutManager { } final QuicEndpoint endpoint = this.connection.endpoint(); assert endpoint != null : "QUIC endpoint is null"; - // disable the event (refreshDeadline() of StreamDataBlockedEvent will return Deadline.MAX) - final Deadline nextDeadline = this.streamDataBlockedEvent.nextDeadline; - if (!nextDeadline.equals(Deadline.MAX)) { - this.streamDataBlockedEvent.nextDeadline = Deadline.MAX; - endpoint.timer().reschedule(this.streamDataBlockedEvent, Deadline.MIN); - } + // disable the stream data blocked timer event + disableTimedEvent(endpoint.timer(), this.streamDataBlockedEvent); this.streamDataBlockedEvent = null; } + // set up a PING timer if the application layer's max idle duration for the connection + // is larger than that of the negotiated QUIC idle timeout for that connection + void appLayerMaxIdle(final Duration maxIdle, final Supplier trafficGenerationCheck) { + Objects.requireNonNull(maxIdle, "maxIdle"); + Objects.requireNonNull(trafficGenerationCheck, "trafficGenerationCheck"); + if (maxIdle.isZero() || maxIdle.isNegative()) { + throw new IllegalArgumentException("invalid maxIdle duration: " + maxIdle); + } + // the application layer must not configure its max idle duration + // until the QUIC connection's handshake has successfully completed + requireSuccessfulHandshake(); + + if (!this.trafficGenerationCheck.compareAndSet(null, trafficGenerationCheck)) { + throw new IllegalStateException("app layer max inactivity already set"); + } + final Optional quicIdleTimeout = getIdleTimeout(); + if (quicIdleTimeout.isEmpty()) { + // the QUIC connection will never idle timeout, nothing more to do + return; + } + // we start the PING sending timer event only if the QUIC layer idle timeout + // is lesser than the app layer's desired idle time + if (Duration.ofMillis(quicIdleTimeout.get()).compareTo(maxIdle) < 0) { + this.stateLock.lock(); + try { + if (shutdown.get()) { + return; + } + // QUIC connection has a lower idle timeout than the app layer. start a timer + // which checks with the app layer at regular intervals to decide whether to + // send a PING to keep the QUIC connection active. + startPingTimer(); + } finally { + this.stateLock.unlock(); + } + } + } + + private void startPingTimer() { + assert stateLock.isHeldByCurrentThread() : "not holding state lock"; + // we don't expect the timer to be started more than once + assert this.pingEvent == null : "PING timer already started"; + final Optional quicIdleTimeout = getIdleTimeout(); + assert quicIdleTimeout.isPresent() : "QUIC idle timeout is disabled, no need to start PING timer"; + // potential PING generation every 75% of QUIC idle timeout + final long pingFrequencyMillis = (long) (0.75 * quicIdleTimeout.get()); + assert pingFrequencyMillis > 0 : "unexpected ping frequency: " + pingFrequencyMillis; + final QuicTimerQueue timerQueue = connection.endpoint().timer(); + final Deadline deadline = timeLine().instant().plusMillis(pingFrequencyMillis); + // create the timeout event and register with the QuicTimerQueue. + this.pingEvent = new PingEvent(deadline, pingFrequencyMillis); + timerQueue.offer(this.pingEvent); + if (debug.on()) { + debug.log("started periodic PING for connection," + + " ping event: " + this.pingEvent + + " deadline: " + deadline); + } else { + Log.logQuic("{0} started periodic PING for connection," + + " ping event: {1} deadline: {2}", + connection.logTag(), this.pingEvent, deadline); + } + } + + private void stopPingTimer() { + assert stateLock.isHeldByCurrentThread() : "not holding state lock"; + if (this.pingEvent == null) { + return; + } + final QuicEndpoint endpoint = this.connection.endpoint(); + assert endpoint != null : "QUIC endpoint is null"; + // disable the ping timer event + disableTimedEvent(endpoint.timer(), this.pingEvent); + this.pingEvent = null; + this.trafficGenerationCheck.set(null); + } + + /** * Attempts to notify the idle connection management that this connection should * be considered "in use". This way the idle connection management doesn't close * this connection during the time the connection is handed out from the pool and any * new stream created on that connection. * - * @return true if the connection has been successfully reserved and is {@link #isOpen()}. false + * @return true if the connection has been successfully reserved. false * otherwise; in which case the connection must not be handed out from the pool. */ boolean tryReserveForUse() { @@ -221,7 +294,7 @@ final class IdleTimeoutManager { } // if the connection is nearing idle timeout due to lack of traffic then // don't use it - final long lastPktActivity = lastPacketActivityAt; + final long lastPktActivity = lastPacketActivityNanos; final long currentNanos = System.nanoTime(); final long inactivityMs = MILLISECONDS.convert((currentNanos - lastPktActivity), NANOSECONDS); @@ -232,7 +305,7 @@ final class IdleTimeoutManager { return false; } // express interest in using the connection - this.lastUsageReservationAt = System.nanoTime(); + this.lastUsageReservationNanos = System.nanoTime(); return true; } finally { this.idleTerminationLock.unlock(); @@ -256,8 +329,9 @@ final class IdleTimeoutManager { return val == NO_IDLE_TIMEOUT ? Optional.empty() : Optional.of(val); } - void keepAlive() { - lastPacketActivityAt = System.nanoTime(); // TODO: timeline().instant()? + // consider the connection as active as of this moment + void markActive() { + lastPacketActivityNanos = System.nanoTime(); // TODO: timeline().instant()? } void shutdown() { @@ -270,6 +344,7 @@ final class IdleTimeoutManager { // unregister the timeout events from the QuicTimerQueue stopIdleTerminationTimer(); stopStreamDataBlockedTimer(); + stopPingTimer(); } finally { this.stateLock.unlock(); } @@ -318,6 +393,15 @@ final class IdleTimeoutManager { return this.connection.endpoint().timeSource(); } + private static void disableTimedEvent(final QuicTimerQueue timer, final TimedEvent te) { + // disable the event (refreshDeadline() of TimedEvent will return Deadline.MAX) + final Deadline nextDeadline = te.nextDeadline; + if (!nextDeadline.equals(Deadline.MAX)) { + te.nextDeadline = Deadline.MAX; + timer.reschedule(te, Deadline.MIN); + } + } + // called when the connection has been idle past its idle timeout duration private void idleTimedOut() { if (shutdown.get()) { @@ -354,35 +438,51 @@ final class IdleTimeoutManager { } private long computeInactivityMillis() { + assert idleTerminationLock.isHeldByCurrentThread() : "not holding idle termination lock"; final long currentNanos = System.nanoTime(); - final long lastActiveNanos = Math.max(lastPacketActivityAt, lastUsageReservationAt); + final long lastActiveNanos = Math.max(lastPacketActivityNanos, lastUsageReservationNanos); return MILLISECONDS.convert((currentNanos - lastActiveNanos), NANOSECONDS); } - final class IdleTimeoutEvent implements QuicTimedEvent { - private final long eventId; - private volatile Deadline deadline; - private volatile Deadline nextDeadline; + sealed abstract class TimedEvent implements QuicTimedEvent { + protected final long eventId; + protected volatile Deadline deadline; + protected volatile Deadline nextDeadline; - private IdleTimeoutEvent(final Deadline deadline) { + private TimedEvent(final Deadline deadline) { assert deadline != null : "timeout deadline is null"; this.deadline = this.nextDeadline = deadline; this.eventId = QuicTimerQueue.newEventId(); } @Override - public Deadline deadline() { + public final Deadline deadline() { return this.deadline; } @Override - public Deadline refreshDeadline() { + public final Deadline refreshDeadline() { if (shutdown.get()) { return this.deadline = this.nextDeadline = Deadline.MAX; } return this.deadline = this.nextDeadline; } + @Override + public final long eventId() { + return this.eventId; + } + + @Override + public abstract Deadline handle(); + } + + final class IdleTimeoutEvent extends TimedEvent { + + private IdleTimeoutEvent(final Deadline deadline) { + super(deadline); + } + @Override public Deadline handle() { if (shutdown.get()) { @@ -442,41 +542,18 @@ final class IdleTimeoutManager { } } - @Override - public long eventId() { - return this.eventId; - } - @Override public String toString() { return "QuicIdleTimeoutEvent-" + this.eventId; } } - final class StreamDataBlockedEvent implements QuicTimedEvent { - private final long eventId; + final class StreamDataBlockedEvent extends TimedEvent { private final long timeoutMillis; - private volatile Deadline deadline; - private volatile Deadline nextDeadline; private StreamDataBlockedEvent(final Deadline deadline, final long timeoutMillis) { - assert deadline != null : "timeout deadline is null"; - this.deadline = this.nextDeadline = deadline; + super(deadline); this.timeoutMillis = timeoutMillis; - this.eventId = QuicTimerQueue.newEventId(); - } - - @Override - public Deadline deadline() { - return this.deadline; - } - - @Override - public Deadline refreshDeadline() { - if (shutdown.get()) { - return this.deadline = this.nextDeadline = Deadline.MAX; - } - return this.deadline = this.nextDeadline; } @Override @@ -517,14 +594,95 @@ final class IdleTimeoutManager { } } - @Override - public long eventId() { - return this.eventId; - } - @Override public String toString() { return "StreamDataBlockedEvent-" + this.eventId; } } + + + final class PingEvent extends TimedEvent { + private final long pingFrequencyNanos; + private final long idleTimeoutNanos; + + private PingEvent(final Deadline deadline, final long pingFrequencyMillis) { + super(deadline); + this.pingFrequencyNanos = MILLISECONDS.toNanos(pingFrequencyMillis); + if (this.pingFrequencyNanos <= 0) { + throw new IllegalArgumentException("ping frequency is too small: " + + pingFrequencyMillis + " milliseconds"); + } + this.idleTimeoutNanos = MILLISECONDS.toNanos(getIdleTimeout().get()); + } + + @Override + public Deadline handle() { + if (shutdown.get()) { + // timeout manager is shutdown, nothing more to do + return this.nextDeadline = Deadline.MAX; + } + if (!shouldInitiateAppLayerCheck()) { + // reschedule for next round + this.nextDeadline = timeLine().instant().plusNanos(this.pingFrequencyNanos); + return this.nextDeadline; + } + // check with the app layer if traffic generation is required + final Supplier check = trafficGenerationCheck.get(); + if (check == null) { + // generateTrafficCheck can be null if the timeout manager was shutdown + // when this event handling was in progress. don't send a PING frame + // in that case. + assert shutdown.get() : "trafficGenerationCheck is absent"; + return this.nextDeadline = Deadline.MAX; + } + if (check.get()) { + // app layer OKed sending a PING + connection.requestSendPing(); + if (debug.on()) { + debug.log("enqueued a PING frame"); + } else { + Log.logQuic("{0} enqueued a PING frame", connection.logTag()); + } + } else { + // app layer told us not to send a PING. + // we skip the PING generation only for the current round, no need + // to disable future PING checks + if (debug.on()) { + debug.log("skipping PING generation"); + } else { + Log.logQuic("{0} skipping PING generation", connection.logTag()); + } + } + this.nextDeadline = timeLine().instant().plusNanos(this.pingFrequencyNanos); + return this.nextDeadline; + } + + @Override + public String toString() { + return "PingEvent-" + this.eventId; + } + + // returns true if the app layer traffic generation check needs to be invoked, + // false otherwise. + private boolean shouldInitiateAppLayerCheck() { + final long lastPktAt = lastPacketActivityNanos; + final long now = System.nanoTime(); + if ((now - lastPktAt) >= this.pingFrequencyNanos) { + // no traffic during the ping interval, initiate a app layer check + // to see if explicit traffic needs to be generated + return true; + } + // check if the connection will potentially idle terminate before the next + // ping check is scheduled, if yes, then initiate a app layer traffic + // generation check now + final long idleTerminationAt = lastPktAt + this.idleTimeoutNanos; + final long nextPingCheck = now + this.pingFrequencyNanos; + if (idleTerminationAt - nextPingCheck <= 0) { + return true; + } + // connection appears to be receiving traffic, no need to initiate app layer + // traffic generation check + return false; + } + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java index d90ad1b217e..240f90852bc 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java @@ -1987,7 +1987,7 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece case NONE -> throw new InternalError("Unrecognized packet type"); } // packet has been processed successfully - connection isn't idle (RFC-9000, section 10.1) - this.terminator.keepAlive(); + this.terminator.markActive(); if (packetSpace != null) { packetSpace.packetReceived( packetType, @@ -2819,7 +2819,7 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece // RFC-9000, section 10.1: An endpoint also restarts its idle timer when sending // an ack-eliciting packet ... if (packet.isAckEliciting()) { - this.terminator.keepAlive(); + this.terminator.markActive(); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java index 9269b12bf64..ac885c1950e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java @@ -45,8 +45,7 @@ sealed interface QuicTimedEvent permits PacketSpaceManager.PacketTransmissionTask, QuicTimerQueue.Marker, QuicEndpoint.ClosedConnection, - IdleTimeoutManager.IdleTimeoutEvent, - IdleTimeoutManager.StreamDataBlockedEvent, + IdleTimeoutManager.TimedEvent, QuicConnectionImpl.MaxInitialTimer { /** diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java index 890c1a63a35..db519dc7557 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java @@ -577,7 +577,6 @@ public class QuicPacketEncoder { final byte[] encodedPacketNumber; final List frames; final int payloadSize; - private int tagSize; OutgoingHandshakePacket(QuicConnectionId sourceId, QuicConnectionId destinationId, @@ -590,7 +589,6 @@ public class QuicPacketEncoder { this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); this.payloadSize = frames.stream().mapToInt(QuicFrame::size).reduce(0, Math::addExact); - this.tagSize = tagSize; this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize); this.size = computeSize(length); } @@ -676,7 +674,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; OutgoingZeroRttPacket(QuicConnectionId sourceId, @@ -689,7 +686,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size) .reduce(0, Math::addExact); this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize); @@ -778,7 +774,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; OutgoingOneRttPacket(QuicConnectionId destinationId, @@ -789,7 +784,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size) .reduce(0, Math::addExact); this.size = computeSize(payloadSize, encodedPacketNumber.length, tagSize); @@ -853,7 +847,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; private record InitialPacketVariableComponents(int length, byte[] token, QuicConnectionId sourceId, @@ -873,7 +866,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream() .mapToInt(QuicFrame::size) .reduce(0, Math::addExact); diff --git a/src/java.sql/share/classes/java/sql/Array.java b/src/java.sql/share/classes/java/sql/Array.java index 1c42d3e5b79..8fe84f4f930 100644 --- a/src/java.sql/share/classes/java/sql/Array.java +++ b/src/java.sql/share/classes/java/sql/Array.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,13 +61,19 @@ package java.sql; * If the connection's type map or a type map supplied to a method has no entry * for the base type, the elements are mapped according to the standard mapping. *

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

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

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

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

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

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

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

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

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

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

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

+ * If the {@code Clob} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the Clob's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Connection.java b/src/java.sql/share/classes/java/sql/Connection.java index 19f283f5762..946459adf7b 100644 --- a/src/java.sql/share/classes/java/sql/Connection.java +++ b/src/java.sql/share/classes/java/sql/Connection.java @@ -43,8 +43,8 @@ import java.util.Map; * should use the appropriate {@code Connection} method such as * {@code setAutoCommit} or {@code setTransactionIsolation}. * Applications should not invoke SQL commands directly to change the connection's - * configuration when there is a JDBC method available. By default a {@code Connection} object is in - * auto-commit mode, which means that it automatically commits changes + * configuration when there is a JDBC method available. By default, a {@code Connection} + * object is in auto-commit mode, which means that it automatically commits changes * after executing each statement. If auto-commit mode has been * disabled, the method {@code commit} must be called explicitly in * order to commit changes; otherwise, database changes will not be saved. @@ -77,7 +77,7 @@ import java.util.Map; * con.setTypeMap(map); *

* - * @see DriverManager#getConnection + * @see DriverManager#getConnection(String) * @see Statement * @see ResultSet * @see DatabaseMetaData @@ -1505,7 +1505,7 @@ public interface Connection extends Wrapper, AutoCloseable { * * @throws SQLException if an error occurs * @since 9 - * @see endRequest + * @see #endRequest() * @see javax.sql.PooledConnection */ default void beginRequest() throws SQLException { @@ -1548,7 +1548,7 @@ public interface Connection extends Wrapper, AutoCloseable { * * @throws SQLException if an error occurs * @since 9 - * @see beginRequest + * @see #beginRequest() * @see javax.sql.PooledConnection */ default void endRequest() throws SQLException { @@ -1676,5 +1676,311 @@ public interface Connection extends Wrapper, AutoCloseable { default void setShardingKey(ShardingKey shardingKey) throws SQLException { throw new SQLFeatureNotSupportedException("setShardingKey not implemented"); } + // JDBC 4.5 + /** + * Returns a {@code String} enclosed in single quotes. Any occurrence of a + * single quote within the string will be replaced by two single quotes. + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
ValueResult
Hello 'Hello'
G'Day 'G''Day'
'G''Day''''G''''Day'''
I'''M 'I''''''M'
+ *
+ * @implSpec + * The default implementation creates the literal as: + * {@code "'" + val.replace("'", "''") + "'"}. + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param val a character string + * @return A string enclosed by single quotes with every single quote + * converted to two single quotes + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default String enquoteLiteral(String val) throws SQLException { + return SQLUtils.enquoteLiteral(val); + } + + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

What the JDBC 4.3 API Includes

- * The JDBC 4.3 API includes both + *

What the JDBC 4.5 API Includes

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

Versions

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

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

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

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

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

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

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

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

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

Custom Mapping of UDTs

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

Package Specification

* * * *

Related Documentation

@@ -326,7 +351,6 @@ *
  • * Lesson:JDBC Basics(The Java Tutorials > JDBC Database Access) * - *
  • JDBC API Tutorial and Reference, Third Edition” * * @since 1.1 */ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index f933ef36565..22ee2393a02 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -413,7 +413,18 @@ public class JavacTrees extends DocTrees { } if (ref.qualifierExpression == null) { - tsym = env.enclClass.sym; + // Resolve target for unqualified reference based on declaring element + tsym = switch (path.getLeaf().getKind()) { + case PACKAGE -> env.toplevel.packge; + case MODULE -> env.toplevel.modle; + case COMPILATION_UNIT -> + // Treat unqualified reference in legacy package.html as package reference. + // Unqualified references in doc-files only need to work locally, so null is fine. + path.getCompilationUnit().getSourceFile().isNameCompatible("package", JavaFileObject.Kind.HTML) + ? env.toplevel.packge + : null; + default -> env.enclClass.sym; // Class or class member reference + }; memberName = (Name) ref.memberName; } else { // Check if qualifierExpression is a type or package, using the methods javac provides. @@ -470,8 +481,11 @@ public class JavacTrees extends DocTrees { } } - if (memberName == null) + if (memberName == null) { return tsym; + } else if (tsym == null || tsym.getKind() == ElementKind.PACKAGE || tsym.getKind() == ElementKind.MODULE) { + return null; // Non-null member name in non-class context + } if (tsym.type.isPrimitive()) { return null; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index eea766f57c1..07f2a742bcb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -2810,7 +2810,12 @@ public class Resolve { Symbol resolveQualifiedMethod(DiagnosticPosition pos, Env env, Symbol location, Type site, Name name, List argtypes, List typeargtypes) { - return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); + try { + return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); + } catch (CompletionFailure cf) { + chk.completionError(pos, cf); + return methodNotFound.access(name, site.tsym); + } } private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext, DiagnosticPosition pos, Env env, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java index 4d679403ee7..af7d79d4195 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java @@ -226,6 +226,8 @@ public final class SourceLauncher { Object instance = null; + // Similar to sun.launcher.LauncherHelper#checkAndLoadMain, including + // checks performed in LauncherHelper#validateMainMethod if (!isStatic) { if (Modifier.isAbstract(mainClass.getModifiers())) { throw new Fault(Errors.CantInstantiate(mainClassName)); @@ -238,6 +240,10 @@ public final class SourceLauncher { throw new Fault(Errors.CantFindConstructor(mainClassName)); } + if (Modifier.isPrivate(constructor.getModifiers())) { + throw new Fault(Errors.CantUsePrivateConstructor(mainClassName)); + } + try { constructor.setAccessible(true); instance = constructor.newInstance(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties index 122e5dca80d..36d50afad0f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties @@ -124,6 +124,12 @@ launcher.err.cant.access.main.method=\ launcher.err.cant.find.constructor=\ can''t find no argument constructor in class: {0} +# 0: string +launcher.err.cant.use.private.constructor=\ + no non-private zero argument constructor found in class {0}\n\ + remove private from existing constructor or define as:\n\ +\ public {0}() + # 0: string launcher.err.cant.access.constructor=\ can''t access no argument constructor in class: {0} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java index 10f6881d010..efbb613994d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,9 @@ package sun.jvm.hotspot.debugger.bsd; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.stream.IntStream; import sun.jvm.hotspot.debugger.Address; import sun.jvm.hotspot.debugger.DebuggerBase; @@ -75,10 +77,11 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { // CDebugger support private BsdCDebugger cdbg; - // threadList and loadObjectList are filled by attach0 method - private List threadList; + // loadObjectList is filled by attach0 method private List loadObjectList; + private List javaThreadList; + // called by native method lookupByAddress0 private ClosestSymbol createClosestSymbol(String name, long offset) { return new ClosestSymbol(name, offset); @@ -241,10 +244,21 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { } } + private void fillJavaThreadList() { + // TODO: thread list on macOS is now supported for corefile only. + if (!isCore && isDarwin) { + javaThreadList = Collections.emptyList(); + } else { + Threads threads = VM.getVM().getThreads(); + javaThreadList = IntStream.range(0, threads.getNumberOfThreads()) + .mapToObj(threads::getJavaThreadAt) + .toList(); + } + } + /** From the Debugger interface via JVMDebugger */ public synchronized void attach(int processID) throws DebuggerException { checkAttached(); - threadList = new ArrayList<>(); loadObjectList = new ArrayList<>(); class AttachTask implements WorkerThreadTask { int pid; @@ -264,7 +278,6 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** From the Debugger interface via JVMDebugger */ public synchronized void attach(String execName, String coreName) { checkAttached(); - threadList = new ArrayList<>(); loadObjectList = new ArrayList<>(); attach0(execName, coreName); attached = true; @@ -278,7 +291,7 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { return false; } - threadList = null; + javaThreadList = null; loadObjectList = null; if (isCore) { @@ -492,7 +505,12 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** From the BsdCDebugger interface */ public List getThreadList() { requireAttach(); - return threadList; + if (javaThreadList == null) { + fillJavaThreadList(); + } + return javaThreadList.stream() + .map(JavaThread::getThreadProxy) + .toList(); } /** From the BsdCDebugger interface */ @@ -561,21 +579,19 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** this functions used for core file reading and called from native attach0, it returns an array of long integers as [thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for - all java threads recorded in Threads. Also adds the ThreadProxy to threadList */ + all java threads recorded in Threads. */ public long[] getJavaThreadsInfo() { requireAttach(); - Threads threads = VM.getVM().getThreads(); - int len = threads.getNumberOfThreads(); - long[] result = new long[len * 3]; // triple + if (javaThreadList == null) { + fillJavaThreadList(); + } + long[] result = new long[javaThreadList.size() * 3]; // triple long beg, end; int i = 0; - for (int k = 0; k < threads.getNumberOfThreads(); k++) { - JavaThread t = threads.getJavaThreadAt(k); + for (var t : javaThreadList) { end = t.getStackBaseValue(); beg = end - t.getStackSize(); - BsdThread bsdt = (BsdThread)t.getThreadProxy(); - long uid = bsdt.getUniqueThreadId(); - if (threadList != null) threadList.add(bsdt); + long uid = ((BsdThread)t.getThreadProxy()).getUniqueThreadId(); result[i] = uid; result[i + 1] = beg; result[i + 2] = end; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java index 47f41fe1383..bc366ef02b5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.jvm.hotspot.debugger.cdbg; import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.utilities.*; /** Models a "C" programming language frame on the stack -- really just an arbitrary frame with hooks to access C and C++ debug @@ -37,7 +39,7 @@ public interface CFrame { public CFrame sender(ThreadProxy th); /** Find sender frame with given FP and PC */ - public default CFrame sender(ThreadProxy th, Address fp, Address pc) { + public default CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { return sender(th); } @@ -70,4 +72,9 @@ public interface CFrame { /** Visit all local variables in this frame if debug information is available. Automatically descends into compound types and arrays. */ public void iterateLocals(ObjectVisitor v); + + /** Get Frame instance assosiated with this CFrame. */ + public default Frame toFrame() { + throw new UnsupportedPlatformException(); + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java index 894e31949b2..e3543503216 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -81,9 +81,11 @@ class LinuxCDebugger implements CDebugger { String cpu = dbg.getCPU(); if (cpu.equals("amd64")) { AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(AMD64ThreadContext.RSP); + if (sp == null) return null; Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP); if (pc == null) return null; - return LinuxAMD64CFrame.getTopFrame(dbg, pc, context); + return LinuxAMD64CFrame.getTopFrame(dbg, sp, pc, context); } else if (cpu.equals("ppc64")) { PPC64ThreadContext context = (PPC64ThreadContext) thread.getContext(); Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP); @@ -93,18 +95,22 @@ class LinuxCDebugger implements CDebugger { return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize()); } else if (cpu.equals("aarch64")) { AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP); + if (sp == null) return null; Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP); if (fp == null) return null; Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC); if (pc == null) return null; - return new LinuxAARCH64CFrame(dbg, fp, pc); + return new LinuxAARCH64CFrame(dbg, sp, fp, pc); } else if (cpu.equals("riscv64")) { RISCV64ThreadContext context = (RISCV64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(RISCV64ThreadContext.SP); + if (sp == null) return null; Address fp = context.getRegisterAsAddress(RISCV64ThreadContext.FP); if (fp == null) return null; Address pc = context.getRegisterAsAddress(RISCV64ThreadContext.PC); if (pc == null) return null; - return new LinuxRISCV64CFrame(dbg, fp, pc); + return new LinuxRISCV64CFrame(dbg, sp, fp, pc); } else { // Runtime exception thrown by LinuxThreadContextFactory if unknown cpu ThreadContext context = thread.getContext(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java index 93edb43eb82..5f76e6308e9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,10 +30,14 @@ import sun.jvm.hotspot.debugger.aarch64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.aarch64.*; public final class LinuxAARCH64CFrame extends BasicCFrame { - public LinuxAARCH64CFrame(LinuxDebugger dbg, Address fp, Address pc) { + public LinuxAARCH64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) { super(dbg.getCDebugger()); + this.sp = sp; this.fp = fp; this.pc = pc; this.dbg = dbg; @@ -55,11 +59,11 @@ public final class LinuxAARCH64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy thread) { - return sender(thread, null, null); + return sender(thread, null, null, null); } @Override - public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) { + public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) { // Check fp // Skip if both nextFP and nextPC are given - do not need to load from fp. if (nextFP == null && nextPC == null) { @@ -86,7 +90,32 @@ public final class LinuxAARCH64CFrame extends BasicCFrame { if (nextPC == null) { return null; } - return new LinuxAARCH64CFrame(dbg, nextFP, nextPC); + + if (nextSP == null) { + CodeCache cc = VM.getVM().getCodeCache(); + CodeBlob currentBlob = cc.findBlobUnsafe(pc()); + + // This case is different from HotSpot. See JDK-8371194 for details. + if (currentBlob != null && (currentBlob.isContinuationStub() || currentBlob.isNativeMethod())) { + // Use FP since it should always be valid for these cases. + // TODO: These should be walked as Frames not CFrames. + nextSP = fp.addOffsetTo(2 * ADDRESS_SIZE); + } else { + CodeBlob codeBlob = cc.findBlobUnsafe(nextPC); + boolean useCodeBlob = codeBlob != null && codeBlob.getFrameSize() > 0; + nextSP = useCodeBlob ? nextFP.addOffsetTo((2 * ADDRESS_SIZE) - codeBlob.getFrameSize()) : nextFP; + } + } + if (nextSP == null) { + return null; + } + + return new LinuxAARCH64CFrame(dbg, nextSP, nextFP, nextPC); + } + + @Override + public Frame toFrame() { + return new AARCH64Frame(sp, fp, pc); } // package/class internals only diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 9fa0fc20e99..612203634f3 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -29,10 +29,12 @@ import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.amd64.*; public final class LinuxAMD64CFrame extends BasicCFrame { - public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rip, ThreadContext context) { + public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rsp, Address rip, ThreadContext context) { Address libptr = dbg.findLibPtrByAddress(rip); Address cfa = context.getRegisterAsAddress(AMD64ThreadContext.RBP); DwarfParser dwarf = null; @@ -45,7 +47,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // DWARF processing should succeed when the frame is native // but it might fail if Common Information Entry (CIE) has language // personality routine and/or Language Specific Data Area (LSDA). - return new LinuxAMD64CFrame(dbg, cfa, rip, dwarf, true); + return new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf, true); } cfa = context.getRegisterAsAddress(dwarf.getCFARegister()) @@ -53,19 +55,20 @@ public final class LinuxAMD64CFrame extends BasicCFrame { } return (cfa == null) ? null - : new LinuxAMD64CFrame(dbg, cfa, rip, dwarf); + : new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf) { - this(dbg, cfa, rip, dwarf, false); + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf) { + this(dbg, rsp, cfa, rip, dwarf, false); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) { - this(dbg, cfa, rip, dwarf, finalFrame, false); + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) { + this(dbg, rsp, cfa, rip, dwarf, finalFrame, false); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) { + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) { super(dbg.getCDebugger()); + this.rsp = rsp; this.cfa = cfa; this.rip = rip; this.dbg = dbg; @@ -107,7 +110,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame { (!isNative || (isNative && nextCFA.greaterThan(cfa))); } - private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP) { + private Address getNextRSP() { + // next RSP should be previous slot of return address. + var bp = dwarf == null ? cfa.addOffsetTo(ADDRESS_SIZE) // top of BP points callser BP + : cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA()); + return bp.addOffsetTo(ADDRESS_SIZE); + } + + private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP, Address senderPC) { Address nextCFA; boolean isNative = false; @@ -115,13 +125,17 @@ public final class LinuxAMD64CFrame extends BasicCFrame { senderFP = cfa.getAddressAt(0); // RBP by default } - if (nextDwarf == null) { // Next frame is Java + if (VM.getVM().getCodeCache().contains(senderPC)) { // Next frame is Java nextCFA = (dwarf == null) ? senderFP // Current frame is Java : cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA()); // Current frame is Native } else { // Next frame is Native - if (dwarf == null) { // Current frame is Java + if (VM.getVM().getCodeCache().contains(pc())) { // Current frame is Java nextCFA = senderFP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()); } else { // Current frame is Native + if (nextDwarf == null) { // maybe runtime entrypoint (_start()) + throw new DebuggerException("nextDwarf is null even though native call"); + } + isNative = true; int nextCFAReg = nextDwarf.getCFARegister(); if (nextCFAReg == AMD64ThreadContext.RBP) { @@ -130,10 +144,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame { Address nextRBP = rbp.getAddressAt(0); nextCFA = nextRBP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()); } else if (nextCFAReg == AMD64ThreadContext.RSP) { - // next RSP should be previous slot of return address. - Address nextRSP = cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA()) - .addOffsetTo(ADDRESS_SIZE); - nextCFA = nextRSP.addOffsetTo(nextDwarf.getCFAOffset()); + nextCFA = getNextRSP().addOffsetTo(nextDwarf.getCFAOffset()); } else { throw new DebuggerException("Unsupported CFA register: " + nextCFAReg); } @@ -153,17 +164,22 @@ public final class LinuxAMD64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy th) { - return sender(th, null, null); + return sender(th, null, null, null); } @Override - public CFrame sender(ThreadProxy th, Address fp, Address pc) { + public CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { if (finalFrame) { return null; } ThreadContext context = th.getContext(); + Address nextRSP = sp != null ? sp : getNextRSP(); + if (nextRSP == null) { + return null; + } + Address nextPC = pc != null ? pc : getNextPC(dwarf != null); if (nextPC == null) { return null; @@ -183,13 +199,16 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // DWARF processing should succeed when the frame is native // but it might fail if Common Information Entry (CIE) has language // personality routine and/or Language Specific Data Area (LSDA). - return new LinuxAMD64CFrame(dbg, null, nextPC, nextDwarf, true); + return null; } } - Address nextCFA = getNextCFA(nextDwarf, context, fp); - return nextCFA == null ? null - : new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf, false, fallback); + try { + Address nextCFA = getNextCFA(nextDwarf, context, fp, nextPC); + return new LinuxAMD64CFrame(dbg, nextRSP, nextCFA, nextPC, nextDwarf, false, fallback); + } catch (DebuggerException _) { + return null; + } } private DwarfParser createDwarfParser(Address pc) throws DebuggerException { @@ -210,8 +229,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame { return nextDwarf; } + @Override + public Frame toFrame() { + return new AMD64Frame(rsp, cfa, rip); + } + // package/class internals only private static final int ADDRESS_SIZE = 8; + private Address rsp; private Address rip; private Address cfa; private LinuxDebugger dbg; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java index 424766fb1b4..c3724f14c2a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ import sun.jvm.hotspot.debugger.ppc64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.ppc64.*; public final class LinuxPPC64CFrame extends BasicCFrame { // package/class internals only @@ -71,6 +73,12 @@ public final class LinuxPPC64CFrame extends BasicCFrame { return new LinuxPPC64CFrame(dbg, nextSP, nextPC, address_size); } + @Override + public Frame toFrame() { + // 2nd arg (raw_fp) would be derived from sp in c'tor of PPC64Frame. + return new PPC64Frame(sp, null, pc); + } + public static int PPC64_STACK_BIAS = 0; private static int address_size; private Address pc; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java index 76f45891c47..65563be59ec 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -31,13 +31,17 @@ import sun.jvm.hotspot.debugger.riscv64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.riscv64.*; public final class LinuxRISCV64CFrame extends BasicCFrame { private static final int C_FRAME_LINK_OFFSET = -2; private static final int C_FRAME_RETURN_ADDR_OFFSET = -1; + private static final int C_FRAME_SENDER_SP_OFFSET = 0; - public LinuxRISCV64CFrame(LinuxDebugger dbg, Address fp, Address pc) { + public LinuxRISCV64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) { super(dbg.getCDebugger()); + this.sp = sp; this.fp = fp; this.pc = pc; this.dbg = dbg; @@ -59,11 +63,11 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy thread) { - return sender(thread, null, null); + return sender(thread, null, null, null); } @Override - public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) { + public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) { // Check fp // Skip if both nextFP and nextPC are given - do not need to load from fp. if (nextFP == null && nextPC == null) { @@ -77,6 +81,13 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { } } + if (nextSP == null) { + nextSP = fp.getAddressAt(C_FRAME_SENDER_SP_OFFSET * ADDRESS_SIZE); + } + if (nextSP == null) { + return null; + } + if (nextFP == null) { nextFP = fp.getAddressAt(C_FRAME_LINK_OFFSET * ADDRESS_SIZE); } @@ -91,7 +102,12 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { return null; } - return new LinuxRISCV64CFrame(dbg, nextFP, nextPC); + return new LinuxRISCV64CFrame(dbg, nextSP, nextFP, nextPC); + } + + @Override + public Frame toFrame() { + return new RISCV64Frame(sp, fp, pc); } // package/class internals only diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java index 5ae4cb703b3..7233d508cbc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java @@ -272,9 +272,7 @@ public class AARCH64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } @@ -389,7 +387,11 @@ public class AARCH64Frame extends Frame { if (Assert.ASSERTS_ENABLED) { Assert.that(cb.getFrameSize() > 0, "must have non-zero frame size"); } - Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize()); + + // TODO: senderSP should consider not only PreserveFramePointer but also _sp_is_trusted. + Address senderSP = !VM.getVM().getCommandLineBooleanFlag("PreserveFramePointer") + ? getUnextendedSP().addOffsetTo(cb.getFrameSize()) + : getSenderSP(); // The return_address is always the word on the stack Address senderPC = stripPAC(senderSP.getAddressAt(-1 * VM.getVM().getAddressSize())); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java index 360f62a253d..fa9d50160e1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java @@ -272,9 +272,7 @@ public class AMD64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java index 9865fbbe0f2..29d2954efdc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java @@ -70,7 +70,6 @@ public class PStack extends Tool { if (cdbg != null) { ConcurrentLocksPrinter concLocksPrinter = null; // compute and cache java Vframes. - initJFrameCache(); if (concurrentLocks) { concLocksPrinter = new ConcurrentLocksPrinter(out); } @@ -96,6 +95,7 @@ public class PStack extends Tool { return; } final boolean cdbgCanDemangle = cdbg.canDemangle(); + Map proxyToThread = createProxyToThread();; String fillerForAddress = " ".repeat(2 + 2 * (int) VM.getVM().getAddressSize()) + "\t"; for (Iterator itr = l.iterator() ; itr.hasNext();) { ThreadProxy th = itr.next(); @@ -109,6 +109,7 @@ public class PStack extends Tool { jthread.printThreadInfoOn(out); } while (f != null) { + Address senderSP = null; Address senderFP = null; Address senderPC = null; ClosestSymbol sym = f.closestSymbolToPC(); @@ -131,7 +132,7 @@ public class PStack extends Tool { // check interpreter frame Interpreter interp = VM.getVM().getInterpreter(); if (interp.contains(pc)) { - nameInfo = getJavaNames(th, f.localVariableBase()); + nameInfo = getJavaNames(jthread, f); // print codelet name if we can't determine method if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) { out.print(" "); @@ -156,7 +157,7 @@ public class PStack extends Tool { } out.println(" (Native method)"); } else { - nameInfo = getJavaNames(th, f.localVariableBase()); + nameInfo = getJavaNames(jthread, f); // just print compiled code, if can't determine method if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) { out.println(""); @@ -164,6 +165,12 @@ public class PStack extends Tool { } } else { out.println("<" + cb.getName() + ">"); + if (cb.getFrameSize() > 0) { + Frame senderFrame = f.toFrame().sender(jthread.newRegisterMap(true)); + senderSP = senderFrame.getSP(); + senderFP = senderFrame.getFP(); + senderPC = senderFrame.getPC(); + } } } else { printUnknown(out); @@ -180,11 +187,12 @@ public class PStack extends Tool { out.println(nameInfo.names()[i]); } } + senderSP = nameInfo.senderSP(); senderFP = nameInfo.senderFP(); senderPC = nameInfo.senderPC(); } } - f = f.sender(th, senderFP, senderPC); + f = f.sender(th, senderSP, senderFP, senderPC); } } catch (Exception exp) { exp.printStackTrace(); @@ -212,95 +220,74 @@ public class PStack extends Tool { } // -- Internals only below this point - private Map jframeCache; - private Map proxyToThread; private PrintStream out; private boolean verbose; private boolean concurrentLocks; - private void initJFrameCache() { - // cache frames for subsequent reference - jframeCache = new HashMap<>(); - proxyToThread = new HashMap<>(); + private Map createProxyToThread() { + Map proxyToThread = new HashMap<>(); Threads threads = VM.getVM().getThreads(); for (int i = 0; i < threads.getNumberOfThreads(); i++) { - JavaThread cur = threads.getJavaThreadAt(i); - List tmp = new ArrayList<>(10); - try { - for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { - tmp.add(vf); - } - } catch (Exception exp) { - // may be we may get frames for other threads, continue - // after printing stack trace. - exp.printStackTrace(); - } - JavaVFrame[] jvframes = tmp.toArray(new JavaVFrame[0]); - jframeCache.put(cur.getThreadProxy(), jvframes); - proxyToThread.put(cur.getThreadProxy(), cur); + JavaThread jthread = threads.getJavaThreadAt(i); + proxyToThread.put(jthread.getThreadProxy(), jthread); } + return proxyToThread; } private void printUnknown(PrintStream out) { out.println("\t????????"); } - private static record JavaNameInfo(String[] names, Address senderFP, Address senderPC) {}; - - private JavaNameInfo getJavaNames(ThreadProxy th, Address fp) { - if (fp == null) { - return null; - } - JavaVFrame[] jvframes = jframeCache.get(th); - if (jvframes == null) return null; // not a java thread + private static record JavaNameInfo(String[] names, Address senderSP, Address senderFP, Address senderPC) {}; + private JavaNameInfo getJavaNames(JavaThread jthread, CFrame f) { List names = new ArrayList<>(10); - JavaVFrame bottomJVFrame = null; - for (int fCount = 0; fCount < jvframes.length; fCount++) { - JavaVFrame vf = jvframes[fCount]; - Frame f = vf.getFrame(); - if (fp.equals(f.getFP())) { - bottomJVFrame = vf; - StringBuilder sb = new StringBuilder(); - Method method = vf.getMethod(); - // a special char to identify java frames in output - sb.append("* "); - sb.append(method.externalNameAndSignature()); - sb.append(" bci:").append(vf.getBCI()); - int lineNumber = method.getLineNumberFromBCI(vf.getBCI()); - if (lineNumber != -1) { - sb.append(" line:").append(lineNumber); - } - - if (verbose) { - sb.append(" Method*:").append(method.getAddress()); - } - - if (vf.isCompiledFrame()) { - sb.append(" (Compiled frame"); - if (vf.isDeoptimized()) { - sb.append(" [deoptimized]"); - } - } else if (vf.isInterpretedFrame()) { - sb.append(" (Interpreted frame"); - } - if (vf.mayBeImpreciseDbg()) { - sb.append("; information may be imprecise"); - } - sb.append(")"); - names.add(sb.toString()); - } - } - + Address senderSP = null; Address senderFP = null; Address senderPC = null; - if (bottomJVFrame != null) { - Frame senderFrame = bottomJVFrame.getFrame().sender((RegisterMap)bottomJVFrame.getRegisterMap().clone()); + VFrame vf = VFrame.newVFrame(f.toFrame(), jthread.newRegisterMap(true), jthread, true, true); + while (vf != null && vf.isJavaFrame()) { + StringBuilder sb = new StringBuilder(); + Method method = ((JavaVFrame)vf).getMethod(); + // a special char to identify java frames in output + sb.append("* "); + sb.append(method.externalNameAndSignature()); + sb.append(" bci:").append(((JavaVFrame)vf).getBCI()); + int lineNumber = method.getLineNumberFromBCI(((JavaVFrame)vf).getBCI()); + if (lineNumber != -1) { + sb.append(" line:").append(lineNumber); + } + + if (verbose) { + sb.append(" Method*:").append(method.getAddress()); + } + + if (vf.isCompiledFrame()) { + sb.append(" (Compiled frame"); + if (vf.isDeoptimized()) { + sb.append(" [deoptimized]"); + } + } else if (vf.isInterpretedFrame()) { + sb.append(" (Interpreted frame"); + } + if (vf.mayBeImpreciseDbg()) { + sb.append("; information may be imprecise"); + } + sb.append(")"); + names.add(sb.toString()); + + // Keep registers in sender Frame + Frame senderFrame = vf.getFrame() + .sender((RegisterMap)vf.getRegisterMap().clone()); + senderSP = senderFrame.getSP(); senderFP = senderFrame.getFP(); senderPC = senderFrame.getPC(); + + // Get sender VFrame for next stack walking + vf = vf.sender(true); } - return new JavaNameInfo(names.toArray(new String[0]), senderFP, senderPC); + return new JavaNameInfo(names.toArray(new String[0]), senderSP, senderFP, senderPC); } public void setVerbose(boolean verbose) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 6896b86279f..1f2c4d97dd3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -908,12 +908,13 @@ public abstract class HtmlDocletWriter { * @param refMemName the name of the member being referenced. This should * be null or empty string if no member is being referenced. * @param label the label for the external link. + * @param title the title for the link * @param style optional style for the link. * @param code true if the label should be code font. * @return the link */ public Content getCrossClassLink(TypeElement classElement, String refMemName, - Content label, HtmlStyle style, boolean code) { + Content label, String title, HtmlStyle style, boolean code) { if (classElement != null) { String className = utils.getSimpleName(classElement); PackageElement packageElement = utils.containingPackage(classElement); @@ -931,9 +932,7 @@ public abstract class HtmlDocletWriter { DocLink link = configuration.extern.getExternalLink(packageElement, pathToRoot, className + ".html", refMemName); return links.createLink(link, - (label == null) || label.isEmpty() ? defaultLabel : label, style, - resources.getText("doclet.Href_Class_Or_Interface_Title", - getLocalizedPackageName(packageElement)), true); + (label == null) || label.isEmpty() ? defaultLabel : label, style, title, true); } } return null; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 4dbbd5e172a..cb8b3dbfd40 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -305,7 +305,7 @@ public class HtmlLinkFactory { } else { Content crossLink = m_writer.getCrossClassLink( typeElement, linkInfo.getFragment(), - label, linkInfo.getStyle(), true); + label, linkInfo.getTitle(), linkInfo.getStyle(), true); if (crossLink != null) { link.add(crossLink); addSuperscript(link, flags, null, typeElement, previewTarget, restrictedTarget); @@ -361,7 +361,7 @@ public class HtmlLinkFactory { if (fileName != null) { return m_writer.links.createLink(fileName.fragment(id.name()), label); } else if (typeElement != null) { - return (m_writer.getCrossClassLink(typeElement, id.name(), label, null, false)); + return (m_writer.getCrossClassLink(typeElement, id.name(), label, null, null, false)); } else { return label; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java index 0af29135654..285ab260e0e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -197,7 +197,7 @@ public class Links { if (style != null) { l.setStyle(style); } - if (title != null && title.length() != 0) { + if (title != null && !title.isEmpty()) { l.put(HtmlAttr.TITLE, title); } if (isExternal) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index df3c2fc3a53..4366295477b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title=annotation interface in {0} doclet.Href_Enum_Title=enum in {0} doclet.Href_Enum_Class_Title=enum class in {0} doclet.Href_Type_Param_Title=type parameter in {0} -doclet.Href_Class_Or_Interface_Title=class or interface in {0} doclet.Summary=Summary: doclet.Detail=Detail: doclet.Module_Sub_Nav=Module: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties index 2669aa9bdc0..4cbb4b97774 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title=Annotationsschnittstelle in {0} doclet.Href_Enum_Title=Enum in {0} doclet.Href_Enum_Class_Title=Enum-Klasse in {0} doclet.Href_Type_Param_Title=Typparameter in {0} -doclet.Href_Class_Or_Interface_Title=Klasse oder Schnittstelle in {0} doclet.Summary=Übersicht: doclet.Detail=Details: doclet.Module_Sub_Nav=Modul: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties index 1694dc980bc..2151b3f4a2e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title={0}内の注釈インタフェース doclet.Href_Enum_Title={0}内の列挙型 doclet.Href_Enum_Class_Title={0}の列挙クラス doclet.Href_Type_Param_Title={0}内の型パラメータ -doclet.Href_Class_Or_Interface_Title={0}内のクラスまたはインタフェース doclet.Summary=概要: doclet.Detail=詳細: doclet.Module_Sub_Nav=モジュール: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties index 8881171351e..66620d158bb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title={0} 中的批注接口 doclet.Href_Enum_Title={0}中的枚举 doclet.Href_Enum_Class_Title={0} 中的枚举类 doclet.Href_Type_Param_Title={0}中的类型参数 -doclet.Href_Class_Or_Interface_Title={0}中的类或接口 doclet.Summary=概要: doclet.Detail=详细资料: doclet.Module_Sub_Nav=模块: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java index 914f70ced47..62b003afd96 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java @@ -50,6 +50,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -159,6 +160,10 @@ public class LinkTaglet extends BaseTaglet { Optional.of(refSignature)); } refFragment = refFragment.substring(1); + if (ref == null && refSignature.startsWith("##")) { + // Unqualified local anchor link in doc-file + return htmlWriter.links.createLink(HtmlId.of(refFragment), labelContent); + } } if (refClass == null) { ModuleElement refModule = ch.getReferencedModule(ref); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index 3669c800a8e..43405c3ebb0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -1004,12 +1004,15 @@ public class Checker extends DocTreePathScanner { @Override @DefinedBy(Api.COMPILER_TREE) public Void visitReference(ReferenceTree tree, Void ignore) { - Element e = env.trees.getElement(getCurrentPath()); - if (e == null) { - reportBadReference(tree); - } else if ((inLink || inSee) - && e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED) { - reportBadReference(tree); + // Exclude same-file anchor links from reference checks + if (!tree.getSignature().startsWith("##")) { + Element e = env.trees.getElement(getCurrentPath()); + if (e == null) { + reportBadReference(tree); + } else if ((inLink || inSee) + && e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED) { + reportBadReference(tree); + } } return super.visitReference(tree, ignore); } diff --git a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp index b5e9c6de6a0..55c03f188cc 100644 --- a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp +++ b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp @@ -140,17 +140,6 @@ class TestGenCollectorPolicy { ASSERT_EQ(param, NewSize); } }; - - class SetMaxNewSizeCmd : public BinaryExecutor { - public: - SetMaxNewSizeCmd(size_t param1, size_t param2) : BinaryExecutor(param1, param2) { } - void execute() { - size_t heap_alignment = GCArguments::compute_heap_alignment(); - size_t new_size_value = align_up(MaxHeapSize, heap_alignment) - - param1 + param2; - FLAG_SET_CMDLINE(MaxNewSize, new_size_value); - } - }; }; diff --git a/test/hotspot/gtest/runtime/test_atomic.cpp b/test/hotspot/gtest/runtime/test_atomic.cpp index dc492e523d1..b37c14d41a7 100644 --- a/test/hotspot/gtest/runtime/test_atomic.cpp +++ b/test/hotspot/gtest/runtime/test_atomic.cpp @@ -101,10 +101,10 @@ TEST_VM(AtomicIntegerTest, arith_uint64) { } template -struct AtomicIntegerXchgTestSupport { +struct AtomicByteAndIntegerXchgTestSupport { Atomic _test_value; - AtomicIntegerXchgTestSupport() : _test_value{} {} + AtomicByteAndIntegerXchgTestSupport() : _test_value{} {} void test() { T zero = 0; @@ -116,13 +116,18 @@ struct AtomicIntegerXchgTestSupport { } }; +TEST_VM(AtomicIntegerTest, xchg_char) { + using Support = AtomicByteAndIntegerXchgTestSupport; + Support().test(); +} + TEST_VM(AtomicIntegerTest, xchg_int32) { - using Support = AtomicIntegerXchgTestSupport; + using Support = AtomicByteAndIntegerXchgTestSupport; Support().test(); } TEST_VM(AtomicIntegerTest, xchg_int64) { - using Support = AtomicIntegerXchgTestSupport; + using Support = AtomicByteAndIntegerXchgTestSupport; Support().test(); } @@ -153,18 +158,16 @@ TEST_VM(AtomicIntegerTest, cmpxchg_int32) { TEST_VM(AtomicIntegerTest, cmpxchg_int64) { // Check if 64-bit atomics are available on the machine. - if (!VM_Version::supports_cx8()) return; - using Support = AtomicIntegerCmpxchgTestSupport; Support().test(); } -struct AtomicCmpxchg1ByteStressSupport { +struct AtomicXchgAndCmpxchg1ByteStressSupport { char _default_val; int _base; Atomic _array[7+32+7]; - AtomicCmpxchg1ByteStressSupport() : _default_val(0x7a), _base(7) {} + AtomicXchgAndCmpxchg1ByteStressSupport() : _default_val(0x7a), _base(7) {} void validate(char val, char val2, int index) { for (int i = 0; i < 7; i++) { @@ -182,35 +185,60 @@ struct AtomicCmpxchg1ByteStressSupport { } } + template void test_index(int index) { + Exchange exchange; char one = 1; - _array[index].compare_exchange(_default_val, one); + exchange(_array[index], _default_val, one); validate(_default_val, one, index); - _array[index].compare_exchange(one, _default_val); + exchange(_array[index], one, _default_val); validate(_default_val, _default_val, index); } + template void test() { for (size_t i = 0; i < ARRAY_SIZE(_array); ++i) { _array[i].store_relaxed(_default_val); } for (int i = _base; i < (_base+32); i++) { - test_index(i); + test_index(i); } } + void test_exchange() { + struct StressWithExchange { + void operator()(Atomic& atomic, char compare_value, char new_value) { + EXPECT_EQ(compare_value, atomic.exchange(new_value)); + } + }; + test(); + } + + void test_compare_exchange() { + struct StressWithCompareExchange { + void operator()(Atomic& atomic, char compare_value, char new_value) { + EXPECT_EQ(compare_value, atomic.compare_exchange(compare_value, new_value)); + } + }; + test(); + } }; -TEST_VM(AtomicCmpxchg1Byte, stress) { - AtomicCmpxchg1ByteStressSupport support; - support.test(); +TEST_VM(AtomicByteTest, stress_xchg) { + AtomicXchgAndCmpxchg1ByteStressSupport support; + support.test_exchange(); +} + +TEST_VM(AtomicByteTest, stress_cmpxchg) { + AtomicXchgAndCmpxchg1ByteStressSupport support; + support.test_compare_exchange(); } template -struct AtomicEnumTestSupport { +struct AtomicTestSupport { Atomic _test_value; - AtomicEnumTestSupport() : _test_value{} {} + AtomicTestSupport() : _test_value{} {} void test_store_load(T value) { EXPECT_NE(value, _test_value.load_relaxed()); @@ -233,6 +261,13 @@ struct AtomicEnumTestSupport { EXPECT_EQ(value1, _test_value.exchange(value2)); EXPECT_EQ(value2, _test_value.load_relaxed()); } + + template + static void test() { + AtomicTestSupport().test_store_load(B); + AtomicTestSupport().test_cmpxchg(B, C); + AtomicTestSupport().test_xchg(B, C); + } }; namespace AtomicEnumTestUnscoped { // Scope the enumerators. @@ -241,11 +276,7 @@ namespace AtomicEnumTestUnscoped { // Scope the enumerators. TEST_VM(AtomicEnumTest, unscoped_enum) { using namespace AtomicEnumTestUnscoped; - using Support = AtomicEnumTestSupport; - - Support().test_store_load(B); - Support().test_cmpxchg(B, C); - Support().test_xchg(B, C); + AtomicTestSupport::test(); } enum class AtomicEnumTestScoped { A, B, C }; @@ -253,11 +284,35 @@ enum class AtomicEnumTestScoped { A, B, C }; TEST_VM(AtomicEnumTest, scoped_enum) { const AtomicEnumTestScoped B = AtomicEnumTestScoped::B; const AtomicEnumTestScoped C = AtomicEnumTestScoped::C; - using Support = AtomicEnumTestSupport; + AtomicTestSupport::test(); +} - Support().test_store_load(B); - Support().test_cmpxchg(B, C); - Support().test_xchg(B, C); +enum class AtomicEnumTestScoped64Bit : uint64_t { A, B, C }; + +TEST_VM(AtomicEnumTest, scoped_enum_64_bit) { + const AtomicEnumTestScoped64Bit B = AtomicEnumTestScoped64Bit::B; + const AtomicEnumTestScoped64Bit C = AtomicEnumTestScoped64Bit::C; + AtomicTestSupport::test(); +} + +enum class AtomicEnumTestScoped8Bit : uint8_t { A, B, C }; + +TEST_VM(AtomicEnumTest, scoped_enum_8_bit) { + const AtomicEnumTestScoped8Bit B = AtomicEnumTestScoped8Bit::B; + const AtomicEnumTestScoped8Bit C = AtomicEnumTestScoped8Bit::C; + AtomicTestSupport::test(); +} + +TEST_VM(AtomicByteTest, char_test) { + const char B = 0xB; + const char C = 0xC; + AtomicTestSupport::test(); +} + +TEST_VM(AtomicByteTest, bool_test) { + const bool B = true; + const bool C = false; + AtomicTestSupport::test(); } template @@ -514,40 +569,6 @@ struct PrimitiveConversions::Translate static Value recover(Decayed x) { return Value(x); } }; -// Test whether Atomic has exchange(). -// Note: This is intentionally a different implementation from what is used -// by the atomic translated type to decide whether to provide exchange(). -// The intent is to make related testing non-tautological. -// The two implementations must agree; it's a bug if they don't. -template -class AtomicTypeHasExchange { - template, - typename = decltype(declval().exchange(declval()))> - static char* test(int); - - template static char test(...); - - using test_type = decltype(test(0)); - -public: - static constexpr bool value = std::is_pointer_v; -}; - -// Unit tests for AtomicTypeHasExchange. -static_assert(AtomicTypeHasExchange::value); -static_assert(AtomicTypeHasExchange::value); -static_assert(AtomicTypeHasExchange::value); -static_assert(AtomicTypeHasExchange::value); -static_assert(!AtomicTypeHasExchange::value); - -// Verify translated byte type *doesn't* have exchange. -static_assert(!AtomicTypeHasExchange::value); - -// Verify that explicit instantiation doesn't attempt to reference the -// non-existent exchange of the atomic decayed type. -template class AtomicImpl::Atomic; - template static void test_atomic_translated_type() { // This works even if T is not default constructible. @@ -562,10 +583,8 @@ static void test_atomic_translated_type() { Translated::recover(10)))); EXPECT_EQ(10, Translated::decay(_test_value.load_relaxed())); - if constexpr (AtomicTypeHasExchange::value) { - EXPECT_EQ(10, Translated::decay(_test_value.exchange(Translated::recover(20)))); - EXPECT_EQ(20, Translated::decay(_test_value.load_relaxed())); - } + EXPECT_EQ(10, Translated::decay(_test_value.exchange(Translated::recover(20)))); + EXPECT_EQ(20, Translated::decay(_test_value.load_relaxed())); } TEST_VM(AtomicTranslatedTypeTest, int_test) { diff --git a/test/hotspot/gtest/runtime/test_atomicAccess.cpp b/test/hotspot/gtest/runtime/test_atomicAccess.cpp index 6e05f429970..a489be71b19 100644 --- a/test/hotspot/gtest/runtime/test_atomicAccess.cpp +++ b/test/hotspot/gtest/runtime/test_atomicAccess.cpp @@ -100,6 +100,11 @@ struct AtomicAccessXchgTestSupport { } }; +TEST_VM(AtomicAccessXchgTest, int8) { + using Support = AtomicAccessXchgTestSupport; + Support().test(); +} + TEST_VM(AtomicAccessXchgTest, int32) { using Support = AtomicAccessXchgTestSupport; Support().test(); @@ -136,9 +141,6 @@ TEST_VM(AtomicAccessCmpxchgTest, int32) { } TEST_VM(AtomicAccessCmpxchgTest, int64) { - // Check if 64-bit atomics are available on the machine. - if (!VM_Version::supports_cx8()) return; - using Support = AtomicAccessCmpxchgTestSupport; Support().test(); } diff --git a/test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp b/test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp new file mode 100644 index 00000000000..0177acda49f --- /dev/null +++ b/test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifdef LINUX + +#include "procMapsParser.hpp" +#include "unittest.hpp" + +#include + +TEST(ProcSmapsParserTest, ParseMappings) { + const char* smaps_content = + "7f5a00000000-7f5a00001000 r--p 00000000 00:00 0 [anon]\n" + "Size: 4 kB\n" + "KernelPageSize: 4 kB\n" + "MMUPageSize: 4 kB\n" + "Rss: 0 kB\n" + "Pss: 0 kB\n" + "Shared_Clean: 0 kB\n" + "Shared_Dirty: 0 kB\n" + "Private_Clean: 0 kB\n" + "Private_Dirty: 0 kB\n" + "Referenced: 0 kB\n" + "Anonymous: 0 kB\n" + "LazyFree: 0 kB\n" + "AnonHugePages: 0 kB\n" + "ShmemPmdMapped: 0 kB\n" + "FilePmdMapped: 0 kB\n" + "Shared_Hugetlb: 0 kB\n" + "Private_Hugetlb: 0 kB\n" + "Swap: 0 kB\n" + "SwapPss: 0 kB\n" + "Locked: 0 kB\n" + "THPeligible: 0\n" + "VmFlags: rd mr mw me ac \n" + "7f5a00001000-7f5a00002000 rw-p 00000000 00:00 0 [anon]\n" + "Size: 4 kB\n" + "KernelPageSize: 4 kB\n" + "MMUPageSize: 4 kB\n" + "Rss: 4 kB\n" + "Pss: 4 kB\n" + "Shared_Clean: 0 kB\n" + "Shared_Dirty: 0 kB\n" + "Private_Clean: 0 kB\n" + "Private_Dirty: 4 kB\n" + "Referenced: 4 kB\n" + "Anonymous: 4 kB\n" + "LazyFree: 0 kB\n" + "AnonHugePages: 0 kB\n" + "ShmemPmdMapped: 0 kB\n" + "FilePmdMapped: 0 kB\n" + "Shared_Hugetlb: 0 kB\n" + "Private_Hugetlb: 0 kB\n" + "Swap: 0 kB\n" + "SwapPss: 0 kB\n" + "Locked: 0 kB\n" + "THPeligible: 0\n" + "VmFlags: rd wr mr mw me ac \n"; + + FILE* f = fmemopen((void*)smaps_content, strlen(smaps_content), "r"); + ASSERT_TRUE(f != nullptr); + + ProcSmapsParser parser(f); + ProcSmapsInfo info; + + // First mapping + ASSERT_TRUE(parser.parse_next(info)); + EXPECT_EQ((uintptr_t)info.from, 0x7f5a00000000ULL); + EXPECT_EQ((uintptr_t)info.to, 0x7f5a00001000ULL); + EXPECT_STREQ(info.prot, "r--p"); + EXPECT_TRUE(info.rd); + EXPECT_FALSE(info.wr); + + // Second mapping + ASSERT_TRUE(parser.parse_next(info)); + EXPECT_EQ((uintptr_t)info.from, 0x7f5a00001000ULL); + EXPECT_EQ((uintptr_t)info.to, 0x7f5a00002000ULL); + EXPECT_STREQ(info.prot, "rw-p"); + EXPECT_TRUE(info.rd); + EXPECT_TRUE(info.wr); + + // End of file + ASSERT_FALSE(parser.parse_next(info)); + + fclose(f); +} + +#endif // LINUX diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 934ef03a987..a51e8aef5ee 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -79,6 +79,8 @@ compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java 8369150 generic-all +compiler/arguments/TestCodeEntryAlignment.java 8372703 generic-x64 + ############################################################################# # :hotspot_gc @@ -141,7 +143,6 @@ serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64 serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64 serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64 -serviceability/sa/TestJhsdbJstackMixedWithXComp.java 8371194 linux-x64 serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 @@ -167,6 +168,7 @@ vmTestbase/metaspace/gc/firstGC_99m/TestDescription.java 8208250 generic-all vmTestbase/metaspace/gc/firstGC_default/TestDescription.java 8208250 generic-all vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 8073470 linux-all +vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t006/TestDescription.java 8372206 generic-all vmTestbase/nsk/jvmti/InterruptThread/intrpthrd003/TestDescription.java 8288911 macosx-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all diff --git a/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java b/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java new file mode 100644 index 00000000000..5c4dcc76a76 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 IBM Corporation. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8371464 + * @summary C2: assert(no_dead_loop) failed: dead loop detected + * @run main/othervm -Xcomp -XX:CompileOnly=TestDeadLoopAtMergeMem::test TestDeadLoopAtMergeMem + * @run main TestDeadLoopAtMergeMem + */ + +public class TestDeadLoopAtMergeMem { + static final int N = 400; + static long instanceCount; + boolean bFld; + float fArrFld[]; + static int iArrFld[] = new int[N]; + long vMeth_check_sum; + + public static void main(String[] strArr) { + TestDeadLoopAtMergeMem r = new TestDeadLoopAtMergeMem(); + for (int i = 0; i < 1000; i++) { + r.test((short) 0, instanceCount); + } + } + + void test(short s, long l) { + int i11 = 6, i12, i13 = 6, i14 = 2; + byte byArr2[] = new byte[N]; + init(byArr2, (byte) 4); + helper(66.118169, i11); + for (i12 = 3; i12 < 23; i12++) { + if (bFld) { + instanceCount = 5; + } else if (bFld) { + fArrFld[i12] = s; + do { + try { + i11 = i13 / i12 % i12; + } catch (ArithmeticException a_e) { + } + } while (i14 < 8); + } + } + for (int i15 : iArrFld) { + try { + i11 = 1 / i15; + } catch (ArithmeticException a_e) { + } + } + vMeth_check_sum += i11; + } + + void helper(double d, int i) { + int i1[] = new int[N]; + } + + public static void init(byte[] a, byte seed) { + for (int j = 0; j < a.length; j++) { + a[j] = (byte) ((j % 2 == 0) ? seed + j : seed - j); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 1abb8e7dd4a..0b90ecfdb19 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -523,13 +523,13 @@ public class IRNode { public static final String CHECKCAST_ARRAY = PREFIX + "CHECKCAST_ARRAY" + POSTFIX; static { - String regex = "(((?i:cmp|CLFI|CLR).*precise \\[.*:|.*(?i:mov|mv|or).*precise \\[.*:.*\\R.*(cmp|CMP|CLR))" + END; + String regex = "(((?i:cmp|CLFI|CLR).*aryklassptr:\\[.*:Constant|.*(?i:mov|mv|or).*aryklassptr:\\[.*:Constant.*\\R.*(cmp|CMP|CLR))" + END; optoOnly(CHECKCAST_ARRAY, regex); } public static final String CHECKCAST_ARRAY_OF = COMPOSITE_PREFIX + "CHECKCAST_ARRAY_OF" + POSTFIX; static { - String regex = "(((?i:cmp|CLFI|CLR).*precise \\[.*" + IS_REPLACED + ":|.*(?i:mov|mv|or).*precise \\[.*" + IS_REPLACED + ":.*\\R.*(cmp|CMP|CLR))" + END; + String regex = "(((?i:cmp|CLFI|CLR).*aryklassptr:\\[.*" + IS_REPLACED + ":.*:Constant|.*(?i:mov|mv|or).*aryklassptr:\\[.*" + IS_REPLACED + ":.*:Constant.*\\R.*(cmp|CMP|CLR))" + END; optoOnly(CHECKCAST_ARRAY_OF, regex); } @@ -3230,10 +3230,9 @@ public class IRNode { // @ matches the start character of the pattern // (\w+: ?)+ tries to match the pattern 'ptrtype:' or 'stable:' with optional trailing whitespaces - // (\w/)* tries to match the pattern 'a/b/` - // (\w$)* tries to match the pattern 'c$d$' + // [\\w/\\$] tries to match the pattern such as 'a/b/', 'a/b', or '/b' but also nested class such as '$c' or '$c$d' // \b asserts that the next character is a word character - private static final String LOAD_STORE_PREFIX = "@(\\w+: ?)+(\\w/)*(\\w$)*\\b"; + private static final String LOAD_STORE_PREFIX = "@(\\w+: ?)+[\\w/\\$]*\\b"; // ( \([^\)]+\))? tries to match the pattern ' (f/g,h/i/j)' // :\w+ tries to match the pattern ':NotNull' // .* tries to match the remaining of the pattern diff --git a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java index fbe69ad0e04..90a8287004f 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java @@ -45,7 +45,8 @@ package compiler.loopopts; * -XX:-TieredCompilation -Xcomp -XX:PerMethodTrapLimit=0 * -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations -XX:-StressDuplicateBackedge * compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit - * @run main/othervm -XX:-StressDuplicateBackedge compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-StressDuplicateBackedge + * compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit */ public class TestVerifyLoopOptimizationsHitsMemLimit { diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java new file mode 100644 index 00000000000..e86d6ec2314 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=all-flags-fixed-stress-seed + * @bug 8371146 + * @summary Test where the pre_init was pinned before the pre-loop but after the + * Auto_Vectorization_Check, and so it should not be used for the auto + * vectorization aliasing check, to avoid a bad (circular) graph. + * @requires vm.gc.Z + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * -XX:+UseZGC + * -XX:+UnlockDiagnosticVMOptions -XX:+StressLoopPeeling -XX:StressSeed=4 + * -XX:LoopUnrollLimit=48 + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=all-flags-no-stress-seed + * @bug 8371146 + * @requires vm.gc.Z + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * -XX:+UseZGC + * -XX:+UnlockDiagnosticVMOptions -XX:+StressLoopPeeling + * -XX:LoopUnrollLimit=48 + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=fewer-flags + * @bug 8371146 + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * -XX:LoopUnrollLimit=48 + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=minimal-flags + * @bug 8371146 + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=vanilla + * @bug 8371146 + * @run main compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +package compiler.loopopts.superword; + +public class TestAliasingCheckPreLimitNotAvailable { + static int sum; + static boolean condition; + static int zero; + static int twoDimensional[][] = new int[20][20]; + + static void test() { + int innerCount = 0; + int conditionCount = 0; + int oneDimensional[] = new int[10]; + for (int i = 2; i > 0; --i) { + for (int j = i; j < 10; j++) { + innerCount += 1; + oneDimensional[1] += innerCount; + oneDimensional[j] += zero; + if (condition) { + conditionCount += 1; + oneDimensional[1] += conditionCount; + sum += oneDimensional[1]; + } + twoDimensional[j] = twoDimensional[j + 1]; + } + } + } + + public static void main(String[] args) { + test(); + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java new file mode 100644 index 00000000000..37dd964048f --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.superword; + +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @bug 8372451 + * @summary Test long reduction chain. Triggered bug with long chain of dead ReductionVector + * vtnodes after optimize_move_non_strict_order_reductions_out_of_loop. + * @library /test/lib / + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=1000 -XX:MaxVectorSize=8 -Xbatch + * -XX:CompileCommand=compileonly,${test.main.class}::test + * ${test.main.class} + * @run main ${test.main.class} + */ + +public class TestLongReductionChain { + static int RANGE = 1024*8; + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + int[] aI = generateI(); + int[] bI = generateI(); + int gold = test(aI, bI); + + for (int i = 0; i < 1000; i++) { + int result = test(aI, bI); + if (result != gold) { + throw new RuntimeException("wrong value"); + } + } + } + + static int[] generateI() { + int[] a = new int[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = RANDOM.nextInt(); + } + return a; + } + + // Test creates a very long reduction chain, especially with -XX:LoopUnrollLimit=1000. + // Limiting the reduction vectors to 2 elements gets us a very long chain -XX:MaxVectorSize=8. + // During VTransform::optimize this means a long chain of nodes needs to be found as dead. + // Before the fix, this took too many rounds, and we hit an assert. + static int test(int[] a, int[] b) { + int s = 0; + for (int i = 0; i < RANGE; i+=8) { + s += a[i+0] * b[i+0]; + s += a[i+1] * b[i+1]; + s += a[i+2] * b[i+2]; + s += a[i+3] * b[i+3]; + + s += a[i+4] & b[i+4]; + s += a[i+5] & b[i+5]; + s += a[i+6] & b[i+6]; + s += a[i+7] & b[i+7]; + } + return s; + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java index a72126ebad5..ab2801179f2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java @@ -162,7 +162,13 @@ public class TestReinterpretAndCast { IRNode.STORE_VECTOR, "> 0", IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least I2F applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeature = {"avx", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", + IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least I2F + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "fphp", "true", "asimdhp", "true"}) public static void test2(int[] a, short[] b) { for (int i = 0; i < SIZE; i++) { int v0 = a[i]; @@ -202,7 +208,14 @@ public class TestReinterpretAndCast { IRNode.STORE_VECTOR, "> 0", IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least F2I applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeature = {"avx", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.VECTOR_CAST_I2L, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least F2I + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "fphp", "true", "asimdhp", "true"}) public static void test3(short[] a, long[] b) { for (int i = 0; i < SIZE; i++) { short v0 = a[i]; diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java index 208dd603615..68331f26766 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java @@ -33,6 +33,7 @@ import java.nio.file.Path; import java.nio.file.Files; import java.util.ArrayList; +import jdk.test.lib.Platform; import jtreg.SkippedException; /* @@ -64,6 +65,9 @@ public class TestMemoryInvisibleParent { if (DockerTestUtils.isRootless()) { throw new SkippedException("Test skipped in rootless mode"); } + if (!Platform.isRoot()) { + throw new SkippedException("Test should be run as root"); + } DockerTestUtils.buildJdkContainerImage(imageName); if ("cgroupv1".equals(metrics.getProvider())) { @@ -84,16 +88,16 @@ public class TestMemoryInvisibleParent { Common.logNewTestCase("Cgroup V1 hidden parent memory limit: " + valueToSet); try { - String cgroupParent = setParentWithLimit(valueToSet); - DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "-version", "-Xlog:os+container=trace"); - opts.appendTestJavaOptions = false; - if (DockerTestUtils.isPodman()) { - // Podman needs to run this test with engine option --cgroup-manager=cgroupfs - opts.addEngineOpts("--cgroup-manager", "cgroupfs"); - } - opts.addDockerOpts("--cgroup-parent=/" + cgroupParent); - Common.run(opts) - .shouldContain("Hierarchical Memory Limit is: " + expectedValue); + String cgroupParent = setParentWithLimit(valueToSet); + DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "-version", "-Xlog:os+container=trace"); + opts.appendTestJavaOptions = false; + if (DockerTestUtils.isPodman()) { + // Podman needs to run this test with engine option --cgroup-manager=cgroupfs + opts.addEngineOpts("--cgroup-manager", "cgroupfs"); + } + opts.addDockerOpts("--cgroup-parent=/" + cgroupParent); + Common.run(opts) + .shouldContain("Hierarchical Memory Limit is: " + expectedValue); } finally { // Reset the parent memory limit to unlimited (-1) setParentWithLimit(UNLIMITED); diff --git a/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java b/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java index af3f77a8a76..a5e144bcd15 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java +++ b/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ public class TestSelectDefaultGC { public static void testDefaultGC(boolean actAsServer) throws Exception { // Start VM without specifying GC - OutputAnalyzer output = GCArguments.executeLimitedTestJava( + OutputAnalyzer output = GCArguments.executeTestJava( "-XX:" + (actAsServer ? "+" : "-") + "AlwaysActAsServerClassMachine", "-XX:" + (actAsServer ? "-" : "+") + "NeverActAsServerClassMachine", "-XX:+PrintFlagsFinal", diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java index a8d5155584b..80962f0ffa6 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java @@ -192,6 +192,17 @@ public class TestRegionSizeArgs { output.shouldHaveExitValue(0); } + // This used to assert that _conservative_max_heap_alignment is not a power-of-2. + { + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", + "-XX:+UseShenandoahGC", + "-Xms100m", + "-Xmx1g", + "-XX:ShenandoahMaxRegionSize=33m", + "-version"); + output.shouldHaveExitValue(0); + } + } private static void testMaxRegionSize() throws Exception { diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java index 0be39d22ebe..26d1f726feb 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,8 +72,8 @@ public class TestCrashOnOutOfMemoryError { # # JRE version: OpenJDK Runtime Environment (9.0) (build 1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00) # Java VM: OpenJDK 64-Bit Server VM (1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00, mixed mode, tiered, compressed oops, serial gc, linux-amd64) - # Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %P" (or dumping to - /home/cheleswer/Desktop/core.6212) + # Core dump will be written. Default location: Determined by the following: + "/usr/share/apport/apport %p %s %c %P" (alternatively, falling back to /home/cheleswer/Desktop/core.6212) # # An error report file with more information is saved as: # /home/cheleswer/Desktop/hs_err_pid6212.log diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java index 043a198331e..a26fc4532df 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java @@ -23,6 +23,7 @@ */ import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import jdk.test.lib.JDKToolLauncher; @@ -32,7 +33,7 @@ import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; /** - * @test + * @test id=xcomp * @bug 8370176 * @requires vm.hasSA * @requires os.family == "linux" @@ -40,6 +41,28 @@ import jdk.test.lib.process.OutputAnalyzer; * @library /test/lib * @run driver TestJhsdbJstackMixedWithXComp */ + +/** + * @test id=xcomp-preserve-frame-pointer + * @bug 8370176 + * @requires vm.hasSA + * @requires os.family == "linux" + * @requires os.arch == "amd64" + * @library /test/lib + * @run driver TestJhsdbJstackMixedWithXComp -XX:+PreserveFramePointer + */ + +/** + * @test id=xcomp-disable-tiered-compilation + * @bug 8370176 + * @requires vm.hasSA + * @requires os.family == "linux" + * @requires os.arch == "amd64" + * @library /test/lib + * @run driver TestJhsdbJstackMixedWithXComp -XX:-TieredCompilation + */ + + public class TestJhsdbJstackMixedWithXComp { private static void runJstack(LingeredApp app) throws Exception { @@ -89,8 +112,12 @@ public class TestJhsdbJstackMixedWithXComp { LingeredApp app = null; try { + List jvmOpts = new ArrayList<>(); + jvmOpts.add("-Xcomp"); + jvmOpts.addAll(Arrays.asList(args)); + app = new LingeredAppWithVirtualThread(); - LingeredApp.startApp(app, "-Xcomp"); + LingeredApp.startApp(app, jvmOpts.toArray(new String[0])); System.out.println("Started LingeredApp with pid " + app.getPid()); runJstack(app); System.out.println("Test Completed"); diff --git a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java index 9119ac45cc3..9e266e67119 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java @@ -25,6 +25,7 @@ * @test TestJmapCore * @summary Test verifies that jhsdb jmap could generate heap dump from core when heap is full * @requires vm.hasSA + * @requires !vm.asan * @library /test/lib * @run driver/timeout=480 TestJmapCore run heap */ diff --git a/test/hotspot/jtreg/serviceability/sa/TestJmapCoreMetaspace.java b/test/hotspot/jtreg/serviceability/sa/TestJmapCoreMetaspace.java index b8e00e53848..6fc04c8de74 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJmapCoreMetaspace.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJmapCoreMetaspace.java @@ -25,6 +25,7 @@ * @test TestJmapCoreMetaspace * @summary Test verifies that jhsdb jmap could generate heap dump from core when metaspace is full * @requires vm.hasSA + * @requires !vm.asan * @library /test/lib * @run driver/timeout=480 TestJmapCore run metaspace */ diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java index 5615cce983a..142a30f34a9 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -255,9 +255,9 @@ public class TestIRMatching { } else { cmp = "cmp"; } - runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 1, cmp, "precise"), - BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 1,cmp, "precise", "MyClass"), - BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 2,cmp, "precise", "ir_framework/tests/MyClass"), + runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 1, cmp, "Constant"), + BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 1,cmp, "Constant", "MyClass"), + BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 2,cmp, "Constant", "ir_framework/tests/MyClass"), GoodFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 3), Platform.isS390x() ? // There is no checkcast_arraycopy stub for C2 on s390 GoodFailOnConstraint.create(CheckCastArray.class, "arrayCopy(java.lang.Object[],java.lang.Class)", 1) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java index 6b33783306f..15bbc9eb964 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java @@ -48,6 +48,9 @@ public class GC extends nsk.share.test.Tests { public GCTestRunner(Test test, String[] args) { super(test, args); + // GC tests often run at the brink of OOME, make sure + // LocalRandom is loaded, initialized, and has enough memory. + LocalRandom.init(); } private GCParams getGCParams(String[] args) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp index 0b43e5ac782..ae2fb040dde 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,7 @@ * questions. */ +#include #include #include @@ -62,6 +63,9 @@ static volatile int currentAgentStatus = NSK_STATUS_PASSED; void nsk_jvmti_setFailStatus() { currentAgentStatus = NSK_STATUS_FAILED; + printf("Test failed by setFailStatus(). See log."); + fflush(stdout); + exit(97); } int nsk_jvmti_isFailStatus() { diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 9452b3a1b9f..9904bd88626 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -586,7 +586,6 @@ java/net/MulticastSocket/Test.java 7145658,8308807 # jdk_nio -java/nio/channels/Channels/SocketChannelStreams.java 8317838 aix-ppc64 java/nio/channels/AsyncCloseAndInterrupt.java 8368290 macosx-26.0.1 java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8308807,8144003 aix-ppc64,macosx-all diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java new file mode 100644 index 00000000000..133e68b344f --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2025, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8371864 + * @run main/othervm/timeout=600 TestGCMSplitBound + * @requires (os.simpleArch == "x64" & (vm.cpu.features ~= ".*avx2.*" | + * vm.cpu.features ~= ".*avx512.*")) + * @summary Test GaloisCounterMode.implGCMCrypt0 AVX512/AVX2 intrinsics. + */ + +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.time.Duration; +import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class TestGCMSplitBound { + + static final SecureRandom SECURE_RANDOM = newDefaultSecureRandom(); + + private static SecureRandom newDefaultSecureRandom() { + SecureRandom retval = new SecureRandom(); + retval.nextLong(); // force seeding + return retval; + } + + private static byte[] randBytes(int size) { + byte[] rand = new byte[size]; + SECURE_RANDOM.nextBytes(rand); + return rand; + } + + private static final int IV_SIZE_IN_BYTES = 12; + private static final int TAG_SIZE_IN_BYTES = 16; + + private Cipher getCipher(final byte[] key, final byte[] aad, + final byte[] nonce, int mode) + throws Exception { + SecretKey keySpec = new SecretKeySpec(key, "AES"); + AlgorithmParameterSpec params = + new GCMParameterSpec(8 * TAG_SIZE_IN_BYTES, nonce, 0, nonce.length); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(mode, keySpec, params); + if (aad != null && aad.length != 0) { + cipher.updateAAD(aad); + } + return cipher; + } + + private byte[] gcmEncrypt(final byte[] key, final byte[] plaintext, + final byte[] aad) + throws Exception { + byte[] nonce = randBytes(IV_SIZE_IN_BYTES); + Cipher cipher = getCipher(key, aad, nonce, Cipher.ENCRYPT_MODE); + int outputSize = cipher.getOutputSize(plaintext.length); + int len = IV_SIZE_IN_BYTES + outputSize; + byte[] output = new byte[len]; + System.arraycopy(nonce, 0, output, 0, IV_SIZE_IN_BYTES); + cipher.doFinal(plaintext, 0, plaintext.length, output, + IV_SIZE_IN_BYTES); + return output; + } + + private byte[] gcmDecrypt(final byte[] key, final byte[] ciphertext, + final byte[] aad) + throws Exception { + byte[] nonce = new byte[IV_SIZE_IN_BYTES]; + System.arraycopy(ciphertext, 0, nonce, 0, IV_SIZE_IN_BYTES); + Cipher cipher = getCipher(key, aad, nonce, Cipher.DECRYPT_MODE); + return cipher.doFinal(ciphertext, IV_SIZE_IN_BYTES, + ciphertext.length - IV_SIZE_IN_BYTES); + } + + // x86-64 parallel intrinsic data size + private static final int PARALLEL_LEN = 512; + // max data size for x86-64 intrinsic + private static final int SPLIT_LEN = 1048576; // 1MB + + private void encryptAndDecrypt(byte[] key, byte[] aad, byte[] message, + int messageSize) + throws Exception { + byte[] ciphertext = gcmEncrypt(key, message, aad); + byte[] decrypted = gcmDecrypt(key, ciphertext, aad); + if (ciphertext == null) { + throw new RuntimeException("ciphertext is null"); + } + if (Arrays.compare(decrypted, 0, messageSize, + message, 0, messageSize) != 0) { + throw new RuntimeException( + "Decrypted message is different from the original message"); + } + } + + private void run() throws Exception { + byte[] aad = randBytes(20); + byte[] key = randBytes(16); + // Force JIT. + for (int i = 0; i < 100000; i++) { + byte[] message = randBytes(PARALLEL_LEN); + encryptAndDecrypt(key, aad, message, PARALLEL_LEN); + } + for (int messageSize = SPLIT_LEN - 300; messageSize <= SPLIT_LEN + 300; + messageSize++) { + byte[] message = randBytes(messageSize); + try { + encryptAndDecrypt(key, aad, message, messageSize); + } catch (Exception e) { + throw new RuntimeException("Failed for messageSize " + + Integer.toHexString(messageSize), e); + } + } + } + + public static void main(String[] args) throws Exception { + TestGCMSplitBound test = new TestGCMSplitBound(); + for (int i = 0; i < 3; i++) { + test.run(); + } + } +} diff --git a/test/jdk/java/foreign/TestMemoryAlignment.java b/test/jdk/java/foreign/TestMemoryAlignment.java index 44d28a07b05..a73635c8f08 100644 --- a/test/jdk/java/foreign/TestMemoryAlignment.java +++ b/test/jdk/java/foreign/TestMemoryAlignment.java @@ -60,8 +60,14 @@ public class TestMemoryAlignment { assertEquals(aligned.byteAlignment(), align); //unreasonable alignment here, to make sure access throws VarHandle vh = aligned.varHandle(); try (Arena arena = Arena.ofConfined()) { - MemorySegment segment = arena.allocate(aligned);; + MemorySegment segment = arena.allocate(aligned); vh.set(segment, 0L, -42); + + // Allocate another segment and fill it with data to + // check that the first segment is not overwritten + MemorySegment nextSegment = arena.allocate(aligned); + vh.set(nextSegment, 0L, 0xffffff); + int val = (int)vh.get(segment, 0L); assertEquals(val, -42); } diff --git a/test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java b/test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java new file mode 100644 index 00000000000..80f4e324627 --- /dev/null +++ b/test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.util.Optional; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test + * @bug 8372787 + * @summary Test the behaviour of ModuleReader when using --patch-module + * @comment patch the java.base module with a test specific resource + * @compile/module=java.base java/lang/PatchedFoo.java + * @run junit/othervm ${test.main.class} + */ +class PatchedModuleReaderTest { + + private static ModuleReference patchedModuleRef; + + @BeforeAll + static void beforeAll() { + patchedModuleRef = ModuleFinder.ofSystem() + .find("java.base") + .orElseThrow(); + } + + /* + * Verifies that the resource that was patched into a module + * is found by the ModuleReader. + */ + @Test + void testResourceFound() throws Exception { + try (ModuleReader reader = patchedModuleRef.open()) { + String resourceName = "java/lang/PatchedFoo.class"; + Optional res = reader.find(resourceName); + assertTrue(res.isPresent(), resourceName + " is missing in " + + patchedModuleRef.descriptor().name() + " module"); + URI uri = res.get(); + assertEquals("file", uri.getScheme(), + "unexpected scheme in resource URI " + uri); + assertTrue(uri.getPath().endsWith(resourceName), + "unexpected path component " + uri.getPath() + + " in resource URI " + uri); + + } + } + + /* + * Verifies the ModuleReader against a resource which isn't + * expected to be part of the patched module. + */ + @Test + void testResourceNotFound() throws Exception { + try (ModuleReader reader = patchedModuleRef.open()) { + String nonExistentResource = "foo/bar/NonExistent.class"; + Optional res = reader.find(nonExistentResource); + assertTrue(res.isEmpty(), "unexpected resource " + nonExistentResource + + " in " + patchedModuleRef.descriptor().name() + " module"); + } + } + + /* + * This test opens a ModuleReader for a patched module, accumulates + * the Stream of resources from that ModuleReader and then closes that + * ModuleReader. It then verifies that the closed ModuleReader + * throws the specified IOException whenever it is used for subsequent + * operations on the Stream of resources. + */ + @Test + void testIOExceptionAfterClose() throws Exception { + ModuleReader reader; + Stream resources; + try (var _ = reader = patchedModuleRef.open()) { + // hold on to the available resources, to test them after the + // ModuleReader is closed + resources = reader.list(); + } // close the ModuleReader + + // verify IOException is thrown by the closed ModuleReader + + assertThrows(IOException.class, () -> reader.list(), + "ModuleReader.list()"); + + resources.forEach(rn -> { + assertThrows(IOException.class, () -> reader.read(rn), + "ModuleReader.read(String)"); + assertThrows(IOException.class, () -> reader.open(rn), + "ModuleReader.open(String)"); + assertThrows(IOException.class, () -> reader.find(rn), + "ModuleReader.find(String)"); + }); + + // repeat the test for a non-existent resource + String nonExistentResource = "foo/bar/NonExistent.class"; + assertThrows(IOException.class, () -> reader.read(nonExistentResource), + "ModuleReader.read(String)"); + assertThrows(IOException.class, () -> reader.open(nonExistentResource), + "ModuleReader.open(String)"); + assertThrows(IOException.class, () -> reader.find(nonExistentResource), + "ModuleReader.find(String)"); + } +} diff --git a/test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java b/test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java new file mode 100644 index 00000000000..814757134d6 --- /dev/null +++ b/test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.lang; + +public class PatchedFoo { +} diff --git a/test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java b/test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java new file mode 100644 index 00000000000..05a2a8e84de --- /dev/null +++ b/test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8372258 + * @summary Test if a copy of the internal state is provided + * @run junit ProtectInnerStateOfTypeVariableImplTest + */ + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.TypeVariable; + +import static org.junit.jupiter.api.Assertions.*; + +final class ProtectInnerStateOfTypeVariableImplTest { + + static final class Foo { + public Foo() { + } + + X x() { + return null; + } + } + + @Test + void testMethod() throws NoSuchMethodException { + Method method = Foo.class.getDeclaredMethod("x"); + TypeVariable tv = method.getTypeParameters()[0]; + + Method gd = tv.getGenericDeclaration(); + Method gd2 = tv.getGenericDeclaration(); + assertNotSame(gd, gd2); + } + + @Test + void testConstructor() throws NoSuchMethodException { + Constructor ctor = Foo.class.getConstructor(); + TypeVariable> tv = ctor.getTypeParameters()[0]; + + Constructor gd = tv.getGenericDeclaration(); + Constructor gd2 = tv.getGenericDeclaration(); + assertNotSame(gd, gd2); + } + +} diff --git a/test/jdk/java/net/httpclient/PlainConnectionLockTest.java b/test/jdk/java/net/httpclient/PlainConnectionLockTest.java new file mode 100644 index 00000000000..3205f87111a --- /dev/null +++ b/test/jdk/java/net/httpclient/PlainConnectionLockTest.java @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLContext; + +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsServer; +import jdk.httpclient.test.lib.common.HttpServerAdapters; +import jdk.httpclient.test.lib.common.TestServerConfigurator; +import jdk.test.lib.net.SimpleSSLContext; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.Version.HTTP_1_1; + +/* + * @test id=default + * @bug 8372198 + * @requires os.family != "windows" + * @summary Attempt to check that no deadlock occurs when + * connections are closed by the ConnectionPool. + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.test.lib.net.SimpleSSLContext + * jdk.httpclient.test.lib.common.HttpServerAdapters + * @run junit/othervm + * -Djdk.httpclient.HttpClient.log=errors + * -Djdk.httpclient.connectionPoolSize=1 + * ${test.main.class} + */ +/* + * @test id=windows + * @bug 8372198 + * @requires os.family == "windows" + * @summary Attempt to check that no deadlock occurs when + * connections are closed by the ConnectionPool. + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.test.lib.net.SimpleSSLContext + * jdk.httpclient.test.lib.common.HttpServerAdapters + * @comment A special jtreg id for windows allows for experimentation + * with different configuration - for instance, specifying + * -Djdk.internal.httpclient.tcp.selector.useVirtualThreads= + * on the run command line, or specifying a different request count + * with -DrequestCount=. + * On windows, it seems important to set the backlog for the HTTP/1.1 + * server to at least the number of concurrent request. This is done + * in the beforeTest() method. + * If the test fails waiting for avalaible permits, due to system limitations, + * even with the backlog correctly configure, adding a margin to the backlog + * or reducing the requestCount could be envisaged. + * @run junit/othervm + * -Djdk.httpclient.HttpClient.log=errors + * -Djdk.httpclient.connectionPoolSize=1 + * ${test.main.class} + */ + +// -Djava.security.debug=all +class PlainConnectionLockTest implements HttpServerAdapters { + + private SSLContext sslContext; + private HttpTestServer http1Server; + private HttpTestServer https1Server; + private String http1URI; + private String https1URI; + private ExecutorService serverExecutor; + private Semaphore responseSemaphore; + private Semaphore requestSemaphore; + private boolean successfulCompletion; + private static final int MANY = Integer.getInteger("requestCount", 100); + + static { + HttpServerAdapters.enableServerLogging(); + } + + private boolean blockResponse(Semaphore request, Semaphore response) { + try { + request.release(); + response.acquire(); + return true; + } catch (InterruptedException x) { + Thread.currentThread().interrupt(); // Restore the interrupt + return false; + } + } + + + @BeforeEach + synchronized void beforeTest() throws Exception { + requestSemaphore = new Semaphore(0); + responseSemaphore = new Semaphore(0); + successfulCompletion = false; + sslContext = new SimpleSSLContext().get(); + if (sslContext == null) { + throw new AssertionError("Unexpected null sslContext"); + } + serverExecutor = Executors.newThreadPerTaskExecutor( + Thread.ofVirtual().name("Http1Server", 0).factory()); + + // On Windows, sending 100 concurrent requests may + // fail if the server's connection backlog is less than 100. + // The default backlog is 50. Just make sure the backlog is + // big enough. + int backlog = Math.max(MANY, 50); + + // create a https server for HTTP/1.1 + var loopback = InetAddress.getLoopbackAddress(); + var wrappedHttps1Server = HttpsServer.create(new InetSocketAddress(loopback, 0), backlog); + wrappedHttps1Server.setHttpsConfigurator(new TestServerConfigurator(loopback, sslContext)); + https1Server = HttpTestServer.of(wrappedHttps1Server, serverExecutor); + https1Server.addHandler((exchange) -> { + if (blockResponse(requestSemaphore, responseSemaphore)) { + exchange.sendResponseHeaders(200, 0); + } else { + exchange.sendResponseHeaders(500, 0); + } + }, "/PlainConnectionLockTest/"); + https1Server.start(); + System.out.println("HTTPS Server started at " + https1Server.getAddress()); + https1URI = "https://" + https1Server.serverAuthority() + "/PlainConnectionLockTest/https1"; + + // create a plain http server for HTTP/1.1 + var wrappedHttp1Server = HttpServer.create(new InetSocketAddress(loopback, 0), backlog); + http1Server = HttpTestServer.of(wrappedHttp1Server, serverExecutor); + http1Server.addHandler((exchange) -> { + if (blockResponse(requestSemaphore, responseSemaphore)) { + exchange.sendResponseHeaders(200, 0); + } else { + exchange.sendResponseHeaders(500, 0); + } + }, "/PlainConnectionLockTest/"); + http1Server.start(); + System.out.println("HTTP Server started at " + http1Server.getAddress()); + http1URI = "http://" + http1Server.serverAuthority() + "/PlainConnectionLockTest/http1"; + } + + @AfterEach + synchronized void afterTest() throws Exception { + if (http1Server != null) { + System.out.println("Stopping HTTP server " + http1Server.getAddress()); + http1Server.stop(); + } + if (https1Server != null) { + System.out.println("Stopping HTTPS server " + https1Server.getAddress()); + https1Server.stop(); + } + if (serverExecutor != null) { + System.out.println("Closing server executor"); + if (successfulCompletion) { + serverExecutor.close(); + } else { + // server handlers may be wedged. + serverExecutor.shutdownNow(); + } + } + requestSemaphore = null; + responseSemaphore = null; + serverExecutor = null; + http1Server = null; + https1Server = null; + http1URI = null; + https1URI = null; + System.out.println("done\n"); + } + + @Test + void sendManyHttpRequestsNoShutdown() throws Exception { + try { + sendManyRequests(http1URI, MANY, false); + } catch (Throwable t) { + t.printStackTrace(System.out); + throw t; + } + } + + @Test + void sendManyHttpRequestsShutdownNow() throws Exception { + try { + sendManyRequests(http1URI, MANY, true); + } catch (Throwable t) { + t.printStackTrace(System.out); + throw t; + } + } + + @Test + void sendManyHttpsRequestsNoShutdown() throws Exception { + try { + sendManyRequests(https1URI, MANY, false); + } catch (Throwable t) { + t.printStackTrace(System.out); + throw t; + } + } + + @Test + void sendManyHttpsRequestsShutdownNow() throws Exception { + try { + sendManyRequests(https1URI, MANY, true); + } catch (Throwable t) { + t.printStackTrace(System.out); + throw t; + } + } + + private static void throwCause(CompletionException x) throws Exception { + var cause = x.getCause(); + if (cause instanceof Exception ex) throw ex; + if (cause instanceof Error err) throw err; + throw x; + } + + static final long start = System.nanoTime(); + public static String now() { + long now = System.nanoTime() - start; + long secs = now / 1000_000_000; + long mill = (now % 1000_000_000) / 1000_000; + long nan = now % 1000_000; + return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan); + } + + static Throwable getCause(Throwable exception) { + if (exception instanceof IOException) return exception; + if (exception instanceof CancellationException) return exception; + if (exception instanceof CompletionException) return getCause(exception.getCause()); + if (exception instanceof ExecutionException) return getCause(exception.getCause()); + return exception; + } + + private synchronized void sendManyRequests(final String requestURI, final int many, boolean shutdown) throws Exception { + System.out.println("\n%sSending %s requests to %s, shutdown=%s\n".formatted(now(), many, requestURI, shutdown)); + System.err.println("\n%sSending %s requests to %s, shutdown=%s\n".formatted(now(), many, requestURI, shutdown)); + assert many > 0; + try (final HttpClient client = HttpClient.newBuilder() + .proxy(NO_PROXY) + .sslContext(sslContext).build()) { + List>> futures = new ArrayList<>(); + final HttpRequest.Builder reqBuilder = HttpRequest.newBuilder().version(HTTP_1_1); + for (int i = 0; i < many; i++) { + // GET + final URI reqURI = new URI(requestURI + "?i=" + i); + final HttpRequest req = reqBuilder.copy().uri(reqURI).GET().build(); + System.out.println(now() + "Issuing request: " + req); + var cf = client.sendAsync(req, BodyHandlers.ofString()); + futures.add(cf); + } + System.out.printf("\n%sWaiting for %s requests to be handled on the server%n", now(), many); + + int count = 0; + // wait for all exchanges to be handled + while (!requestSemaphore.tryAcquire(many, 5, TimeUnit.SECONDS)) { + count++; + System.out.printf("%sFailed to obtain %s permits after %ss - only %s available%n", + now(), many, (count * 5), requestSemaphore.availablePermits()); + for (var cf : futures) { + if (cf.isDone() || cf.isCancelled()) { + System.out.printf("%sFound some completed cf: %s%n", now(), cf); + if (cf.isCancelled()) { + System.out.printf("%scf is cancelled: %s%n", now(), cf); + client.shutdownNow(); // make sure HttpCient::close won't block waiting for server + var error = new AssertionError(now() + "A request cf was cancelled" + cf); + System.out.printf("%s throwing: %s%n", now(), error); + throw error; + } + if (cf.isCompletedExceptionally()) { + System.out.printf("%scf is completed exceptionally: %s%n", now(), cf); + var exception = getCause(cf.exceptionNow()); + System.out.printf("%sexception is: %s%n", now(), exception); + client.shutdownNow(); // make sure HttpCient::close won't block waiting for server + exception.printStackTrace(System.out); + var error = new AssertionError(now() + "A request failed prematurely", exception); + System.out.printf("%s throwing: %s%n", now(), error); + throw error; + } + System.out.printf("%scf is completed prematurely: %s%n", now(), cf); + client.shutdownNow(); // make sure HttpCient::close won't block waiting for server + var error = new AssertionError(now() + "A request succeeded prematurely: " + cf.join()); + System.out.printf("%s throwing: %s%n", now(), error); + throw error; + } + } + System.out.printf("%sCouldn't acquire %s permits, only %s available - keep on waiting%n", + now(), many, requestSemaphore.availablePermits()); + } + + System.out.println(now() + "All requests reached the server: releasing one response"); + // allow one request to proceed + responseSemaphore.release(); + try { + // wait for the first response. + System.out.println(now() + "Waiting for the first response"); + CompletableFuture.anyOf(futures.toArray(new CompletableFuture[0])).join(); + System.out.println(now() + "Got first response: " + futures.stream().filter(CompletableFuture::isDone) + .findFirst().map(CompletableFuture::join)); + if (shutdown) { + System.out.println(now() + "Calling HttpClient::shutdownNow"); + client.shutdownNow(); + client.awaitTermination(Duration.ofSeconds(1)); + } + } finally { + System.out.printf("%s Releasing %s remaining responses%n", now(), many - 1); + // now release the others. + responseSemaphore.release(many - 1); + } + + // wait for all responses + System.out.printf("%sWaiting for all %s responses to complete%n", now(), many); + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).exceptionally(t -> null).join(); + + // check + System.out.printf("%sAll %s responses completed. Checking...%n%n", now(), many); + Set conns = new HashSet<>(); + int exceptionCount = 0; + int success = 0; + for (var respCF : futures) { + try { + var resp = respCF.join(); + Assertions.assertEquals(200, resp.statusCode(), + now() + "unexpected response code for GET request: " + resp); + Assertions.assertTrue(conns.add(resp.connectionLabel().get()), + now() + "unexepected reuse of connection: " + + resp.connectionLabel().get() + " found in " + conns); + success++; + } catch (CompletionException x) { + if (shutdown) exceptionCount++; + else throwCause(x); + } + } + if (shutdown) { + if (success == 0) { + throw new AssertionError(("%s%s: shutdownNow=%s: Expected at least one response, " + + "got success=%s, exceptions=%s").formatted(now(), requestURI, shutdown, success, exceptionCount)); + } + } + System.out.println("%sSuccess: %s: shutdownNow:%s, success=%s, exceptions:%s\n" + .formatted(now(), requestURI, shutdown, success, exceptionCount)); + successfulCompletion = true; + } + } +} diff --git a/test/jdk/java/net/httpclient/TlsContextTest.java b/test/jdk/java/net/httpclient/TlsContextTest.java index f24007f6d90..86b067f66f8 100644 --- a/test/jdk/java/net/httpclient/TlsContextTest.java +++ b/test/jdk/java/net/httpclient/TlsContextTest.java @@ -31,6 +31,8 @@ import java.net.http.HttpResponse; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; + import jdk.httpclient.test.lib.common.HttpServerAdapters; import jdk.httpclient.test.lib.http2.Http2TestServer; import jdk.test.lib.net.SimpleSSLContext; @@ -49,7 +51,7 @@ import jdk.test.lib.security.SecurityUtils; /* * @test - * @bug 8239594 + * @bug 8239594 8371887 * @summary This test verifies that the TLS version handshake respects ssl context * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext TlsContextTest @@ -101,9 +103,25 @@ public class TlsContextTest implements HttpServerAdapters { * Tests various scenarios between client and server tls handshake with valid http */ @Test(dataProvider = "scenarios") - public void testVersionProtocols(SSLContext context, + public void testVersionProtocolsNoParams(SSLContext context, Version version, String expectedProtocol) throws Exception { + runTest(context, version, expectedProtocol, false); + } + + /** + * Tests various scenarios between client and server tls handshake with valid http, + * but with empty SSLParameters + */ + @Test(dataProvider = "scenarios") + public void testVersionProtocolsEmptyParams(SSLContext context, + Version version, + String expectedProtocol) throws Exception { + runTest(context, version, expectedProtocol, true); + } + + private void runTest(SSLContext context, Version version, String expectedProtocol, + boolean setEmptyParams) throws Exception { // for HTTP/3 we won't accept to set the version to HTTP/3 on the // client if we don't have TLSv1.3; We will set the version // on the request instead in that case. @@ -111,8 +129,11 @@ public class TlsContextTest implements HttpServerAdapters { : HttpClient.newBuilder().version(version); var reqBuilder = HttpRequest.newBuilder(new URI(https2URI)); + if (setEmptyParams) { + builder.sslParameters(new SSLParameters()); + } HttpClient client = builder.sslContext(context) - .build(); + .build(); if (version == HTTP_3) { // warmup to obtain AltService client.send(reqBuilder.version(HTTP_2).GET().build(), ofString()); diff --git a/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java b/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java index 1eaf331c261..767d31f13e5 100644 --- a/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java +++ b/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java @@ -27,7 +27,7 @@ * @summary checks connection flow control * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.internal.httpclient.debug=true + * @run junit/othervm -Djdk.internal.httpclient.debug=err * -Djdk.httpclient.connectionWindowSize=65535 * -Djdk.httpclient.windowsize=16384 * ConnectionFlowControlTest @@ -122,7 +122,7 @@ public class ConnectionFlowControlTest { final HttpClient cc = client; var response = cc.send(request, BodyHandlers.ofInputStream()); responses.put(query, response); - String ckey = response.headers().firstValue("X-Connection-Key").get(); + String ckey = response.connectionLabel().get(); if (label == null) label = ckey; try { if (i < max - 1) { @@ -149,7 +149,7 @@ public class ConnectionFlowControlTest { try { String query = keys[i]; var response = responses.get(keys[i]); - String ckey = response.headers().firstValue("X-Connection-Key").get(); + String ckey = response.connectionLabel().get(); if (label == null) label = ckey; if (i < max - 1) { // the connection window might be exceeded at i == max - 2, which @@ -206,7 +206,7 @@ public class ConnectionFlowControlTest { System.out.println("\nSending last request:" + uriWithQuery); var response = client.send(request, BodyHandlers.ofString()); if (label != null) { - String ckey = response.headers().firstValue("X-Connection-Key").get(); + String ckey = response.connectionLabel().get(); assertNotEquals(label, ckey); System.out.printf("last request %s sent on different connection as expected:" + "\n\tlast: %s\n\tprevious: %s%n", query, ckey, label); @@ -281,7 +281,6 @@ public class ConnectionFlowControlTest { byte[] bytes = is.readAllBytes(); System.out.println("Server " + t.getLocalAddress() + " received:\n" + t.getRequestURI() + ": " + new String(bytes, StandardCharsets.UTF_8)); - t.getResponseHeaders().setHeader("X-Connection-Key", t.getConnectionKey()); if (bytes.length == 0) bytes = "no request body!".getBytes(StandardCharsets.UTF_8); int window = Math.max(16384, Integer.getInteger("jdk.httpclient.windowsize", 2*16*1024)); diff --git a/test/jdk/java/net/httpclient/http2/TLSConnection.java b/test/jdk/java/net/httpclient/http2/TLSConnection.java index fd9cff38371..e4009219bca 100644 --- a/test/jdk/java/net/httpclient/http2/TLSConnection.java +++ b/test/jdk/java/net/httpclient/http2/TLSConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ import jdk.httpclient.test.lib.http2.Http2Handler; /* * @test - * @bug 8150769 8157107 + * @bug 8150769 8157107 8371887 * @library /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * @summary Checks that SSL parameters can be set for HTTP/2 connection @@ -135,6 +135,12 @@ public class TLSConnection { success &= checkCipherSuite(handler.getSSLSession(), "TLS_RSA_WITH_AES_128_CBC_SHA"); + success &= expectSuccess( + "---\nTest #5: empty SSL parameters, " + + "expect successful connection", + () -> connect(uriString, new SSLParameters())); + success &= checkProtocol(handler.getSSLSession(), expectedTLSVersion(null)); + if (success) { System.out.println("Test passed"); } else { diff --git a/test/jdk/java/net/httpclient/http3/H3IdleExceedsQuicIdleTimeout.java b/test/jdk/java/net/httpclient/http3/H3IdleExceedsQuicIdleTimeout.java new file mode 100644 index 00000000000..6b62fcf6043 --- /dev/null +++ b/test/jdk/java/net/httpclient/http3/H3IdleExceedsQuicIdleTimeout.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpOption; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.SSLContext; + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.Version.HTTP_3; +import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/* + * @test + * @bug 8371802 + * @summary verify that if a higher idle timeout is configured for a HTTP/3 connection + * then a lower negotiated QUIC idle timeout doesn't cause QUIC to + * idle terminate the connection + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @comment this test has some explicit delays to simulate a idle connection, the timeout=180 + * is merely to provide some leeway to the test and prevent timing out the test on busy + * systems + * @run junit/othervm/timeout=180 -Djdk.httpclient.quic.idleTimeout=30 + * -Djdk.httpclient.keepalive.timeout.h3=120 + * ${test.main.class} + */ +class H3IdleExceedsQuicIdleTimeout { + + private static final String REQ_PATH = "/8371802"; + + private static HttpTestServer h3Server; + private static SSLContext sslCtx; + + @BeforeAll + static void beforeAll() throws Exception { + sslCtx = new SimpleSSLContext().get(); + assert sslCtx != null : "SSLContext is null"; + h3Server = HttpTestServer.create(HTTP_3_URI_ONLY, sslCtx); + h3Server.addHandler(new Handler(), REQ_PATH); + h3Server.start(); + System.err.println("HTTP/3 server started at " + h3Server.getAddress()); + } + + @AfterAll + static void afterAll() throws Exception { + if (h3Server != null) { + System.err.println("stopping server at " + h3Server.getAddress()); + h3Server.stop(); + } + } + + /* + * With QUIC idle connection timeout configured to be lower than the HTTP/3 idle timeout, + * this test issues a HTTP/3 request and expects that request to establish a QUIC connection + * and receive a successful response. The test then stays idle for a duration larger + * than the QUIC idle timeout and issues a HTTP/3 request again after that idle period. + * The test then expects that the second request too is responded by the previously opened + * connection, thus proving that the QUIC layer did the necessary work to prevent the (idle) + * connection from terminating. + */ + @Test + void testQUICKeepsConnAlive() throws Exception { + final long quicIdleTimeoutSecs = 30; + assertEquals(quicIdleTimeoutSecs, + Integer.parseInt(System.getProperty("jdk.httpclient.quic.idleTimeout")), + "unexpected QUIC idle timeout"); + assertEquals(120, + Integer.parseInt(System.getProperty("jdk.httpclient.keepalive.timeout.h3")), + "unexpected HTTP/3 idle timeout"); + try (final HttpClient client = HttpClient.newBuilder() + .sslContext(sslCtx) + .proxy(NO_PROXY) + .version(HTTP_3) + .build()) { + + final URI req1URI = URIBuilder.newBuilder() + .scheme("https") + .host(h3Server.getAddress().getAddress()) + .port(h3Server.getAddress().getPort()) + .path(REQ_PATH) + .query("i=1") + .build(); + System.err.println("issuing request " + req1URI); + final HttpRequest req1 = HttpRequest.newBuilder() + .uri(req1URI) + .setOption(HttpOption.H3_DISCOVERY, HTTP_3_URI_ONLY) + .build(); + final HttpResponse resp1 = client.send(req1, BodyHandlers.discarding()); + assertEquals(200, resp1.statusCode(), "unexpected status code"); + final String resp1ConnLabel = resp1.connectionLabel().orElse(null); + System.err.println("first request handled by connection: " + resp1ConnLabel); + assertNotNull(resp1ConnLabel, "missing connection label on response"); + assertEquals(HTTP_3, resp1.version(), "unexpected response version"); + // don't generate any more traffic from the HTTP/3 side for longer than the QUIC + // idle timeout + stayIdle(quicIdleTimeoutSecs + 13, TimeUnit.SECONDS); + // now send the HTTP/3 request and expect the same previous connection to handle + // respond to this request + final URI req2URI = URIBuilder.newBuilder() + .scheme("https") + .host(h3Server.getAddress().getAddress()) + .port(h3Server.getAddress().getPort()) + .path(REQ_PATH) + .query("i=2") + .build(); + System.err.println("issuing request " + req2URI); + final HttpRequest req2 = HttpRequest.newBuilder() + .uri(req2URI) + .setOption(HttpOption.H3_DISCOVERY, HTTP_3_URI_ONLY) + .build(); + final HttpResponse resp2 = client.send(req2, BodyHandlers.discarding()); + assertEquals(200, resp2.statusCode(), "unexpected status code"); + final String resp2ConnLabel = resp2.connectionLabel().orElse(null); + System.err.println("second request handled by connection: " + resp2ConnLabel); + assertEquals(resp1ConnLabel, resp2ConnLabel, "second request handled by a different connection"); + assertEquals(HTTP_3, resp2.version(), "unexpected response version"); + } + } + + private static void stayIdle(final long time, final TimeUnit unit) throws InterruptedException { + // await on a CountDownLatch which no one counts down. this is merely + // to avoid using Thread.sleep(...) and other similar constructs and then + // having to deal with spurious wakeups. + final boolean countedDown = new CountDownLatch(1).await(time, unit); + assertFalse(countedDown, "wasn't expected to be counted down"); + } + + private static final class Handler implements HttpTestHandler { + private static final int NO_RESP_BODY = 0; + + @Override + public void handle(final HttpTestExchange exchange) throws IOException { + System.err.println("handling request " + exchange.getRequestURI()); + exchange.sendResponseHeaders(200, NO_RESP_BODY); + } + } +} diff --git a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java index 34d5163760f..862ccf22ddc 100644 --- a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java +++ b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java @@ -23,7 +23,7 @@ /* * @test id=with-continuations - * @bug 8087112 + * @bug 8087112 8372409 * @requires os.family != "windows" | ( os.name != "Windows 10" & os.name != "Windows Server 2016" * & os.name != "Windows Server 2019" ) * @library /test/lib /test/jdk/java/net/httpclient/lib @@ -46,7 +46,7 @@ */ /* * @test id=without-continuations - * @bug 8087112 + * @bug 8087112 8372409 * @requires os.family == "windows" & ( os.name == "Windows 10" | os.name == "Windows Server 2016" * | os.name == "Windows Server 2019" ) * @library /test/lib /test/jdk/java/net/httpclient/lib @@ -71,7 +71,7 @@ */ /* * @test id=useNioSelector - * @bug 8087112 + * @bug 8087112 8372409 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.http2.Http2TestServer @@ -96,7 +96,7 @@ */ /* * @test id=reno-cc - * @bug 8087112 + * @bug 8087112 8372409 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.http2.Http2TestServer diff --git a/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java b/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java index 090dec2c189..790af245db8 100644 --- a/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java +++ b/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java @@ -34,6 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test + * @bug 8371887 * @summary Tests that a HttpClient configured with SSLParameters that doesn't include TLSv1.3 * cannot be used for HTTP3 * @library /test/lib /test/jdk/java/net/httpclient/lib @@ -75,4 +76,18 @@ public class H3UnsupportedSSLParametersTest { .version(HttpClient.Version.HTTP_3).build(); assertNotNull(client, "HttpClient is null"); } + + /** + * Builds a HttpClient with SSLParameters without protocol versions + * and expects the build() to succeed and return a HttpClient instance + */ + @Test + public void testDefault() throws Exception { + final SSLParameters params = new SSLParameters(); + final HttpClient client = HttpServerAdapters.createClientBuilderForH3() + .proxy(HttpClient.Builder.NO_PROXY) + .sslParameters(params) + .version(HttpClient.Version.HTTP_3).build(); + assertNotNull(client, "HttpClient is null"); + } } diff --git a/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java b/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java index f917b6af4dc..7a4fe15ecac 100644 --- a/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java +++ b/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +22,108 @@ */ package test.sql; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; -import util.StubCallableStatement; +import org.testng.annotations.Test; +import util.BaseTest; +import util.StubConnection; -public class CallableStatementTests extends PreparedStatementTests { +import java.sql.CallableStatement; +import java.sql.SQLException; + +import static org.testng.Assert.assertEquals; + +public class CallableStatementTests extends BaseTest { + private CallableStatement cstmt; @BeforeMethod public void setUpMethod() throws Exception { - stmt = new StubCallableStatement(); + cstmt = new StubConnection().prepareCall("{call SuperHero_Proc(?)}"); } + @AfterMethod + public void tearDownMethod() throws Exception { + cstmt.close(); + } + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedLiteralValues") + public void test00(String s, String expected) throws SQLException { + assertEquals(cstmt.enquoteLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test01() throws SQLException { + cstmt.enquoteLiteral(null); + } + + /* + * Validate that enquoteIdentifier returns the expected value + */ + @Test(dataProvider = "validIdentifierValues") + public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { + assertEquals(cstmt.enquoteIdentifier(s, alwaysQuote), expected); + } + + /* + * Validate that a SQLException is thrown for values that are not valid + * for a SQL identifier + */ + @Test(dataProvider = "invalidIdentifierValues", + expectedExceptions = SQLException.class) + public void test03(String s, boolean alwaysQuote) throws SQLException { + cstmt.enquoteIdentifier(s, alwaysQuote); + } + + /* + * Validate a NullPointerException is thrown is the string passed to + * enquoteIdentiifer is null + */ + @Test(dataProvider = "trueFalse", + expectedExceptions = NullPointerException.class) + public void test04(boolean alwaysQuote) throws SQLException { + cstmt.enquoteIdentifier(null, alwaysQuote); + } + + /* + * Validate that isSimpleIdentifier returns the expected value + */ + @Test(dataProvider = "simpleIdentifierValues") + public void test05(String s, boolean expected) throws SQLException { + assertEquals(cstmt.isSimpleIdentifier(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * isSimpleIdentifier is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test06() throws SQLException { + cstmt.isSimpleIdentifier(null); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedNCharLiteralValues") + public void test07(String s, String expected) throws SQLException { + assertEquals(cstmt.enquoteNCharLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteNCharLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test08() throws SQLException { + cstmt.enquoteNCharLiteral(null); + } } diff --git a/test/jdk/java/sql/testng/test/sql/ConnectionTests.java b/test/jdk/java/sql/testng/test/sql/ConnectionTests.java new file mode 100644 index 00000000000..f40c2784e4a --- /dev/null +++ b/test/jdk/java/sql/testng/test/sql/ConnectionTests.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package test.sql; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import util.BaseTest; +import util.StubConnection; + +import java.sql.SQLException; + +import static org.testng.Assert.*; + +public class ConnectionTests extends BaseTest { + + protected StubConnection conn; + + @BeforeMethod + public void setUpMethod() throws Exception { + conn = new StubConnection(); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedLiteralValues") + public void test00(String s, String expected) throws SQLException { + assertEquals(conn.enquoteLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test01() throws SQLException { + conn.enquoteLiteral(null); + } + + /* + * Validate that enquoteIdentifier returns the expected value + */ + @Test(dataProvider = "validIdentifierValues") + public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { + assertEquals(conn.enquoteIdentifier(s, alwaysQuote), expected); + } + + /* + * Validate that a SQLException is thrown for values that are not valid + * for a SQL identifier + */ + @Test(dataProvider = "invalidIdentifierValues", + expectedExceptions = SQLException.class) + public void test03(String s, boolean alwaysQuote) throws SQLException { + conn.enquoteIdentifier(s, alwaysQuote); + } + + /* + * Validate a NullPointerException is thrown is the string passed to + * enquoteIdentiifer is null + */ + @Test(dataProvider = "trueFalse", + expectedExceptions = NullPointerException.class) + public void test04(boolean alwaysQuote) throws SQLException { + conn.enquoteIdentifier(null, alwaysQuote); + } + + /* + * Validate that isSimpleIdentifier returns the expected value + */ + @Test(dataProvider = "simpleIdentifierValues") + public void test05(String s, boolean expected) throws SQLException { + assertEquals(conn.isSimpleIdentifier(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * isSimpleIdentifier is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test06() throws SQLException { + conn.isSimpleIdentifier(null); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedNCharLiteralValues") + public void test07(String s, String expected) throws SQLException { + assertEquals(conn.enquoteNCharLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteNCharLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test08() throws SQLException { + conn.enquoteNCharLiteral(null); + } +} diff --git a/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java b/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java index d54763189c5..7813038361d 100644 --- a/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java +++ b/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,14 +22,109 @@ */ package test.sql; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; -import util.StubPreparedStatement; +import org.testng.annotations.Test; +import util.BaseTest; +import util.StubConnection; -public class PreparedStatementTests extends StatementTests { +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import static org.testng.Assert.assertEquals; + +public class PreparedStatementTests extends BaseTest { + + private PreparedStatement pstmt; @BeforeMethod public void setUpMethod() throws Exception { - stmt = new StubPreparedStatement(); + pstmt = new StubConnection().prepareStatement("Select * from foo were bar = ?"); } + @AfterMethod + public void tearDownMethod() throws Exception { + pstmt.close(); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedLiteralValues") + public void test00(String s, String expected) throws SQLException { + assertEquals(pstmt.enquoteLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test01() throws SQLException { + pstmt.enquoteLiteral(null); + } + + /* + * Validate that enquoteIdentifier returns the expected value + */ + @Test(dataProvider = "validIdentifierValues") + public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { + assertEquals(pstmt.enquoteIdentifier(s, alwaysQuote), expected); + } + + /* + * Validate that a SQLException is thrown for values that are not valid + * for a SQL identifier + */ + @Test(dataProvider = "invalidIdentifierValues", + expectedExceptions = SQLException.class) + public void test03(String s, boolean alwaysQuote) throws SQLException { + pstmt.enquoteIdentifier(s, alwaysQuote); + } + + /* + * Validate a NullPointerException is thrown is the string passed to + * enquoteIdentiifer is null + */ + @Test(dataProvider = "trueFalse", + expectedExceptions = NullPointerException.class) + public void test04(boolean alwaysQuote) throws SQLException { + pstmt.enquoteIdentifier(null, alwaysQuote); + } + + /* + * Validate that isSimpleIdentifier returns the expected value + */ + @Test(dataProvider = "simpleIdentifierValues") + public void test05(String s, boolean expected) throws SQLException { + assertEquals(pstmt.isSimpleIdentifier(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * isSimpleIdentifier is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test06() throws SQLException { + pstmt.isSimpleIdentifier(null); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedNCharLiteralValues") + public void test07(String s, String expected) throws SQLException { + assertEquals(pstmt.enquoteNCharLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteNCharLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test08() throws SQLException { + pstmt.enquoteNCharLiteral(null); + } } diff --git a/test/jdk/java/sql/testng/test/sql/StatementTests.java b/test/jdk/java/sql/testng/test/sql/StatementTests.java index 88697b77f9d..f2bfe712eb5 100644 --- a/test/jdk/java/sql/testng/test/sql/StatementTests.java +++ b/test/jdk/java/sql/testng/test/sql/StatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,38 +23,31 @@ package test.sql; import java.sql.SQLException; +import java.sql.Statement; + import static org.testng.Assert.assertEquals; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import org.testng.annotations.*; import util.BaseTest; -import util.StubStatement; +import util.StubConnection; public class StatementTests extends BaseTest { - protected StubStatement stmt; - protected static String maxIdentifier; + private Statement stmt; @BeforeMethod public void setUpMethod() throws Exception { - stmt = new StubStatement(); + stmt = new StubConnection().createStatement(); } - @BeforeClass - public static void setUpClass() throws Exception { - int maxLen = 128; - StringBuilder s = new StringBuilder(maxLen); - for (int i = 0; i < maxLen; i++) { - s.append('a'); - } - maxIdentifier = s.toString(); + @AfterMethod + public void tearDownMethod() throws Exception { + stmt.close(); } /* * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedLiteralValues") public void test00(String s, String expected) throws SQLException { assertEquals(stmt.enquoteLiteral(s), expected); @@ -67,7 +60,6 @@ public class StatementTests extends BaseTest { @Test(expectedExceptions = NullPointerException.class) public void test01() throws SQLException { stmt.enquoteLiteral(null); - } /* @@ -76,7 +68,6 @@ public class StatementTests extends BaseTest { @Test(dataProvider = "validIdentifierValues") public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { assertEquals(stmt.enquoteIdentifier(s, alwaysQuote), expected); - } /* @@ -87,7 +78,6 @@ public class StatementTests extends BaseTest { expectedExceptions = SQLException.class) public void test03(String s, boolean alwaysQuote) throws SQLException { stmt.enquoteIdentifier(s, alwaysQuote); - } /* @@ -98,7 +88,6 @@ public class StatementTests extends BaseTest { expectedExceptions = NullPointerException.class) public void test04(boolean alwaysQuote) throws SQLException { stmt.enquoteIdentifier(null, alwaysQuote); - } /* @@ -116,7 +105,6 @@ public class StatementTests extends BaseTest { @Test(expectedExceptions = NullPointerException.class) public void test06() throws SQLException { stmt.isSimpleIdentifier(null); - } /* @@ -136,97 +124,4 @@ public class StatementTests extends BaseTest { public void test08() throws SQLException { stmt.enquoteNCharLiteral(null); } - - /* - * DataProvider used to provide strings that will be used to validate - * that enquoteLiteral converts a string to a literal and every instance of - * a single quote will be converted into two single quotes in the literal. - */ - @DataProvider(name = "validEnquotedLiteralValues") - protected Object[][] validEnquotedLiteralValues() { - return new Object[][]{ - {"Hello", "'Hello'"}, - {"G'Day", "'G''Day'"}, - {"'G''Day'", "'''G''''Day'''"}, - {"I'''M", "'I''''''M'"}, - {"The Dark Knight", "'The Dark Knight'"} - - }; - } - - /* - * DataProvider used to provide strings that will be used to validate - * that enqouteIdentifier returns a simple SQL Identifier or a double - * quoted identifier - */ - @DataProvider(name = "validIdentifierValues") - protected Object[][] validEnquotedIdentifierValues() { - return new Object[][]{ - {"b", false, "b"}, - {"b", true, "\"b\""}, - {maxIdentifier, false, maxIdentifier}, - {maxIdentifier, true, "\"" + maxIdentifier + "\""}, - {"Hello", false, "Hello"}, - {"Hello", true, "\"Hello\""}, - {"G'Day", false, "\"G'Day\""}, - {"G'Day", true, "\"G'Day\""}, - {"Bruce Wayne", false, "\"Bruce Wayne\""}, - {"Bruce Wayne", true, "\"Bruce Wayne\""}, - {"GoodDay$", false, "\"GoodDay$\""}, - {"GoodDay$", true, "\"GoodDay$\""},}; - } - - /* - * DataProvider used to provide strings are invalid for enquoteIdentifier - * resulting in a SQLException being thrown - */ - @DataProvider(name = "invalidIdentifierValues") - protected Object[][] invalidEnquotedIdentifierValues() { - return new Object[][]{ - {"Hel\"lo", false}, - {"\"Hel\"lo\"", true}, - {"Hello" + '\0', false}, - {"", false}, - {maxIdentifier + 'a', false},}; - } - - /* - * DataProvider used to provide strings that will be used to validate - * that isSimpleIdentifier returns the correct value based on the - * identifier specified. - */ - @DataProvider(name = "simpleIdentifierValues") - protected Object[][] simpleIdentifierValues() { - return new Object[][]{ - {"b", true}, - {"Hello", true}, - {"\"Gotham\"", false}, - {"G'Day", false}, - {"Bruce Wayne", false}, - {"GoodDay$", false}, - {"Dick_Grayson", true}, - {"Batmobile1966", true}, - {maxIdentifier, true}, - {maxIdentifier + 'a', false}, - {"", false},}; - } - - /* - * DataProvider used to provide strings that will be used to validate - * that enquoteNCharLiteral converts a string to a National Character - * literal and every instance of - * a single quote will be converted into two single quotes in the literal. - */ - @DataProvider(name = "validEnquotedNCharLiteralValues") - protected Object[][] validEnquotedNCharLiteralValues() { - return new Object[][]{ - {"Hello", "N'Hello'"}, - {"G'Day", "N'G''Day'"}, - {"'G''Day'", "N'''G''''Day'''"}, - {"I'''M", "N'I''''''M'"}, - {"N'Hello'", "N'N''Hello'''"}, - {"The Dark Knight", "N'The Dark Knight'"} - - }; - } } diff --git a/test/jdk/java/sql/testng/test/sql/TimestampTests.java b/test/jdk/java/sql/testng/test/sql/TimestampTests.java index fefe3276d47..6baea9fa26f 100644 --- a/test/jdk/java/sql/testng/test/sql/TimestampTests.java +++ b/test/jdk/java/sql/testng/test/sql/TimestampTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -667,6 +667,44 @@ public class TimestampTests extends BaseTest { expectThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MIN)); } + /* + * Validate that two Timestamp hashCode values are equal when + * the Timestamp values match, including the nanos. + */ + @Test + public void test54() { + long t = System.currentTimeMillis(); + Timestamp ts1 = new Timestamp(t); + Timestamp ts2 = new Timestamp(t); + ts1.setNanos(123456789); + ts2.setNanos(123456789); + assertTrue(ts1.equals(ts1)); + assertTrue(ts2.equals(ts2)); + assertTrue(ts1.equals(ts2)); + // As the Timestamp values, including the nanos are the same, the hashCode's + // should be equal + assertEquals(ts1.hashCode(), ts2.hashCode()); + } + + /* + * Validate that two Timestamp hashCode values are not equal when only + * the nanos value for the Timestamp differ. + */ + @Test + public void test55() { + long t = System.currentTimeMillis(); + Timestamp ts1 = new Timestamp(t); + Timestamp ts2 = new Timestamp(t); + // Modify the nanos so that the Timestamp values differ + ts1.setNanos(123456789); + ts2.setNanos(987654321); + assertTrue(ts1.equals(ts1)); + assertTrue(ts2.equals(ts2)); + assertFalse(ts1.equals(ts2)); + // As the nanos differ, the hashCode values should differ + assertNotEquals(ts1.hashCode(), ts2.hashCode()); + } + /* * DataProvider used to provide Timestamps which are not valid and are used * to validate that an IllegalArgumentException will be thrown from the diff --git a/test/jdk/java/sql/testng/util/BaseTest.java b/test/jdk/java/sql/testng/util/BaseTest.java index 6821940b7ce..8751183726d 100644 --- a/test/jdk/java/sql/testng/util/BaseTest.java +++ b/test/jdk/java/sql/testng/util/BaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.security.Policy; import java.sql.JDBCType; import java.sql.SQLException; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; + import org.testng.annotations.DataProvider; public class BaseTest { @@ -47,22 +43,7 @@ public class BaseTest { protected final int errorCode = 21; protected final String[] msgs = {"Exception 1", "cause 1", "Exception 2", "Exception 3", "cause 2"}; - - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - - @BeforeMethod - public void setUpMethod() throws Exception { - } - - @AfterMethod - public void tearDownMethod() throws Exception { - } + private static final String MAX_LENGTH_IDENTIFIER = "a".repeat(128); /* * Take some form of SQLException, serialize and deserialize it @@ -92,13 +73,6 @@ public class BaseTest { return o1; } - /* - * Utility Method used to set the current Policy - */ - protected static void setPolicy(Policy p) { - Policy.setPolicy(p); - } - /* * DataProvider used to specify the value to set and check for * methods using boolean values @@ -123,4 +97,99 @@ public class BaseTest { } return o; } + + /* + * DataProvider used to provide strings that will be used to validate + * that enquoteLiteral converts a string to a literal and every instance of + * a single quote will be converted into two single quotes in the literal. + */ + @DataProvider(name = "validEnquotedLiteralValues") + protected Object[][] validEnquotedLiteralValues() { + return new Object[][]{ + {"Hello", "'Hello'"}, + {"G'Day", "'G''Day'"}, + {"'G''Day'", "'''G''''Day'''"}, + {"I'''M", "'I''''''M'"}, + {"The Dark Knight", "'The Dark Knight'"}, + }; + } + + /* + * DataProvider used to provide strings that will be used to validate + * that enqouteIdentifier returns a simple SQL Identifier or a + * quoted identifier + */ + @DataProvider(name = "validIdentifierValues") + protected Object[][] validEnquotedIdentifierValues() { + return new Object[][]{ + {"b", false, "b"}, + {"b", true, "\"b\""}, + {MAX_LENGTH_IDENTIFIER, false, MAX_LENGTH_IDENTIFIER}, + {MAX_LENGTH_IDENTIFIER, true, "\"" + MAX_LENGTH_IDENTIFIER + "\""}, + {"Hello", false, "Hello"}, + {"Hello", true, "\"Hello\""}, + {"G'Day", false, "\"G'Day\""}, + {"G'Day", true, "\"G'Day\""}, + {"Bruce Wayne", false, "\"Bruce Wayne\""}, + {"Bruce Wayne", true, "\"Bruce Wayne\""}, + {"select", false, "\"select\""}, + {"table", true, "\"table\""}, + {"GoodDay$", false, "\"GoodDay$\""}, + {"GoodDay$", true, "\"GoodDay$\""},}; + } + + /* + * DataProvider used to provide strings are invalid for enquoteIdentifier + * resulting in a SQLException being thrown + */ + @DataProvider(name = "invalidIdentifierValues") + protected Object[][] invalidEnquotedIdentifierValues() { + return new Object[][]{ + {"Hel\"lo", false}, + {"\"Hel\"lo\"", true}, + {"Hello" + '\0', false}, + {"", false}, + {MAX_LENGTH_IDENTIFIER + 'a', false},}; + } + + /* + * DataProvider used to provide strings that will be used to validate + * that isSimpleIdentifier returns the correct value based on the + * identifier specified. + */ + @DataProvider(name = "simpleIdentifierValues") + protected Object[][] simpleIdentifierValues() { + return new Object[][]{ + {"b", true}, + {"Hello", true}, + {"\"Gotham\"", false}, + {"G'Day", false}, + {"Bruce Wayne", false}, + {"GoodDay$", false}, + {"Dick_Grayson", true}, + {"Batmobile1966", true}, + {MAX_LENGTH_IDENTIFIER, true}, + {MAX_LENGTH_IDENTIFIER + 'a', false}, + {"", false}, + {"select", false} + }; + } + + /* + * DataProvider used to provide strings that will be used to validate + * that enquoteNCharLiteral converts a string to a National Character + * literal and every instance of + * a single quote will be converted into two single quotes in the literal. + */ + @DataProvider(name = "validEnquotedNCharLiteralValues") + protected Object[][] validEnquotedNCharLiteralValues() { + return new Object[][]{ + {"Hello", "N'Hello'"}, + {"G'Day", "N'G''Day'"}, + {"'G''Day'", "N'''G''''Day'''"}, + {"I'''M", "N'I''''''M'"}, + {"N'Hello'", "N'N''Hello'''"}, + {"The Dark Knight", "N'The Dark Knight'"} + }; + } } diff --git a/test/jdk/java/sql/testng/util/StubCallableStatement.java b/test/jdk/java/sql/testng/util/StubCallableStatement.java index 1833a44d56d..4a7c27314bb 100644 --- a/test/jdk/java/sql/testng/util/StubCallableStatement.java +++ b/test/jdk/java/sql/testng/util/StubCallableStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,24 +26,17 @@ import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; -import java.sql.Array; -import java.sql.Blob; -import java.sql.CallableStatement; -import java.sql.Clob; -import java.sql.Date; -import java.sql.NClob; -import java.sql.Ref; -import java.sql.RowId; -import java.sql.SQLException; -import java.sql.SQLXML; -import java.sql.Time; -import java.sql.Timestamp; +import java.sql.*; import java.util.Calendar; import java.util.Map; public class StubCallableStatement extends StubPreparedStatement implements CallableStatement{ + public StubCallableStatement(StubConnection con) { + super(con); + } + @Override public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); @@ -608,5 +601,4 @@ implements CallableStatement{ public T getObject(String parameterName, Class type) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); } - } diff --git a/test/jdk/java/sql/testng/util/StubConnection.java b/test/jdk/java/sql/testng/util/StubConnection.java index b9ab97062d3..cd013572adc 100644 --- a/test/jdk/java/sql/testng/util/StubConnection.java +++ b/test/jdk/java/sql/testng/util/StubConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,20 +44,25 @@ import java.util.concurrent.Executor; public class StubConnection implements Connection { private boolean autoCommit = false; + private boolean isclosed; + + public StubConnection() { + isclosed = false; + } @Override public Statement createStatement() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubStatement(this); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubPreparedStatement(this); } @Override public CallableStatement prepareCall(String sql) throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubCallableStatement(this); } @Override @@ -89,17 +94,17 @@ public class StubConnection implements Connection { @Override public void close() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + isclosed = true; } @Override public boolean isClosed() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return isclosed; } @Override public DatabaseMetaData getMetaData() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubDatabaseMetaData(); } @Override diff --git a/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java b/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java new file mode 100644 index 00000000000..3bf70afaa8f --- /dev/null +++ b/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package util; + +import java.sql.*; + +public class StubDatabaseMetaData implements DatabaseMetaData { + @Override + public boolean allProceduresAreCallable() throws SQLException { + return false; + } + + @Override + public boolean allTablesAreSelectable() throws SQLException { + return false; + } + + @Override + public String getURL() throws SQLException { + return ""; + } + + @Override + public String getUserName() throws SQLException { + return ""; + } + + @Override + public boolean isReadOnly() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedHigh() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedLow() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedAtEnd() throws SQLException { + return false; + } + + @Override + public String getDatabaseProductName() throws SQLException { + return ""; + } + + @Override + public String getDatabaseProductVersion() throws SQLException { + return ""; + } + + @Override + public String getDriverName() throws SQLException { + return ""; + } + + @Override + public String getDriverVersion() throws SQLException { + return ""; + } + + @Override + public int getDriverMajorVersion() { + return 0; + } + + @Override + public int getDriverMinorVersion() { + return 0; + } + + @Override + public boolean usesLocalFiles() throws SQLException { + return false; + } + + @Override + public boolean usesLocalFilePerTable() throws SQLException { + return false; + } + + @Override + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesUpperCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesLowerCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesMixedCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public String getIdentifierQuoteString() throws SQLException { + return "\""; + } + + @Override + public String getSQLKeywords() throws SQLException { + return ""; + } + + @Override + public String getNumericFunctions() throws SQLException { + return ""; + } + + @Override + public String getStringFunctions() throws SQLException { + return ""; + } + + @Override + public String getSystemFunctions() throws SQLException { + return ""; + } + + @Override + public String getTimeDateFunctions() throws SQLException { + return ""; + } + + @Override + public String getSearchStringEscape() throws SQLException { + return ""; + } + + @Override + public String getExtraNameCharacters() throws SQLException { + return ""; + } + + @Override + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return false; + } + + @Override + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return false; + } + + @Override + public boolean supportsColumnAliasing() throws SQLException { + return false; + } + + @Override + public boolean nullPlusNonNullIsNull() throws SQLException { + return false; + } + + @Override + public boolean supportsConvert() throws SQLException { + return false; + } + + @Override + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + @Override + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + @Override + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + @Override + public boolean supportsExpressionsInOrderBy() throws SQLException { + return false; + } + + @Override + public boolean supportsOrderByUnrelated() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupBy() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupByUnrelated() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupByBeyondSelect() throws SQLException { + return false; + } + + @Override + public boolean supportsLikeEscapeClause() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsNonNullableColumns() throws SQLException { + return false; + } + + @Override + public boolean supportsMinimumSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsCoreSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsExtendedSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } + + @Override + public boolean supportsOuterJoins() throws SQLException { + return false; + } + + @Override + public boolean supportsFullOuterJoins() throws SQLException { + return false; + } + + @Override + public boolean supportsLimitedOuterJoins() throws SQLException { + return false; + } + + @Override + public String getSchemaTerm() throws SQLException { + return ""; + } + + @Override + public String getProcedureTerm() throws SQLException { + return ""; + } + + @Override + public String getCatalogTerm() throws SQLException { + return ""; + } + + @Override + public boolean isCatalogAtStart() throws SQLException { + return false; + } + + @Override + public String getCatalogSeparator() throws SQLException { + return ""; + } + + @Override + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsPositionedDelete() throws SQLException { + return false; + } + + @Override + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + @Override + public boolean supportsSelectForUpdate() throws SQLException { + return false; + } + + @Override + public boolean supportsStoredProcedures() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInComparisons() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInExists() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInIns() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return false; + } + + @Override + public boolean supportsCorrelatedSubqueries() throws SQLException { + return false; + } + + @Override + public boolean supportsUnion() throws SQLException { + return false; + } + + @Override + public boolean supportsUnionAll() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return false; + } + + @Override + public int getMaxBinaryLiteralLength() throws SQLException { + return 0; + } + + @Override + public int getMaxCharLiteralLength() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInGroupBy() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInIndex() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInOrderBy() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInSelect() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInTable() throws SQLException { + return 0; + } + + @Override + public int getMaxConnections() throws SQLException { + return 0; + } + + @Override + public int getMaxCursorNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxIndexLength() throws SQLException { + return 0; + } + + @Override + public int getMaxSchemaNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxProcedureNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxCatalogNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxRowSize() throws SQLException { + return 0; + } + + @Override + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } + + @Override + public int getMaxStatementLength() throws SQLException { + return 0; + } + + @Override + public int getMaxStatements() throws SQLException { + return 0; + } + + @Override + public int getMaxTableNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxTablesInSelect() throws SQLException { + return 0; + } + + @Override + public int getMaxUserNameLength() throws SQLException { + return 0; + } + + @Override + public int getDefaultTransactionIsolation() throws SQLException { + return 0; + } + + @Override + public boolean supportsTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + return false; + } + + @Override + public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + return false; + } + + @Override + public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + return false; + } + + @Override + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return false; + } + + @Override + public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException { + return null; + } + + @Override + public ResultSet getSchemas() throws SQLException { + return null; + } + + @Override + public ResultSet getCatalogs() throws SQLException { + return null; + } + + @Override + public ResultSet getTableTypes() throws SQLException { + return null; + } + + @Override + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { + return null; + } + + @Override + public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + return null; + } + + @Override + public ResultSet getTypeInfo() throws SQLException { + return null; + } + + @Override + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { + return null; + } + + @Override + public boolean supportsResultSetType(int type) throws SQLException { + return false; + } + + @Override + public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { + return false; + } + + @Override + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean insertsAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean supportsBatchUpdates() throws SQLException { + return false; + } + + @Override + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { + return null; + } + + @Override + public Connection getConnection() throws SQLException { + return null; + } + + @Override + public boolean supportsSavepoints() throws SQLException { + return false; + } + + @Override + public boolean supportsNamedParameters() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleOpenResults() throws SQLException { + return false; + } + + @Override + public boolean supportsGetGeneratedKeys() throws SQLException { + return false; + } + + @Override + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { + return null; + } + + @Override + public boolean supportsResultSetHoldability(int holdability) throws SQLException { + return false; + } + + @Override + public int getResultSetHoldability() throws SQLException { + return 0; + } + + @Override + public int getDatabaseMajorVersion() throws SQLException { + return 0; + } + + @Override + public int getDatabaseMinorVersion() throws SQLException { + return 0; + } + + @Override + public int getJDBCMajorVersion() throws SQLException { + return 0; + } + + @Override + public int getJDBCMinorVersion() throws SQLException { + return 0; + } + + @Override + public int getSQLStateType() throws SQLException { + return 0; + } + + @Override + public boolean locatorsUpdateCopy() throws SQLException { + return false; + } + + @Override + public boolean supportsStatementPooling() throws SQLException { + return false; + } + + @Override + public RowIdLifetime getRowIdLifetime() throws SQLException { + return null; + } + + @Override + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + return null; + } + + @Override + public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + return false; + } + + @Override + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return false; + } + + @Override + public ResultSet getClientInfoProperties() throws SQLException { + return null; + } + + @Override + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public boolean generatedKeyAlwaysReturned() throws SQLException { + return false; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } +} diff --git a/test/jdk/java/sql/testng/util/StubPreparedStatement.java b/test/jdk/java/sql/testng/util/StubPreparedStatement.java index 4e272bcee2d..a3b95a65f4e 100644 --- a/test/jdk/java/sql/testng/util/StubPreparedStatement.java +++ b/test/jdk/java/sql/testng/util/StubPreparedStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,25 +26,15 @@ import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; -import java.sql.Array; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Date; -import java.sql.NClob; -import java.sql.ParameterMetaData; -import java.sql.PreparedStatement; -import java.sql.Ref; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.RowId; -import java.sql.SQLException; -import java.sql.SQLXML; -import java.sql.Time; -import java.sql.Timestamp; +import java.sql.*; import java.util.Calendar; public class StubPreparedStatement extends StubStatement implements PreparedStatement{ + public StubPreparedStatement(StubConnection con) { + super(con); + } + @Override public ResultSet executeQuery() throws SQLException { throw new UnsupportedOperationException("Not supported yet."); @@ -319,5 +309,4 @@ public class StubPreparedStatement extends StubStatement implements PreparedStat public void setNClob(int parameterIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); } - } diff --git a/test/jdk/java/sql/testng/util/StubStatement.java b/test/jdk/java/sql/testng/util/StubStatement.java index df792e2e4fe..c8f6a3ac071 100644 --- a/test/jdk/java/sql/testng/util/StubStatement.java +++ b/test/jdk/java/sql/testng/util/StubStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,15 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; -import java.util.regex.Pattern; -import static java.util.stream.Collectors.joining; public class StubStatement implements Statement { + protected final Connection con; + + public StubStatement(StubConnection con) { + this.con = con; + } + @Override public ResultSet executeQuery(String sql) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); @@ -44,7 +48,7 @@ public class StubStatement implements Statement { @Override public void close() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + con.close(); } @Override @@ -169,7 +173,7 @@ public class StubStatement implements Statement { @Override public Connection getConnection() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return con; } @Override @@ -251,7 +255,4 @@ public class StubStatement implements Statement { public boolean isWrapperFor(Class iface) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); } - - - } diff --git a/test/jdk/java/text/Format/NumberFormat/Bug4944439.java b/test/jdk/java/text/Format/NumberFormat/Bug4944439.java index 561052e9a95..a13a36733e2 100644 --- a/test/jdk/java/text/Format/NumberFormat/Bug4944439.java +++ b/test/jdk/java/text/Format/NumberFormat/Bug4944439.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,22 +23,19 @@ /* * @test - * @bug 4944439 + * @bug 4944439 8372609 * @summary Confirm that numbers where all digits after the decimal separator are 0 * and which are between Long.MIN_VALUE and Long.MAX_VALUE are returned * as Long(not double). * @run junit Bug4944439 */ -import java.text.DecimalFormat; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Locale; import java.util.stream.Stream; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -47,21 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertInstanceOf; public class Bug4944439 { - // Save JVM default locale - private static final Locale savedLocale = Locale.getDefault(); - private static final DecimalFormat df = new DecimalFormat(); - - // Set JVM default locale to US for testing - @BeforeAll - static void initAll() { - Locale.setDefault(Locale.US); - } - - // Restore JVM default locale - @AfterAll - static void tearDownAll() { - Locale.setDefault(savedLocale); - } + private static final NumberFormat df = NumberFormat.getInstance(Locale.US); // Check return type and value returned by DecimalFormat.parse() for longs @ParameterizedTest diff --git a/test/jdk/java/util/concurrent/BlockingQueue/MissedPoll.java b/test/jdk/java/util/concurrent/BlockingQueue/MissedPoll.java new file mode 100644 index 00000000000..9eb39634ce6 --- /dev/null +++ b/test/jdk/java/util/concurrent/BlockingQueue/MissedPoll.java @@ -0,0 +1,78 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8371740 + * @summary Checks for poll() (or peek) returning null when an element must exist. + */ +import java.util.*; +import java.util.concurrent.*; + +public class MissedPoll { + public static void main(String... args) throws Throwable { + test(new LinkedTransferQueue<>()); + test(new LinkedBlockingQueue<>()); + test(new LinkedBlockingDeque<>()); + test(new ArrayBlockingQueue<>(10)); + } + + private static void test(BlockingQueue q) + throws ExecutionException, InterruptedException { + System.out.println(q.getClass()); + try (var pool = Executors.newCachedThreadPool()) { + var futures = new ArrayList>(); + var phaser = new Phaser(4) { + @Override + protected boolean onAdvance(int phase, int registeredParties) { + q.clear(); + return super.onAdvance(phase, registeredParties); + } + }; + for (var i = 0; i < 4; i++) { + futures.add(pool.submit(() -> { + int errors = 0; + for (int k = 0; k < 10; k++) { + for (int j = 0; j < 1000; j++) { + q.offer(j); + if (q.peek() == null) + ++errors; + if (q.poll() == null) + ++errors; + } + phaser.arriveAndAwaitAdvance(); + } + return errors; + })); + } + for (var future : futures) { + Integer res; + if ((res = future.get()) != 0) + throw new AssertionError("Expected 0 but got " + res); + } + } + if (!q.isEmpty()) + throw new AssertionError("Queue is not empty: " + q); + } +} diff --git a/test/jdk/java/util/concurrent/forkjoin/Starvation.java b/test/jdk/java/util/concurrent/forkjoin/Starvation.java index 8397e852ffa..d864fa0ba33 100644 --- a/test/jdk/java/util/concurrent/forkjoin/Starvation.java +++ b/test/jdk/java/util/concurrent/forkjoin/Starvation.java @@ -28,6 +28,7 @@ */ import java.util.concurrent.Callable; import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; import java.util.concurrent.atomic.AtomicInteger; public class Starvation { @@ -42,7 +43,7 @@ public class Starvation { while (count.get() == c) Thread.onSpinWait(); return null; }}; - public static void main(String[] args) throws Exception { + static void testSubmitExternalCallable() throws Exception { try (var pool = new ForkJoinPool(2)) { for (int i = 0; i < 100_000; i++) { var future1 = pool.submit(new AwaitCount(i)); @@ -53,4 +54,21 @@ public class Starvation { } } } + + static void testSubmitAdaptedCallable() throws Exception { + try (var pool = new ForkJoinPool(2)) { + for (int i = 0; i < 100_000; i++) { + var future1 = pool.submit(new AwaitCount(i)); + var future2 = pool.submit(ForkJoinTask.adapt(noop)); + future2.get(); + count.set(i + 1); + future1.get(); + } + } + } + + public static void main(String[] args) throws Exception { + testSubmitExternalCallable(); + testSubmitAdaptedCallable(); + } } diff --git a/test/jdk/javax/management/security/keystoreAgent b/test/jdk/javax/management/security/keystoreAgent index cfb02e00c38..ebb95dd0dfa 100644 Binary files a/test/jdk/javax/management/security/keystoreAgent and b/test/jdk/javax/management/security/keystoreAgent differ diff --git a/test/jdk/javax/management/security/keystoreClient b/test/jdk/javax/management/security/keystoreClient index f0e0b7f5718..2382154441d 100644 Binary files a/test/jdk/javax/management/security/keystoreClient and b/test/jdk/javax/management/security/keystoreClient differ diff --git a/test/jdk/javax/management/security/truststoreAgent b/test/jdk/javax/management/security/truststoreAgent index 5b5f698cb97..2382154441d 100644 Binary files a/test/jdk/javax/management/security/truststoreAgent and b/test/jdk/javax/management/security/truststoreAgent differ diff --git a/test/jdk/javax/management/security/truststoreClient b/test/jdk/javax/management/security/truststoreClient index f6a6a0098aa..ebb95dd0dfa 100644 Binary files a/test/jdk/javax/management/security/truststoreClient and b/test/jdk/javax/management/security/truststoreClient differ diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java b/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java index cb11b17ebb5..464bb00fe82 100644 --- a/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java +++ b/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java @@ -27,31 +27,60 @@ // /* - * @test + * @test id=tls12 * @bug 6668231 * @summary Presence of a critical subjectAltName causes JSSE's SunX509 to * fail trusted checks - * @run main/othervm CriticalSubjectAltName + * @library /test/lib + * @modules java.base/sun.security.x509 java.base/sun.security.util + * @run main/othervm CriticalSubjectAltName TLSv1.2 MD5withRSA * @author Xuelei Fan */ + /* - * This test depends on binary keystore, crisubn.jks and trusted.jks. Because - * JAVA keytool cannot generate X509 certificate with SubjectAltName extension, - * the certificates are generated with openssl toolkits and then imported into - * JAVA keystore. - * - * The crisubn.jks holds a private key entry and the corresponding X509 - * certificate issued with an empty Subject field, and a critical - * SubjectAltName extension. - * - * The trusted.jks holds the trusted certificate. + * @test id=tls13 + * @bug 6668231 + * @summary Presence of a critical subjectAltName causes JSSE's SunX509 to + * fail trusted checks + * @library /test/lib + * @modules java.base/sun.security.x509 java.base/sun.security.util + * @run main/othervm CriticalSubjectAltName TLSv1.3 SHA256withRSA + * @author Xuelei Fan */ -import java.io.*; -import java.net.*; -import javax.net.ssl.*; -import java.security.Security; + + +import jdk.test.lib.security.CertificateBuilder; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.OIDName; +import sun.security.x509.RFC822Name; +import sun.security.x509.SubjectAlternativeNameExtension; + + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManagerFactory; +import java.io.BufferedWriter; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.URL; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.List; + +import jdk.test.lib.security.SecurityUtils; public class CriticalSubjectAltName implements HostnameVerifier { /* @@ -70,20 +99,18 @@ public class CriticalSubjectAltName implements HostnameVerifier { /* * Where do we find the keystores? */ - static String pathToStores = "./"; - static String keyStoreFile = "crisubn.jks"; - static String trustStoreFile = "trusted.jks"; - static String passwd = "passphrase"; + public static final char[] PASSPHRASE = "passphrase".toCharArray(); /* * Is the server ready to serve? */ - volatile static boolean serverReady = false; + private final CountDownLatch serverReady = new CountDownLatch(1); + private final int SERVER_WAIT_SECS = 10; /* * Turn on SSL debugging? */ - static boolean debug = false; + static boolean debug = Boolean.getBoolean("test.debug"); /* * If the client or server is doing some kind of object creation @@ -101,17 +128,17 @@ public class CriticalSubjectAltName implements HostnameVerifier { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLServerSocketFactory sslssf = - (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + SSLContext ctx = createServerContext(); + SSLServerSocketFactory sslssf = ctx.getServerSocketFactory(); SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort); - sslServerSocket.setEnabledProtocols(new String[]{"TLSv1.2"}); + sslServerSocket.setEnabledProtocols(new String[]{protocol}); serverPort = sslServerSocket.getLocalPort(); /* * Signal Client, we're ready for his connect. */ - serverReady = true; + serverReady.countDown(); SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); OutputStream sslOS = sslSocket.getOutputStream(); @@ -122,6 +149,36 @@ public class CriticalSubjectAltName implements HostnameVerifier { sslSocket.close(); } + private SSLContext createServerContext() throws Exception { + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + ks.setCertificateEntry("Trusted Cert", trustedCert); + + Certificate[] chain = new Certificate[] {serverCert}; + ks.setKeyEntry("Server key", serverKeys.getPrivate(), + PASSPHRASE, chain); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ks); + + SSLContext ctx = SSLContext.getInstance(protocol); + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, PASSPHRASE); + ctx.init(kmf.getKeyManagers(), null, null); + return ctx; + } + + private SSLContext createClientContext() throws Exception { + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + ks.setCertificateEntry("Trusted Cert", trustedCert); + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ks); + SSLContext ctx = SSLContext.getInstance(protocol); + ctx.init(null, tmf.getTrustManagers(), null); + return ctx; + } + /* * Define the client side of the test. * @@ -130,15 +187,12 @@ public class CriticalSubjectAltName implements HostnameVerifier { */ void doClientSide() throws Exception { - /* - * Wait for server to get started. - */ - while (!serverReady) { - Thread.sleep(50); - } + serverReady.await(); + SSLContext ctx = createClientContext(); URL url = new URL("https://localhost:"+serverPort+"/index.html"); HttpsURLConnection urlc = (HttpsURLConnection)url.openConnection(); + urlc.setSSLSocketFactory(ctx.getSocketFactory()); urlc.setHostnameVerifier(this); urlc.getInputStream(); @@ -159,42 +213,73 @@ public class CriticalSubjectAltName implements HostnameVerifier { volatile Exception clientException = null; public static void main(String[] args) throws Exception { - // MD5 is used in this test case, don't disable MD5 algorithm. - Security.setProperty("jdk.certpath.disabledAlgorithms", - "MD2, RSA keySize < 1024"); - Security.setProperty("jdk.tls.disabledAlgorithms", - "SSLv3, RC4, DH keySize < 768"); + if (args[1].contains("MD5")) { + SecurityUtils.removeFromDisabledAlgs( + "jdk.certpath.disabledAlgorithms", List.of("MD5")); + SecurityUtils.removeFromDisabledTlsAlgs("MD5"); + } - String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; - - System.setProperty("javax.net.ssl.keyStore", keyFilename); - System.setProperty("javax.net.ssl.keyStorePassword", passwd); - System.setProperty("javax.net.ssl.trustStore", trustFilename); - System.setProperty("javax.net.ssl.trustStorePassword", passwd); - - if (debug) + if (debug) { System.setProperty("javax.net.debug", "all"); + } /* * Start the tests. */ - new CriticalSubjectAltName(); + new CriticalSubjectAltName(args[0], args[1]); } Thread clientThread = null; Thread serverThread = null; + private final String protocol; + private KeyPair serverKeys; + private X509Certificate trustedCert; + private X509Certificate serverCert; + + private void setupCertificates(String signatureAlg) throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + KeyPair caKeys = kpg.generateKeyPair(); + serverKeys = kpg.generateKeyPair(); + + trustedCert = CertificateBuilder.newCertificateBuilder( + "CN=Someone, O=Some Org, ST=Some-State, C=US", + caKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(true, true, -1) + .setOneHourValidity() + .build(null, caKeys.getPrivate(), signatureAlg); + if (debug) { + System.out.println("Trusted Certificate"); + CertificateBuilder.printCertificate(trustedCert, System.out); + } + + GeneralNames gns = new GeneralNames(); + gns.add(new GeneralName(new RFC822Name("example@openjdk.net"))); + gns.add(new GeneralName(new OIDName("1.2.3.4"))); + + serverCert = CertificateBuilder.newCertificateBuilder("", + serverKeys.getPublic(), caKeys.getPublic()) + .setOneHourValidity() + .addBasicConstraintsExt(false, false, -1) + .addExtension(new SubjectAlternativeNameExtension(true, gns)) + .setOneHourValidity() + .build(trustedCert, caKeys.getPrivate(), signatureAlg); + if (debug) { + System.out.println("Server Certificate"); + CertificateBuilder.printCertificate(serverCert, System.out); + } + } + /* * Primary constructor, used to drive remainder of the test. * * Fork off the other side, then do your work. */ - CriticalSubjectAltName() throws Exception { + CriticalSubjectAltName(String protocol, String signatureAlg) throws Exception { + this.protocol = protocol; + + setupCertificates(signatureAlg); + if (separateServerThread) { startServer(true); startClient(false); @@ -238,7 +323,7 @@ public class CriticalSubjectAltName implements HostnameVerifier { * Release the client, if not active already... */ System.err.println("Server died..."); - serverReady = true; + serverReady.countDown(); serverException = e; } } diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/crisubn.jks b/test/jdk/javax/net/ssl/HttpsURLConnection/crisubn.jks deleted file mode 100644 index aee7d9f3379..00000000000 Binary files a/test/jdk/javax/net/ssl/HttpsURLConnection/crisubn.jks and /dev/null differ diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/trusted.jks b/test/jdk/javax/net/ssl/HttpsURLConnection/trusted.jks deleted file mode 100644 index 0202bec1620..00000000000 Binary files a/test/jdk/javax/net/ssl/HttpsURLConnection/trusted.jks and /dev/null differ diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java index 95cc508828a..5bd10ed8848 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,6 @@ public class SQLInputImplTests extends BaseTest { private final String sqlType = "SUPERHERO"; @BeforeMethod - @Override public void setUpMethod() throws Exception { map = new HashMap<>(); impl = new TestSQLDataImpl("TestSQLData"); @@ -120,7 +119,6 @@ public class SQLInputImplTests extends BaseTest { SQLInputImpl sqli = new SQLInputImpl(values, map); Object o = sqli.readObject(); assertTrue(hero.equals(o)); - } /* @@ -204,8 +202,6 @@ public class SQLInputImplTests extends BaseTest { Object[] values = {struct}; SQLInputImpl sqli = new SQLInputImpl(values, map); Object o = sqli.readObject(); - assertTrue(hero.equals(o)); - } } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java index 00f62df6f79..1f90c9981a7 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,6 @@ public class SQLOutputImplTests extends BaseTest { private SQLOutputImpl outImpl; @BeforeMethod - @Override public void setUpMethod() throws Exception { results = new Vector(); impl = new TestSQLDataImpl("TestSQLData"); diff --git a/test/jdk/sun/java2d/marlin/ClipShapeTest.java b/test/jdk/sun/java2d/marlin/ClipShapeTest.java index 3bdbd416e63..e77fca6924d 100644 --- a/test/jdk/sun/java2d/marlin/ClipShapeTest.java +++ b/test/jdk/sun/java2d/marlin/ClipShapeTest.java @@ -154,13 +154,12 @@ public final class ClipShapeTest { static final AtomicBoolean isMarlin = new AtomicBoolean(); static final AtomicBoolean isClipRuntime = new AtomicBoolean(); + static final Logger log = Logger.getLogger("sun.java2d.marlin"); + static { Locale.setDefault(Locale.US); // FIRST: Get Marlin runtime state from its log: - - // initialize j.u.l Looger: - final Logger log = Logger.getLogger("sun.java2d.marlin"); log.addHandler(new Handler() { @Override public void publish(LogRecord record) { diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java index 4b2dece0c75..7204fac35d1 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java @@ -26,392 +26,44 @@ // system properties in samevm/agentvm mode. // -/* @test +/* @test id=tls12 * @bug 6766775 * @summary X509 certificate hostname checking is broken in JDK1.6.0_10 - * @run main/othervm DNSIdentities + * @library /test/lib + * @run main/othervm DNSIdentities TLSv1.2 MD5withRSA * @author Xuelei Fan */ -import java.net.*; -import java.util.*; -import java.io.*; -import javax.net.ssl.*; -import java.security.Security; -import java.security.KeyStore; -import java.security.KeyFactory; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; -import java.math.BigInteger; - -/* - * Certificates and key used in the test. - * - * TLS server certificate: - * server private key: - * -----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,D9AE407F6D0E389A - * - * WPrA7TFol/cQCcp9oHnXWNpYlvRbbIcQj0m+RKT2Iuzfus+DHt3Zadf8nJpKfX2e - * h2rnhlzCN9M7djRDooZKDOPCsdBn51Au7HlZF3S3Opgo7D8XFM1a8t1Je4ke14oI - * nw6QKYsBblRziPnP2PZ0zvX24nOv7bbY8beynlJHGs00VWSFdoH2DS0aE1p6D+3n - * ptJuJ75dVfZFK4X7162APlNXevX8D6PEQpSiRw1rjjGGcnvQ4HdWk3BxDVDcCNJb - * Y1aGNRxsjTDvPi3R9Qx2M+W03QzEPx4SR3ZHVskeSJHaetM0TM/w/45Paq4GokXP - * ZeTnbEx1xmjkA7h+t4doLL4watx5F6yLsJzu8xB3lt/1EtmkYtLz1t7X4BetPAXz - * zS69X/VwhKfsOI3qXBWuL2oHPyhDmT1gcaUQwEPSV6ogHEEQEDXdiUS8heNK13KF - * TCQYFkETvV2BLxUhV1hypPzRQ6tUpJiAbD5KmoK2lD9slshG2QtvKQq0/bgkDY5J - * LhDHV2dtcZ3kDPkkZXpbcJQvoeH3d09C5sIsuTFo2zgNR6oETHUc5TzP6FY2YYRa - * QcK5HcmtsRRiXFm01ac+aMejJUIujjFt84SiKWT/73vC8AmY4tYcJBLjCg4XIxSH - * fdDFLL1YZENNO5ivlp8mdiHqcawx+36L7DrEZQ8RZt6cqST5t/+XTdM74s6k81GT - * pNsa82P2K2zmIUZ/DL2mKjW1vfRByw1NQFEBkN3vdyZxYfM/JyUzX4hbjXBEkh9Q - * QYrcwLKLjis2QzSvK04B3bvRzRb+4ocWiso8ZPAXAIxZFBWDpTMM2A== - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICXAIBAAKBgQClrFscN6LdmYktsnm4j9VIpecchBeNaZzGrG358h0fORna03Ie - * buxEzHCk3LoAMPagTz1UemFqzFfQCn+VKBg/mtmU8hvIJIh+/p0PPftXUwizIDPU - * PxdHFNHN6gjYDnVOr77M0uyvqXpJ38LZrLgkQJCmA1Yq0DAFQCxPq9l0iQIDAQAB - * AoGAbqcbg1E1mkR99uOJoNeQYKFOJyGiiXTMnXV1TseC4+PDfQBU7Dax35GcesBi - * CtapIpFKKS5D+ozY6b7ZT8ojxuQ/uHLPAvz0WDR3ds4iRF8tyu71Q1ZHcQsJa17y - * yO7UbkSSKn/Mp9Rb+/dKqftUGNXVFLqgHBOzN2s3We3bbbECQQDYBPKOg3hkaGHo - * OhpHKqtQ6EVkldihG/3i4WejRonelXN+HRh1KrB2HBx0M8D/qAzP1i3rNSlSHer4 - * 59YRTJnHAkEAxFX/sVYSn07BHv9Zhn6XXct/Cj43z/tKNbzlNbcxqQwQerw3IH51 - * 8UH2YOA+GD3lXbKp+MytoFLWv8zg4YT/LwJAfqan75Z1R6lLffRS49bIiq8jwE16 - * rTrUJ+kv8jKxMqc9B3vXkxpsS1M/+4E8bqgAmvpgAb8xcsvHsBd9ErdukQJBAKs2 - * j67W75BrPjBI34pQ1LEfp56IGWXOrq1kF8IbCjxv3+MYRT6Z6UJFkpRymNPNDjsC - * dgUYgITiGJHUGXuw3lMCQHEHqo9ZtXz92yFT+VhsNc29B8m/sqUJdtCcMd/jGpAF - * u6GHufjqIZBpQsk63wbwESAPZZ+kk1O1kS5GIRLX608= - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * publicExponent: 65537 (0x10001) - * privateExponent: - * 6e:a7:1b:83:51:35:9a:44:7d:f6:e3:89:a0:d7:90: - * 60:a1:4e:27:21:a2:89:74:cc:9d:75:75:4e:c7:82: - * e3:e3:c3:7d:00:54:ec:36:b1:df:91:9c:7a:c0:62: - * 0a:d6:a9:22:91:4a:29:2e:43:fa:8c:d8:e9:be:d9: - * 4f:ca:23:c6:e4:3f:b8:72:cf:02:fc:f4:58:34:77: - * 76:ce:22:44:5f:2d:ca:ee:f5:43:56:47:71:0b:09: - * 6b:5e:f2:c8:ee:d4:6e:44:92:2a:7f:cc:a7:d4:5b: - * fb:f7:4a:a9:fb:54:18:d5:d5:14:ba:a0:1c:13:b3: - * 37:6b:37:59:ed:db:6d:b1 - * prime1: - * 00:d8:04:f2:8e:83:78:64:68:61:e8:3a:1a:47:2a: - * ab:50:e8:45:64:95:d8:a1:1b:fd:e2:e1:67:a3:46: - * 89:de:95:73:7e:1d:18:75:2a:b0:76:1c:1c:74:33: - * c0:ff:a8:0c:cf:d6:2d:eb:35:29:52:1d:ea:f8:e7: - * d6:11:4c:99:c7 - * prime2: - * 00:c4:55:ff:b1:56:12:9f:4e:c1:1e:ff:59:86:7e: - * 97:5d:cb:7f:0a:3e:37:cf:fb:4a:35:bc:e5:35:b7: - * 31:a9:0c:10:7a:bc:37:20:7e:75:f1:41:f6:60:e0: - * 3e:18:3d:e5:5d:b2:a9:f8:cc:ad:a0:52:d6:bf:cc: - * e0:e1:84:ff:2f - * exponent1: - * 7e:a6:a7:ef:96:75:47:a9:4b:7d:f4:52:e3:d6:c8: - * 8a:af:23:c0:4d:7a:ad:3a:d4:27:e9:2f:f2:32:b1: - * 32:a7:3d:07:7b:d7:93:1a:6c:4b:53:3f:fb:81:3c: - * 6e:a8:00:9a:fa:60:01:bf:31:72:cb:c7:b0:17:7d: - * 12:b7:6e:91 - * exponent2: - * 00:ab:36:8f:ae:d6:ef:90:6b:3e:30:48:df:8a:50: - * d4:b1:1f:a7:9e:88:19:65:ce:ae:ad:64:17:c2:1b: - * 0a:3c:6f:df:e3:18:45:3e:99:e9:42:45:92:94:72: - * 98:d3:cd:0e:3b:02:76:05:18:80:84:e2:18:91:d4: - * 19:7b:b0:de:53 - * coefficient: - * 71:07:aa:8f:59:b5:7c:fd:db:21:53:f9:58:6c:35: - * cd:bd:07:c9:bf:b2:a5:09:76:d0:9c:31:df:e3:1a: - * 90:05:bb:a1:87:b9:f8:ea:21:90:69:42:c9:3a:df: - * 06:f0:11:20:0f:65:9f:a4:93:53:b5:91:2e:46:21: - * 12:d7:eb:4f - * - * - * server certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 8 (0x8) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:43:04 2008 GMT - * Not After : Aug 25 03:43:04 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Server, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * ED:6E:DB:F4:B5:56:C8:FB:1A:06:61:3F:0F:08:BB:A6:04:D8:16:54 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * DNS:localhost - * Signature Algorithm: md5WithRSAEncryption0 - * - * -----BEGIN CERTIFICATE----- - * MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3 - * ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6 - * YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS - * 7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh - * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac - * PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi - * nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn - * JqCpf5uZGOo= - * -----END CERTIFICATE----- - * - * - * TLS client certificate: - * client private key: - * ----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,FA2A435CD35A9390 - * - * Z+Y2uaETbsUWIyJUyVu1UV2G4rgFYJyACZT6Tp1KjRtxflSh2kXkJ9MpuXMXA0V4 - * Yy3fDzPqCL9NJmQAYRlAx/W/+j4F5EyMWDIx8fUxzONRZyoiwF7jLm+KscAfv6Pf - * q7ItWOdj3z7IYrwlB8YIGd3F2cDKT3S+lYRk7rKb/qT7itbuHnY4Ardh3yl+MZak - * jBp+ELUlRsUqSr1V0LoM+0rCCykarpyfhpxEcqsrl0v9Cyi5uhU50/oKv5zql3SH - * l2ImgDjp3batAs8+Bd4NF2aqi0a7Hy44JUHxRm4caZryU/i/D9N1MbuM6882HLat - * 5N0G+NaIUfywa8mjwq2D5aiit18HqKA6XeRRYeJ5Dvu9DCO4GeFSwcUFIBMI0L46 - * 7s114+oDodg57pMgITi+04vmUxvqlN9aiyd7f5Fgd7PeHGeOdbMz1NaJLJaPI9++ - * NakK8eK9iwT/Gdq0Uap5/CHW7vCT5PO+h3HY0STH0lWStXhdWnFO04zTdywsbSp+ - * DLpHeFT66shfeUlxR0PsCbG9vPRt/QmGLeYQZITppWo/ylSq4j+pRIuXvuWHdBRN - * rTZ8QF4Y7AxQUXVz1j1++s6ZMHTzaK2i9HrhmDs1MbJl+QwWre3Xpv3LvTVz3k5U - * wX8kuY1m3STt71QCaRWENq5sRaMImLxZbxc/ivFl9RAzUqo4NCxLod/QgA4iLqtO - * ztnlpzwlC/F8HbQ1oqYWwnZAPhzU/cULtstl+Yrws2c2atO323LbPXZqbASySgig - * sNpFXQMObdfP6LN23bY+1SvtK7V4NUTNhpdIc6INQAQ= - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICWwIBAAKBgQC78EA2rCZUTvSjWgAvaSFvuXo6k+yi9uGOx2PYLxIwmS6w8o/4 - * Jy0keCiE9wG/jUR53TvSVfPOPLJbIX3v/TNKsaP/xsibuQ98QTWX+ds6BWAFFa9Z - * F5KjEK0WHOQHU6+odqJWKpLT+SjgeM9eH0irXBnd4WdDunWN9YKsQ5JEGwIDAQAB - * AoGAEbdqNj0wN85hnWyEi/ObJU8UyKTdL9eaF72QGfcF/fLSxfd3vurihIeXOkGW - * tpn4lIxYcVGM9CognhqgJpl11jFTQzn1KqZ+NEJRKkCHA4hDabKJbSC9fXHvRwrf - * BsFpZqgiNxp3HseUTiwnaUVeyPgMt/jAj5nB5Sib+UyUxrECQQDnNQBiF2aifEg6 - * zbJOOC7he5CHAdkFxSxWVFVHL6EfXfqdLVkUohMbgZv+XxyIeU2biOExSg49Kds3 - * FOKgTau1AkEA0Bd1haj6QuCo8I0AXm2WO+MMTZMTvtHD/bGjKNM+fT4I8rKYnQRX - * 1acHdqS9Xx2rNJqZgkMmpESIdPR2fc4yjwJALFeM6EMmqvj8/VIf5UJ/Mz14fXwM - * PEARfckUxd9LnnFutCBTWlKvKXJVEZb6KO5ixPaegc57Jp3Vbh3yTN44lQJADD/1 - * SSMDaIB1MYP7a5Oj7m6VQNPRq8AJe5vDcRnOae0G9dKRrVyeFxO4GsHj6/+BHp2j - * P8nYMn9eURQ7DXjf/QJAAQzMlWnKGSO8pyTDtnQx3hRMoUkOEhmNq4bQhLkYqtnY - * FcqpUQ2qMjW+NiNWk5HnTrMS3L9EdJobMUzaNZLy4w== - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * publicExponent: 65537 (0x10001) - * privateExponent: - * 11:b7:6a:36:3d:30:37:ce:61:9d:6c:84:8b:f3:9b: - * 25:4f:14:c8:a4:dd:2f:d7:9a:17:bd:90:19:f7:05: - * fd:f2:d2:c5:f7:77:be:ea:e2:84:87:97:3a:41:96: - * b6:99:f8:94:8c:58:71:51:8c:f4:2a:20:9e:1a:a0: - * 26:99:75:d6:31:53:43:39:f5:2a:a6:7e:34:42:51: - * 2a:40:87:03:88:43:69:b2:89:6d:20:bd:7d:71:ef: - * 47:0a:df:06:c1:69:66:a8:22:37:1a:77:1e:c7:94: - * 4e:2c:27:69:45:5e:c8:f8:0c:b7:f8:c0:8f:99:c1: - * e5:28:9b:f9:4c:94:c6:b1 - * prime1: - * 00:e7:35:00:62:17:66:a2:7c:48:3a:cd:b2:4e:38: - * 2e:e1:7b:90:87:01:d9:05:c5:2c:56:54:55:47:2f: - * a1:1f:5d:fa:9d:2d:59:14:a2:13:1b:81:9b:fe:5f: - * 1c:88:79:4d:9b:88:e1:31:4a:0e:3d:29:db:37:14: - * e2:a0:4d:ab:b5 - * prime2: - * 00:d0:17:75:85:a8:fa:42:e0:a8:f0:8d:00:5e:6d: - * 96:3b:e3:0c:4d:93:13:be:d1:c3:fd:b1:a3:28:d3: - * 3e:7d:3e:08:f2:b2:98:9d:04:57:d5:a7:07:76:a4: - * bd:5f:1d:ab:34:9a:99:82:43:26:a4:44:88:74:f4: - * 76:7d:ce:32:8f - * exponent1: - * 2c:57:8c:e8:43:26:aa:f8:fc:fd:52:1f:e5:42:7f: - * 33:3d:78:7d:7c:0c:3c:40:11:7d:c9:14:c5:df:4b: - * 9e:71:6e:b4:20:53:5a:52:af:29:72:55:11:96:fa: - * 28:ee:62:c4:f6:9e:81:ce:7b:26:9d:d5:6e:1d:f2: - * 4c:de:38:95 - * exponent2: - * 0c:3f:f5:49:23:03:68:80:75:31:83:fb:6b:93:a3: - * ee:6e:95:40:d3:d1:ab:c0:09:7b:9b:c3:71:19:ce: - * 69:ed:06:f5:d2:91:ad:5c:9e:17:13:b8:1a:c1:e3: - * eb:ff:81:1e:9d:a3:3f:c9:d8:32:7f:5e:51:14:3b: - * 0d:78:df:fd - * coefficient: - * 01:0c:cc:95:69:ca:19:23:bc:a7:24:c3:b6:74:31: - * de:14:4c:a1:49:0e:12:19:8d:ab:86:d0:84:b9:18: - * aa:d9:d8:15:ca:a9:51:0d:aa:32:35:be:36:23:56: - * 93:91:e7:4e:b3:12:dc:bf:44:74:9a:1b:31:4c:da: - * 35:92:f2:e3 - * - * client certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 9 (0x9) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:43:24 2008 GMT - * Not After : Aug 25 03:43:24 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * DNS:localhost - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas - * JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV - * 8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq - * ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh - * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F - * HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj - * XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN - * cl/epUcHL7E= - * -----END CERTIFICATE----- - * - * - * - * Trusted CA certificate: - * Certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 0 (0x0) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 02:43:36 2008 GMT - * Not After : Aug 25 02:43:36 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: - * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: - * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: - * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: - * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: - * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: - * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: - * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: - * 89:2a:95:12:4c:d8:09:2a:e9 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Subject Key Identifier: - * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org - * serial:00 - * - * X509v3 Basic Constraints: - * CA:TRUE - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB - * gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX - * 4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj - * 7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G - * A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ - * hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt - * U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw - * DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA - * ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ - * LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P - * 6Mvf0r1PNTY2hwTJLJmKtg== - * -----END CERTIFICATE--- +/* @test id=tls13 + * @bug 6766775 + * @summary X509 certificate hostname checking is broken in JDK1.6.0_10 + * @library /test/lib + * @run main/othervm DNSIdentities TLSv1.3 SHA256withRSA + * @author Xuelei Fan */ +import jdk.test.lib.security.CertificateBuilder; +import jdk.test.lib.security.SecurityUtils; +import sun.security.x509.DNSName; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.SubjectAlternativeNameExtension; -public class DNSIdentities { - static Map cookies; - ServerSocket ss; - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.util.List; + +public class DNSIdentities extends IdentitiesBase { /* * Should we run the client or server in a separate thread? * Both sides can throw exceptions, but do you have a preference @@ -419,209 +71,6 @@ public class DNSIdentities { */ static boolean separateServerThread = true; - /* - * Where do we find the keystores? - */ - static String trusedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + - "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + - "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + - "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + - "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + - "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + - "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + - "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + - "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + - "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + - "6Mvf0r1PNTY2hwTJLJmKtg==\n" + - "-----END CERTIFICATE-----"; - - static String serverCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3\n" + - "ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6\n" + - "YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS\n" + - "7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" + - "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac\n" + - "PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi\n" + - "nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn\n" + - "JqCpf5uZGOo=\n" + - "-----END CERTIFICATE-----"; - - static String clientCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + - "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + - "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + - "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" + - "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F\n" + - "HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj\n" + - "XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN\n" + - "cl/epUcHL7E=\n" + - "-----END CERTIFICATE-----"; - - static byte serverPrivateExponent[] = { - (byte)0x6e, (byte)0xa7, (byte)0x1b, (byte)0x83, - (byte)0x51, (byte)0x35, (byte)0x9a, (byte)0x44, - (byte)0x7d, (byte)0xf6, (byte)0xe3, (byte)0x89, - (byte)0xa0, (byte)0xd7, (byte)0x90, (byte)0x60, - (byte)0xa1, (byte)0x4e, (byte)0x27, (byte)0x21, - (byte)0xa2, (byte)0x89, (byte)0x74, (byte)0xcc, - (byte)0x9d, (byte)0x75, (byte)0x75, (byte)0x4e, - (byte)0xc7, (byte)0x82, (byte)0xe3, (byte)0xe3, - (byte)0xc3, (byte)0x7d, (byte)0x00, (byte)0x54, - (byte)0xec, (byte)0x36, (byte)0xb1, (byte)0xdf, - (byte)0x91, (byte)0x9c, (byte)0x7a, (byte)0xc0, - (byte)0x62, (byte)0x0a, (byte)0xd6, (byte)0xa9, - (byte)0x22, (byte)0x91, (byte)0x4a, (byte)0x29, - (byte)0x2e, (byte)0x43, (byte)0xfa, (byte)0x8c, - (byte)0xd8, (byte)0xe9, (byte)0xbe, (byte)0xd9, - (byte)0x4f, (byte)0xca, (byte)0x23, (byte)0xc6, - (byte)0xe4, (byte)0x3f, (byte)0xb8, (byte)0x72, - (byte)0xcf, (byte)0x02, (byte)0xfc, (byte)0xf4, - (byte)0x58, (byte)0x34, (byte)0x77, (byte)0x76, - (byte)0xce, (byte)0x22, (byte)0x44, (byte)0x5f, - (byte)0x2d, (byte)0xca, (byte)0xee, (byte)0xf5, - (byte)0x43, (byte)0x56, (byte)0x47, (byte)0x71, - (byte)0x0b, (byte)0x09, (byte)0x6b, (byte)0x5e, - (byte)0xf2, (byte)0xc8, (byte)0xee, (byte)0xd4, - (byte)0x6e, (byte)0x44, (byte)0x92, (byte)0x2a, - (byte)0x7f, (byte)0xcc, (byte)0xa7, (byte)0xd4, - (byte)0x5b, (byte)0xfb, (byte)0xf7, (byte)0x4a, - (byte)0xa9, (byte)0xfb, (byte)0x54, (byte)0x18, - (byte)0xd5, (byte)0xd5, (byte)0x14, (byte)0xba, - (byte)0xa0, (byte)0x1c, (byte)0x13, (byte)0xb3, - (byte)0x37, (byte)0x6b, (byte)0x37, (byte)0x59, - (byte)0xed, (byte)0xdb, (byte)0x6d, (byte)0xb1 - }; - - static byte serverModulus[] = { - (byte)0x00, - (byte)0xa5, (byte)0xac, (byte)0x5b, (byte)0x1c, - (byte)0x37, (byte)0xa2, (byte)0xdd, (byte)0x99, - (byte)0x89, (byte)0x2d, (byte)0xb2, (byte)0x79, - (byte)0xb8, (byte)0x8f, (byte)0xd5, (byte)0x48, - (byte)0xa5, (byte)0xe7, (byte)0x1c, (byte)0x84, - (byte)0x17, (byte)0x8d, (byte)0x69, (byte)0x9c, - (byte)0xc6, (byte)0xac, (byte)0x6d, (byte)0xf9, - (byte)0xf2, (byte)0x1d, (byte)0x1f, (byte)0x39, - (byte)0x19, (byte)0xda, (byte)0xd3, (byte)0x72, - (byte)0x1e, (byte)0x6e, (byte)0xec, (byte)0x44, - (byte)0xcc, (byte)0x70, (byte)0xa4, (byte)0xdc, - (byte)0xba, (byte)0x00, (byte)0x30, (byte)0xf6, - (byte)0xa0, (byte)0x4f, (byte)0x3d, (byte)0x54, - (byte)0x7a, (byte)0x61, (byte)0x6a, (byte)0xcc, - (byte)0x57, (byte)0xd0, (byte)0x0a, (byte)0x7f, - (byte)0x95, (byte)0x28, (byte)0x18, (byte)0x3f, - (byte)0x9a, (byte)0xd9, (byte)0x94, (byte)0xf2, - (byte)0x1b, (byte)0xc8, (byte)0x24, (byte)0x88, - (byte)0x7e, (byte)0xfe, (byte)0x9d, (byte)0x0f, - (byte)0x3d, (byte)0xfb, (byte)0x57, (byte)0x53, - (byte)0x08, (byte)0xb3, (byte)0x20, (byte)0x33, - (byte)0xd4, (byte)0x3f, (byte)0x17, (byte)0x47, - (byte)0x14, (byte)0xd1, (byte)0xcd, (byte)0xea, - (byte)0x08, (byte)0xd8, (byte)0x0e, (byte)0x75, - (byte)0x4e, (byte)0xaf, (byte)0xbe, (byte)0xcc, - (byte)0xd2, (byte)0xec, (byte)0xaf, (byte)0xa9, - (byte)0x7a, (byte)0x49, (byte)0xdf, (byte)0xc2, - (byte)0xd9, (byte)0xac, (byte)0xb8, (byte)0x24, - (byte)0x40, (byte)0x90, (byte)0xa6, (byte)0x03, - (byte)0x56, (byte)0x2a, (byte)0xd0, (byte)0x30, - (byte)0x05, (byte)0x40, (byte)0x2c, (byte)0x4f, - (byte)0xab, (byte)0xd9, (byte)0x74, (byte)0x89 - }; - - static byte clientPrivateExponent[] = { - (byte)0x11, (byte)0xb7, (byte)0x6a, (byte)0x36, - (byte)0x3d, (byte)0x30, (byte)0x37, (byte)0xce, - (byte)0x61, (byte)0x9d, (byte)0x6c, (byte)0x84, - (byte)0x8b, (byte)0xf3, (byte)0x9b, (byte)0x25, - (byte)0x4f, (byte)0x14, (byte)0xc8, (byte)0xa4, - (byte)0xdd, (byte)0x2f, (byte)0xd7, (byte)0x9a, - (byte)0x17, (byte)0xbd, (byte)0x90, (byte)0x19, - (byte)0xf7, (byte)0x05, (byte)0xfd, (byte)0xf2, - (byte)0xd2, (byte)0xc5, (byte)0xf7, (byte)0x77, - (byte)0xbe, (byte)0xea, (byte)0xe2, (byte)0x84, - (byte)0x87, (byte)0x97, (byte)0x3a, (byte)0x41, - (byte)0x96, (byte)0xb6, (byte)0x99, (byte)0xf8, - (byte)0x94, (byte)0x8c, (byte)0x58, (byte)0x71, - (byte)0x51, (byte)0x8c, (byte)0xf4, (byte)0x2a, - (byte)0x20, (byte)0x9e, (byte)0x1a, (byte)0xa0, - (byte)0x26, (byte)0x99, (byte)0x75, (byte)0xd6, - (byte)0x31, (byte)0x53, (byte)0x43, (byte)0x39, - (byte)0xf5, (byte)0x2a, (byte)0xa6, (byte)0x7e, - (byte)0x34, (byte)0x42, (byte)0x51, (byte)0x2a, - (byte)0x40, (byte)0x87, (byte)0x03, (byte)0x88, - (byte)0x43, (byte)0x69, (byte)0xb2, (byte)0x89, - (byte)0x6d, (byte)0x20, (byte)0xbd, (byte)0x7d, - (byte)0x71, (byte)0xef, (byte)0x47, (byte)0x0a, - (byte)0xdf, (byte)0x06, (byte)0xc1, (byte)0x69, - (byte)0x66, (byte)0xa8, (byte)0x22, (byte)0x37, - (byte)0x1a, (byte)0x77, (byte)0x1e, (byte)0xc7, - (byte)0x94, (byte)0x4e, (byte)0x2c, (byte)0x27, - (byte)0x69, (byte)0x45, (byte)0x5e, (byte)0xc8, - (byte)0xf8, (byte)0x0c, (byte)0xb7, (byte)0xf8, - (byte)0xc0, (byte)0x8f, (byte)0x99, (byte)0xc1, - (byte)0xe5, (byte)0x28, (byte)0x9b, (byte)0xf9, - (byte)0x4c, (byte)0x94, (byte)0xc6, (byte)0xb1 - }; - - static byte clientModulus[] = { - (byte)0x00, - (byte)0xbb, (byte)0xf0, (byte)0x40, (byte)0x36, - (byte)0xac, (byte)0x26, (byte)0x54, (byte)0x4e, - (byte)0xf4, (byte)0xa3, (byte)0x5a, (byte)0x00, - (byte)0x2f, (byte)0x69, (byte)0x21, (byte)0x6f, - (byte)0xb9, (byte)0x7a, (byte)0x3a, (byte)0x93, - (byte)0xec, (byte)0xa2, (byte)0xf6, (byte)0xe1, - (byte)0x8e, (byte)0xc7, (byte)0x63, (byte)0xd8, - (byte)0x2f, (byte)0x12, (byte)0x30, (byte)0x99, - (byte)0x2e, (byte)0xb0, (byte)0xf2, (byte)0x8f, - (byte)0xf8, (byte)0x27, (byte)0x2d, (byte)0x24, - (byte)0x78, (byte)0x28, (byte)0x84, (byte)0xf7, - (byte)0x01, (byte)0xbf, (byte)0x8d, (byte)0x44, - (byte)0x79, (byte)0xdd, (byte)0x3b, (byte)0xd2, - (byte)0x55, (byte)0xf3, (byte)0xce, (byte)0x3c, - (byte)0xb2, (byte)0x5b, (byte)0x21, (byte)0x7d, - (byte)0xef, (byte)0xfd, (byte)0x33, (byte)0x4a, - (byte)0xb1, (byte)0xa3, (byte)0xff, (byte)0xc6, - (byte)0xc8, (byte)0x9b, (byte)0xb9, (byte)0x0f, - (byte)0x7c, (byte)0x41, (byte)0x35, (byte)0x97, - (byte)0xf9, (byte)0xdb, (byte)0x3a, (byte)0x05, - (byte)0x60, (byte)0x05, (byte)0x15, (byte)0xaf, - (byte)0x59, (byte)0x17, (byte)0x92, (byte)0xa3, - (byte)0x10, (byte)0xad, (byte)0x16, (byte)0x1c, - (byte)0xe4, (byte)0x07, (byte)0x53, (byte)0xaf, - (byte)0xa8, (byte)0x76, (byte)0xa2, (byte)0x56, - (byte)0x2a, (byte)0x92, (byte)0xd3, (byte)0xf9, - (byte)0x28, (byte)0xe0, (byte)0x78, (byte)0xcf, - (byte)0x5e, (byte)0x1f, (byte)0x48, (byte)0xab, - (byte)0x5c, (byte)0x19, (byte)0xdd, (byte)0xe1, - (byte)0x67, (byte)0x43, (byte)0xba, (byte)0x75, - (byte)0x8d, (byte)0xf5, (byte)0x82, (byte)0xac, - (byte)0x43, (byte)0x92, (byte)0x44, (byte)0x1b - }; - - static char passphrase[] = "passphrase".toCharArray(); /* * Is the server ready to serve? @@ -640,6 +89,20 @@ public class DNSIdentities { private SSLServerSocket sslServerSocket = null; + @Override + protected CertificateBuilder customizeServerCert(CertificateBuilder builder) throws Exception { + GeneralNames gns = new GeneralNames(); + gns.add(new GeneralName(new DNSName("localhost"))); + return builder.addExtension(new SubjectAlternativeNameExtension(true, gns)); + } + + @Override + protected CertificateBuilder customizeClientCert(CertificateBuilder builder) throws Exception { + GeneralNames gns = new GeneralNames(); + gns.add(new GeneralName(new DNSName("localhost"))); + return builder.addExtension(new SubjectAlternativeNameExtension(true, gns)); + } + /* * Define the server side of the test. * @@ -647,8 +110,7 @@ public class DNSIdentities { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLContext context = getSSLContext(trusedCertStr, serverCertStr, - serverModulus, serverPrivateExponent, passphrase); + SSLContext context = getServerSSLContext(); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); // doClientSide() connects to "localhost" @@ -703,8 +165,7 @@ public class DNSIdentities { void doClientSide() throws Exception { SSLContext reservedSSLContext = SSLContext.getDefault(); try { - SSLContext context = getSSLContext(trusedCertStr, clientCertStr, - clientModulus, clientPrivateExponent, passphrase); + SSLContext context = getClientSSLContext(); SSLContext.setDefault(context); @@ -748,12 +209,12 @@ public class DNSIdentities { volatile Exception serverException = null; volatile Exception clientException = null; - public static void main(String args[]) throws Exception { - // MD5 is used in this test case, don't disable MD5 algorithm. - Security.setProperty("jdk.certpath.disabledAlgorithms", - "MD2, RSA keySize < 1024"); - Security.setProperty("jdk.tls.disabledAlgorithms", - "SSLv3, RC4, DH keySize < 768"); + public static void main(String [] args) throws Exception { + if (args[1].contains("MD5")) { + SecurityUtils.removeFromDisabledAlgs( + "jdk.certpath.disabledAlgorithms", List.of("MD5")); + SecurityUtils.removeFromDisabledTlsAlgs("MD5"); + } if (debug) System.setProperty("javax.net.debug", "all"); @@ -761,7 +222,7 @@ public class DNSIdentities { /* * Start the tests. */ - new DNSIdentities(); + new DNSIdentities(args[0], args[1]); } Thread clientThread = null; @@ -771,7 +232,8 @@ public class DNSIdentities { * * Fork off the other side, then do your work. */ - DNSIdentities() throws Exception { + DNSIdentities(String protocol, String signatureAlg) throws Exception { + super(protocol, signatureAlg); if (separateServerThread) { startServer(true); startClient(false); @@ -846,65 +308,4 @@ public class DNSIdentities { doClientSide(); } } - - // get the ssl context - private static SSLContext getSSLContext(String trusedCertStr, - String keyCertStr, byte[] modulus, - byte[] privateExponent, char[] passphrase) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - ByteArrayInputStream is = - new ByteArrayInputStream(trusedCertStr.getBytes()); - Certificate trusedCert = cf.generateCertificate(is); - is.close(); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - ks.setCertificateEntry("RSA Export Signer", trusedCert); - - if (keyCertStr != null) { - // generate the private key. - RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec( - new BigInteger(modulus), - new BigInteger(privateExponent)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - - // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLSv1.2"); - - if (keyCertStr != null) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; - } - } diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressDNSIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressDNSIdentities.java index dda6dc6078a..9fe9354ba60 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressDNSIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressDNSIdentities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,15 +21,23 @@ * questions. */ -/* @test +/* @test id=tls12 * @bug 6766775 * @library /test/lib * @summary X509 certificate hostname checking is broken in JDK1.6.0_10 - * @run main/othervm IPAddressDNSIdentities * - * SunJSSE does not support dynamic system properties, no way to re-use - * system properties in samevm/agentvm mode. * @author Xuelei Fan + * @run main/othervm IPAddressDNSIdentities TLSv1.2 MD5withRSA + */ + + +/* @test id=tls13 + * @bug 6766775 + * @library /test/lib + * @summary X509 certificate hostname checking is broken in JDK1.6.0_10 + * + * @author Xuelei Fan + * @run main/othervm IPAddressDNSIdentities TLSv1.3 SHA256withRSA */ import java.net.*; @@ -44,372 +52,12 @@ import java.security.spec.*; import java.security.interfaces.*; import java.math.BigInteger; import jdk.test.lib.net.URIBuilder; - -/* - * Certificates and key used in the test. - * - * TLS server certificate: - * server private key: - * -----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,D9AE407F6D0E389A - * - * WPrA7TFol/cQCcp9oHnXWNpYlvRbbIcQj0m+RKT2Iuzfus+DHt3Zadf8nJpKfX2e - * h2rnhlzCN9M7djRDooZKDOPCsdBn51Au7HlZF3S3Opgo7D8XFM1a8t1Je4ke14oI - * nw6QKYsBblRziPnP2PZ0zvX24nOv7bbY8beynlJHGs00VWSFdoH2DS0aE1p6D+3n - * ptJuJ75dVfZFK4X7162APlNXevX8D6PEQpSiRw1rjjGGcnvQ4HdWk3BxDVDcCNJb - * Y1aGNRxsjTDvPi3R9Qx2M+W03QzEPx4SR3ZHVskeSJHaetM0TM/w/45Paq4GokXP - * ZeTnbEx1xmjkA7h+t4doLL4watx5F6yLsJzu8xB3lt/1EtmkYtLz1t7X4BetPAXz - * zS69X/VwhKfsOI3qXBWuL2oHPyhDmT1gcaUQwEPSV6ogHEEQEDXdiUS8heNK13KF - * TCQYFkETvV2BLxUhV1hypPzRQ6tUpJiAbD5KmoK2lD9slshG2QtvKQq0/bgkDY5J - * LhDHV2dtcZ3kDPkkZXpbcJQvoeH3d09C5sIsuTFo2zgNR6oETHUc5TzP6FY2YYRa - * QcK5HcmtsRRiXFm01ac+aMejJUIujjFt84SiKWT/73vC8AmY4tYcJBLjCg4XIxSH - * fdDFLL1YZENNO5ivlp8mdiHqcawx+36L7DrEZQ8RZt6cqST5t/+XTdM74s6k81GT - * pNsa82P2K2zmIUZ/DL2mKjW1vfRByw1NQFEBkN3vdyZxYfM/JyUzX4hbjXBEkh9Q - * QYrcwLKLjis2QzSvK04B3bvRzRb+4ocWiso8ZPAXAIxZFBWDpTMM2A== - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICXAIBAAKBgQClrFscN6LdmYktsnm4j9VIpecchBeNaZzGrG358h0fORna03Ie - * buxEzHCk3LoAMPagTz1UemFqzFfQCn+VKBg/mtmU8hvIJIh+/p0PPftXUwizIDPU - * PxdHFNHN6gjYDnVOr77M0uyvqXpJ38LZrLgkQJCmA1Yq0DAFQCxPq9l0iQIDAQAB - * AoGAbqcbg1E1mkR99uOJoNeQYKFOJyGiiXTMnXV1TseC4+PDfQBU7Dax35GcesBi - * CtapIpFKKS5D+ozY6b7ZT8ojxuQ/uHLPAvz0WDR3ds4iRF8tyu71Q1ZHcQsJa17y - * yO7UbkSSKn/Mp9Rb+/dKqftUGNXVFLqgHBOzN2s3We3bbbECQQDYBPKOg3hkaGHo - * OhpHKqtQ6EVkldihG/3i4WejRonelXN+HRh1KrB2HBx0M8D/qAzP1i3rNSlSHer4 - * 59YRTJnHAkEAxFX/sVYSn07BHv9Zhn6XXct/Cj43z/tKNbzlNbcxqQwQerw3IH51 - * 8UH2YOA+GD3lXbKp+MytoFLWv8zg4YT/LwJAfqan75Z1R6lLffRS49bIiq8jwE16 - * rTrUJ+kv8jKxMqc9B3vXkxpsS1M/+4E8bqgAmvpgAb8xcsvHsBd9ErdukQJBAKs2 - * j67W75BrPjBI34pQ1LEfp56IGWXOrq1kF8IbCjxv3+MYRT6Z6UJFkpRymNPNDjsC - * dgUYgITiGJHUGXuw3lMCQHEHqo9ZtXz92yFT+VhsNc29B8m/sqUJdtCcMd/jGpAF - * u6GHufjqIZBpQsk63wbwESAPZZ+kk1O1kS5GIRLX608= - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * publicExponent: 65537 (0x10001) - * privateExponent: - * 6e:a7:1b:83:51:35:9a:44:7d:f6:e3:89:a0:d7:90: - * 60:a1:4e:27:21:a2:89:74:cc:9d:75:75:4e:c7:82: - * e3:e3:c3:7d:00:54:ec:36:b1:df:91:9c:7a:c0:62: - * 0a:d6:a9:22:91:4a:29:2e:43:fa:8c:d8:e9:be:d9: - * 4f:ca:23:c6:e4:3f:b8:72:cf:02:fc:f4:58:34:77: - * 76:ce:22:44:5f:2d:ca:ee:f5:43:56:47:71:0b:09: - * 6b:5e:f2:c8:ee:d4:6e:44:92:2a:7f:cc:a7:d4:5b: - * fb:f7:4a:a9:fb:54:18:d5:d5:14:ba:a0:1c:13:b3: - * 37:6b:37:59:ed:db:6d:b1 - * prime1: - * 00:d8:04:f2:8e:83:78:64:68:61:e8:3a:1a:47:2a: - * ab:50:e8:45:64:95:d8:a1:1b:fd:e2:e1:67:a3:46: - * 89:de:95:73:7e:1d:18:75:2a:b0:76:1c:1c:74:33: - * c0:ff:a8:0c:cf:d6:2d:eb:35:29:52:1d:ea:f8:e7: - * d6:11:4c:99:c7 - * prime2: - * 00:c4:55:ff:b1:56:12:9f:4e:c1:1e:ff:59:86:7e: - * 97:5d:cb:7f:0a:3e:37:cf:fb:4a:35:bc:e5:35:b7: - * 31:a9:0c:10:7a:bc:37:20:7e:75:f1:41:f6:60:e0: - * 3e:18:3d:e5:5d:b2:a9:f8:cc:ad:a0:52:d6:bf:cc: - * e0:e1:84:ff:2f - * exponent1: - * 7e:a6:a7:ef:96:75:47:a9:4b:7d:f4:52:e3:d6:c8: - * 8a:af:23:c0:4d:7a:ad:3a:d4:27:e9:2f:f2:32:b1: - * 32:a7:3d:07:7b:d7:93:1a:6c:4b:53:3f:fb:81:3c: - * 6e:a8:00:9a:fa:60:01:bf:31:72:cb:c7:b0:17:7d: - * 12:b7:6e:91 - * exponent2: - * 00:ab:36:8f:ae:d6:ef:90:6b:3e:30:48:df:8a:50: - * d4:b1:1f:a7:9e:88:19:65:ce:ae:ad:64:17:c2:1b: - * 0a:3c:6f:df:e3:18:45:3e:99:e9:42:45:92:94:72: - * 98:d3:cd:0e:3b:02:76:05:18:80:84:e2:18:91:d4: - * 19:7b:b0:de:53 - * coefficient: - * 71:07:aa:8f:59:b5:7c:fd:db:21:53:f9:58:6c:35: - * cd:bd:07:c9:bf:b2:a5:09:76:d0:9c:31:df:e3:1a: - * 90:05:bb:a1:87:b9:f8:ea:21:90:69:42:c9:3a:df: - * 06:f0:11:20:0f:65:9f:a4:93:53:b5:91:2e:46:21: - * 12:d7:eb:4f - * - * - * server certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 8 (0x8) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:43:04 2008 GMT - * Not After : Aug 25 03:43:04 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Server, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * ED:6E:DB:F4:B5:56:C8:FB:1A:06:61:3F:0F:08:BB:A6:04:D8:16:54 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * DNS:localhost - * Signature Algorithm: md5WithRSAEncryption0 - * - * -----BEGIN CERTIFICATE----- - * MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3 - * ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6 - * YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS - * 7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh - * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac - * PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi - * nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn - * JqCpf5uZGOo= - * -----END CERTIFICATE----- - * - * - * TLS client certificate: - * client private key: - * ----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,FA2A435CD35A9390 - * - * Z+Y2uaETbsUWIyJUyVu1UV2G4rgFYJyACZT6Tp1KjRtxflSh2kXkJ9MpuXMXA0V4 - * Yy3fDzPqCL9NJmQAYRlAx/W/+j4F5EyMWDIx8fUxzONRZyoiwF7jLm+KscAfv6Pf - * q7ItWOdj3z7IYrwlB8YIGd3F2cDKT3S+lYRk7rKb/qT7itbuHnY4Ardh3yl+MZak - * jBp+ELUlRsUqSr1V0LoM+0rCCykarpyfhpxEcqsrl0v9Cyi5uhU50/oKv5zql3SH - * l2ImgDjp3batAs8+Bd4NF2aqi0a7Hy44JUHxRm4caZryU/i/D9N1MbuM6882HLat - * 5N0G+NaIUfywa8mjwq2D5aiit18HqKA6XeRRYeJ5Dvu9DCO4GeFSwcUFIBMI0L46 - * 7s114+oDodg57pMgITi+04vmUxvqlN9aiyd7f5Fgd7PeHGeOdbMz1NaJLJaPI9++ - * NakK8eK9iwT/Gdq0Uap5/CHW7vCT5PO+h3HY0STH0lWStXhdWnFO04zTdywsbSp+ - * DLpHeFT66shfeUlxR0PsCbG9vPRt/QmGLeYQZITppWo/ylSq4j+pRIuXvuWHdBRN - * rTZ8QF4Y7AxQUXVz1j1++s6ZMHTzaK2i9HrhmDs1MbJl+QwWre3Xpv3LvTVz3k5U - * wX8kuY1m3STt71QCaRWENq5sRaMImLxZbxc/ivFl9RAzUqo4NCxLod/QgA4iLqtO - * ztnlpzwlC/F8HbQ1oqYWwnZAPhzU/cULtstl+Yrws2c2atO323LbPXZqbASySgig - * sNpFXQMObdfP6LN23bY+1SvtK7V4NUTNhpdIc6INQAQ= - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICWwIBAAKBgQC78EA2rCZUTvSjWgAvaSFvuXo6k+yi9uGOx2PYLxIwmS6w8o/4 - * Jy0keCiE9wG/jUR53TvSVfPOPLJbIX3v/TNKsaP/xsibuQ98QTWX+ds6BWAFFa9Z - * F5KjEK0WHOQHU6+odqJWKpLT+SjgeM9eH0irXBnd4WdDunWN9YKsQ5JEGwIDAQAB - * AoGAEbdqNj0wN85hnWyEi/ObJU8UyKTdL9eaF72QGfcF/fLSxfd3vurihIeXOkGW - * tpn4lIxYcVGM9CognhqgJpl11jFTQzn1KqZ+NEJRKkCHA4hDabKJbSC9fXHvRwrf - * BsFpZqgiNxp3HseUTiwnaUVeyPgMt/jAj5nB5Sib+UyUxrECQQDnNQBiF2aifEg6 - * zbJOOC7he5CHAdkFxSxWVFVHL6EfXfqdLVkUohMbgZv+XxyIeU2biOExSg49Kds3 - * FOKgTau1AkEA0Bd1haj6QuCo8I0AXm2WO+MMTZMTvtHD/bGjKNM+fT4I8rKYnQRX - * 1acHdqS9Xx2rNJqZgkMmpESIdPR2fc4yjwJALFeM6EMmqvj8/VIf5UJ/Mz14fXwM - * PEARfckUxd9LnnFutCBTWlKvKXJVEZb6KO5ixPaegc57Jp3Vbh3yTN44lQJADD/1 - * SSMDaIB1MYP7a5Oj7m6VQNPRq8AJe5vDcRnOae0G9dKRrVyeFxO4GsHj6/+BHp2j - * P8nYMn9eURQ7DXjf/QJAAQzMlWnKGSO8pyTDtnQx3hRMoUkOEhmNq4bQhLkYqtnY - * FcqpUQ2qMjW+NiNWk5HnTrMS3L9EdJobMUzaNZLy4w== - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * publicExponent: 65537 (0x10001) - * privateExponent: - * 11:b7:6a:36:3d:30:37:ce:61:9d:6c:84:8b:f3:9b: - * 25:4f:14:c8:a4:dd:2f:d7:9a:17:bd:90:19:f7:05: - * fd:f2:d2:c5:f7:77:be:ea:e2:84:87:97:3a:41:96: - * b6:99:f8:94:8c:58:71:51:8c:f4:2a:20:9e:1a:a0: - * 26:99:75:d6:31:53:43:39:f5:2a:a6:7e:34:42:51: - * 2a:40:87:03:88:43:69:b2:89:6d:20:bd:7d:71:ef: - * 47:0a:df:06:c1:69:66:a8:22:37:1a:77:1e:c7:94: - * 4e:2c:27:69:45:5e:c8:f8:0c:b7:f8:c0:8f:99:c1: - * e5:28:9b:f9:4c:94:c6:b1 - * prime1: - * 00:e7:35:00:62:17:66:a2:7c:48:3a:cd:b2:4e:38: - * 2e:e1:7b:90:87:01:d9:05:c5:2c:56:54:55:47:2f: - * a1:1f:5d:fa:9d:2d:59:14:a2:13:1b:81:9b:fe:5f: - * 1c:88:79:4d:9b:88:e1:31:4a:0e:3d:29:db:37:14: - * e2:a0:4d:ab:b5 - * prime2: - * 00:d0:17:75:85:a8:fa:42:e0:a8:f0:8d:00:5e:6d: - * 96:3b:e3:0c:4d:93:13:be:d1:c3:fd:b1:a3:28:d3: - * 3e:7d:3e:08:f2:b2:98:9d:04:57:d5:a7:07:76:a4: - * bd:5f:1d:ab:34:9a:99:82:43:26:a4:44:88:74:f4: - * 76:7d:ce:32:8f - * exponent1: - * 2c:57:8c:e8:43:26:aa:f8:fc:fd:52:1f:e5:42:7f: - * 33:3d:78:7d:7c:0c:3c:40:11:7d:c9:14:c5:df:4b: - * 9e:71:6e:b4:20:53:5a:52:af:29:72:55:11:96:fa: - * 28:ee:62:c4:f6:9e:81:ce:7b:26:9d:d5:6e:1d:f2: - * 4c:de:38:95 - * exponent2: - * 0c:3f:f5:49:23:03:68:80:75:31:83:fb:6b:93:a3: - * ee:6e:95:40:d3:d1:ab:c0:09:7b:9b:c3:71:19:ce: - * 69:ed:06:f5:d2:91:ad:5c:9e:17:13:b8:1a:c1:e3: - * eb:ff:81:1e:9d:a3:3f:c9:d8:32:7f:5e:51:14:3b: - * 0d:78:df:fd - * coefficient: - * 01:0c:cc:95:69:ca:19:23:bc:a7:24:c3:b6:74:31: - * de:14:4c:a1:49:0e:12:19:8d:ab:86:d0:84:b9:18: - * aa:d9:d8:15:ca:a9:51:0d:aa:32:35:be:36:23:56: - * 93:91:e7:4e:b3:12:dc:bf:44:74:9a:1b:31:4c:da: - * 35:92:f2:e3 - * - * client certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 9 (0x9) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:43:24 2008 GMT - * Not After : Aug 25 03:43:24 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * DNS:localhost - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas - * JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV - * 8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq - * ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh - * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F - * HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj - * XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN - * cl/epUcHL7E= - * -----END CERTIFICATE----- - * - * - * - * Trusted CA certificate: - * Certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 0 (0x0) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 02:43:36 2008 GMT - * Not After : Aug 25 02:43:36 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: - * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: - * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: - * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: - * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: - * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: - * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: - * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: - * 89:2a:95:12:4c:d8:09:2a:e9 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Subject Key Identifier: - * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org - * serial:00 - * - * X509v3 Basic Constraints: - * CA:TRUE - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB - * gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX - * 4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj - * 7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G - * A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ - * hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt - * U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw - * DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA - * ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ - * LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P - * 6Mvf0r1PNTY2hwTJLJmKtg== - * -----END CERTIFICATE--- - */ +import jdk.test.lib.security.CertificateBuilder; +import jdk.test.lib.security.SecurityUtils; -public class IPAddressDNSIdentities { - static Map cookies; - ServerSocket ss; - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ +public class IPAddressDNSIdentities extends IdentitiesBase { /* * Should we run the client or server in a separate thread? @@ -418,209 +66,6 @@ public class IPAddressDNSIdentities { */ static boolean separateServerThread = true; - /* - * Where do we find the keystores? - */ - static String trusedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + - "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + - "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + - "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + - "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + - "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + - "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + - "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + - "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + - "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + - "6Mvf0r1PNTY2hwTJLJmKtg==\n" + - "-----END CERTIFICATE-----"; - - static String serverCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3\n" + - "ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6\n" + - "YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS\n" + - "7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" + - "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac\n" + - "PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi\n" + - "nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn\n" + - "JqCpf5uZGOo=\n" + - "-----END CERTIFICATE-----"; - - static String clientCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + - "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + - "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + - "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" + - "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F\n" + - "HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj\n" + - "XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN\n" + - "cl/epUcHL7E=\n" + - "-----END CERTIFICATE-----"; - - static byte serverPrivateExponent[] = { - (byte)0x6e, (byte)0xa7, (byte)0x1b, (byte)0x83, - (byte)0x51, (byte)0x35, (byte)0x9a, (byte)0x44, - (byte)0x7d, (byte)0xf6, (byte)0xe3, (byte)0x89, - (byte)0xa0, (byte)0xd7, (byte)0x90, (byte)0x60, - (byte)0xa1, (byte)0x4e, (byte)0x27, (byte)0x21, - (byte)0xa2, (byte)0x89, (byte)0x74, (byte)0xcc, - (byte)0x9d, (byte)0x75, (byte)0x75, (byte)0x4e, - (byte)0xc7, (byte)0x82, (byte)0xe3, (byte)0xe3, - (byte)0xc3, (byte)0x7d, (byte)0x00, (byte)0x54, - (byte)0xec, (byte)0x36, (byte)0xb1, (byte)0xdf, - (byte)0x91, (byte)0x9c, (byte)0x7a, (byte)0xc0, - (byte)0x62, (byte)0x0a, (byte)0xd6, (byte)0xa9, - (byte)0x22, (byte)0x91, (byte)0x4a, (byte)0x29, - (byte)0x2e, (byte)0x43, (byte)0xfa, (byte)0x8c, - (byte)0xd8, (byte)0xe9, (byte)0xbe, (byte)0xd9, - (byte)0x4f, (byte)0xca, (byte)0x23, (byte)0xc6, - (byte)0xe4, (byte)0x3f, (byte)0xb8, (byte)0x72, - (byte)0xcf, (byte)0x02, (byte)0xfc, (byte)0xf4, - (byte)0x58, (byte)0x34, (byte)0x77, (byte)0x76, - (byte)0xce, (byte)0x22, (byte)0x44, (byte)0x5f, - (byte)0x2d, (byte)0xca, (byte)0xee, (byte)0xf5, - (byte)0x43, (byte)0x56, (byte)0x47, (byte)0x71, - (byte)0x0b, (byte)0x09, (byte)0x6b, (byte)0x5e, - (byte)0xf2, (byte)0xc8, (byte)0xee, (byte)0xd4, - (byte)0x6e, (byte)0x44, (byte)0x92, (byte)0x2a, - (byte)0x7f, (byte)0xcc, (byte)0xa7, (byte)0xd4, - (byte)0x5b, (byte)0xfb, (byte)0xf7, (byte)0x4a, - (byte)0xa9, (byte)0xfb, (byte)0x54, (byte)0x18, - (byte)0xd5, (byte)0xd5, (byte)0x14, (byte)0xba, - (byte)0xa0, (byte)0x1c, (byte)0x13, (byte)0xb3, - (byte)0x37, (byte)0x6b, (byte)0x37, (byte)0x59, - (byte)0xed, (byte)0xdb, (byte)0x6d, (byte)0xb1 - }; - - static byte serverModulus[] = { - (byte)0x00, - (byte)0xa5, (byte)0xac, (byte)0x5b, (byte)0x1c, - (byte)0x37, (byte)0xa2, (byte)0xdd, (byte)0x99, - (byte)0x89, (byte)0x2d, (byte)0xb2, (byte)0x79, - (byte)0xb8, (byte)0x8f, (byte)0xd5, (byte)0x48, - (byte)0xa5, (byte)0xe7, (byte)0x1c, (byte)0x84, - (byte)0x17, (byte)0x8d, (byte)0x69, (byte)0x9c, - (byte)0xc6, (byte)0xac, (byte)0x6d, (byte)0xf9, - (byte)0xf2, (byte)0x1d, (byte)0x1f, (byte)0x39, - (byte)0x19, (byte)0xda, (byte)0xd3, (byte)0x72, - (byte)0x1e, (byte)0x6e, (byte)0xec, (byte)0x44, - (byte)0xcc, (byte)0x70, (byte)0xa4, (byte)0xdc, - (byte)0xba, (byte)0x00, (byte)0x30, (byte)0xf6, - (byte)0xa0, (byte)0x4f, (byte)0x3d, (byte)0x54, - (byte)0x7a, (byte)0x61, (byte)0x6a, (byte)0xcc, - (byte)0x57, (byte)0xd0, (byte)0x0a, (byte)0x7f, - (byte)0x95, (byte)0x28, (byte)0x18, (byte)0x3f, - (byte)0x9a, (byte)0xd9, (byte)0x94, (byte)0xf2, - (byte)0x1b, (byte)0xc8, (byte)0x24, (byte)0x88, - (byte)0x7e, (byte)0xfe, (byte)0x9d, (byte)0x0f, - (byte)0x3d, (byte)0xfb, (byte)0x57, (byte)0x53, - (byte)0x08, (byte)0xb3, (byte)0x20, (byte)0x33, - (byte)0xd4, (byte)0x3f, (byte)0x17, (byte)0x47, - (byte)0x14, (byte)0xd1, (byte)0xcd, (byte)0xea, - (byte)0x08, (byte)0xd8, (byte)0x0e, (byte)0x75, - (byte)0x4e, (byte)0xaf, (byte)0xbe, (byte)0xcc, - (byte)0xd2, (byte)0xec, (byte)0xaf, (byte)0xa9, - (byte)0x7a, (byte)0x49, (byte)0xdf, (byte)0xc2, - (byte)0xd9, (byte)0xac, (byte)0xb8, (byte)0x24, - (byte)0x40, (byte)0x90, (byte)0xa6, (byte)0x03, - (byte)0x56, (byte)0x2a, (byte)0xd0, (byte)0x30, - (byte)0x05, (byte)0x40, (byte)0x2c, (byte)0x4f, - (byte)0xab, (byte)0xd9, (byte)0x74, (byte)0x89 - }; - - static byte clientPrivateExponent[] = { - (byte)0x11, (byte)0xb7, (byte)0x6a, (byte)0x36, - (byte)0x3d, (byte)0x30, (byte)0x37, (byte)0xce, - (byte)0x61, (byte)0x9d, (byte)0x6c, (byte)0x84, - (byte)0x8b, (byte)0xf3, (byte)0x9b, (byte)0x25, - (byte)0x4f, (byte)0x14, (byte)0xc8, (byte)0xa4, - (byte)0xdd, (byte)0x2f, (byte)0xd7, (byte)0x9a, - (byte)0x17, (byte)0xbd, (byte)0x90, (byte)0x19, - (byte)0xf7, (byte)0x05, (byte)0xfd, (byte)0xf2, - (byte)0xd2, (byte)0xc5, (byte)0xf7, (byte)0x77, - (byte)0xbe, (byte)0xea, (byte)0xe2, (byte)0x84, - (byte)0x87, (byte)0x97, (byte)0x3a, (byte)0x41, - (byte)0x96, (byte)0xb6, (byte)0x99, (byte)0xf8, - (byte)0x94, (byte)0x8c, (byte)0x58, (byte)0x71, - (byte)0x51, (byte)0x8c, (byte)0xf4, (byte)0x2a, - (byte)0x20, (byte)0x9e, (byte)0x1a, (byte)0xa0, - (byte)0x26, (byte)0x99, (byte)0x75, (byte)0xd6, - (byte)0x31, (byte)0x53, (byte)0x43, (byte)0x39, - (byte)0xf5, (byte)0x2a, (byte)0xa6, (byte)0x7e, - (byte)0x34, (byte)0x42, (byte)0x51, (byte)0x2a, - (byte)0x40, (byte)0x87, (byte)0x03, (byte)0x88, - (byte)0x43, (byte)0x69, (byte)0xb2, (byte)0x89, - (byte)0x6d, (byte)0x20, (byte)0xbd, (byte)0x7d, - (byte)0x71, (byte)0xef, (byte)0x47, (byte)0x0a, - (byte)0xdf, (byte)0x06, (byte)0xc1, (byte)0x69, - (byte)0x66, (byte)0xa8, (byte)0x22, (byte)0x37, - (byte)0x1a, (byte)0x77, (byte)0x1e, (byte)0xc7, - (byte)0x94, (byte)0x4e, (byte)0x2c, (byte)0x27, - (byte)0x69, (byte)0x45, (byte)0x5e, (byte)0xc8, - (byte)0xf8, (byte)0x0c, (byte)0xb7, (byte)0xf8, - (byte)0xc0, (byte)0x8f, (byte)0x99, (byte)0xc1, - (byte)0xe5, (byte)0x28, (byte)0x9b, (byte)0xf9, - (byte)0x4c, (byte)0x94, (byte)0xc6, (byte)0xb1 - }; - - static byte clientModulus[] = { - (byte)0x00, - (byte)0xbb, (byte)0xf0, (byte)0x40, (byte)0x36, - (byte)0xac, (byte)0x26, (byte)0x54, (byte)0x4e, - (byte)0xf4, (byte)0xa3, (byte)0x5a, (byte)0x00, - (byte)0x2f, (byte)0x69, (byte)0x21, (byte)0x6f, - (byte)0xb9, (byte)0x7a, (byte)0x3a, (byte)0x93, - (byte)0xec, (byte)0xa2, (byte)0xf6, (byte)0xe1, - (byte)0x8e, (byte)0xc7, (byte)0x63, (byte)0xd8, - (byte)0x2f, (byte)0x12, (byte)0x30, (byte)0x99, - (byte)0x2e, (byte)0xb0, (byte)0xf2, (byte)0x8f, - (byte)0xf8, (byte)0x27, (byte)0x2d, (byte)0x24, - (byte)0x78, (byte)0x28, (byte)0x84, (byte)0xf7, - (byte)0x01, (byte)0xbf, (byte)0x8d, (byte)0x44, - (byte)0x79, (byte)0xdd, (byte)0x3b, (byte)0xd2, - (byte)0x55, (byte)0xf3, (byte)0xce, (byte)0x3c, - (byte)0xb2, (byte)0x5b, (byte)0x21, (byte)0x7d, - (byte)0xef, (byte)0xfd, (byte)0x33, (byte)0x4a, - (byte)0xb1, (byte)0xa3, (byte)0xff, (byte)0xc6, - (byte)0xc8, (byte)0x9b, (byte)0xb9, (byte)0x0f, - (byte)0x7c, (byte)0x41, (byte)0x35, (byte)0x97, - (byte)0xf9, (byte)0xdb, (byte)0x3a, (byte)0x05, - (byte)0x60, (byte)0x05, (byte)0x15, (byte)0xaf, - (byte)0x59, (byte)0x17, (byte)0x92, (byte)0xa3, - (byte)0x10, (byte)0xad, (byte)0x16, (byte)0x1c, - (byte)0xe4, (byte)0x07, (byte)0x53, (byte)0xaf, - (byte)0xa8, (byte)0x76, (byte)0xa2, (byte)0x56, - (byte)0x2a, (byte)0x92, (byte)0xd3, (byte)0xf9, - (byte)0x28, (byte)0xe0, (byte)0x78, (byte)0xcf, - (byte)0x5e, (byte)0x1f, (byte)0x48, (byte)0xab, - (byte)0x5c, (byte)0x19, (byte)0xdd, (byte)0xe1, - (byte)0x67, (byte)0x43, (byte)0xba, (byte)0x75, - (byte)0x8d, (byte)0xf5, (byte)0x82, (byte)0xac, - (byte)0x43, (byte)0x92, (byte)0x44, (byte)0x1b - }; - - static char passphrase[] = "passphrase".toCharArray(); /* * Is the server ready to serve? @@ -632,10 +77,6 @@ public class IPAddressDNSIdentities { */ volatile static boolean closeReady = false; - /* - * Turn on SSL debugging? - */ - static boolean debug = false; private SSLServerSocket sslServerSocket = null; @@ -646,8 +87,7 @@ public class IPAddressDNSIdentities { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLContext context = getSSLContext(trusedCertStr, serverCertStr, - serverModulus, serverPrivateExponent, passphrase); + SSLContext context = getServerSSLContext(); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); // doClientSide() connects to the loopback address @@ -702,8 +142,7 @@ public class IPAddressDNSIdentities { void doClientSide() throws Exception { SSLContext reservedSSLContext = SSLContext.getDefault(); try { - SSLContext context = getSSLContext(trusedCertStr, clientCertStr, - clientModulus, clientPrivateExponent, passphrase); + SSLContext context = getClientSSLContext(); SSLContext.setDefault(context); @@ -761,14 +200,21 @@ public class IPAddressDNSIdentities { volatile Exception serverException = null; volatile Exception clientException = null; - public static void main(String args[]) throws Exception { + public static void main(String[] args) throws Exception { + if (args[1].contains("MD5")) { + System.err.println("RE-ENABLING MD5"); + SecurityUtils.removeFromDisabledAlgs( + "jdk.certpath.disabledAlgorithms", List.of("MD5")); + SecurityUtils.removeFromDisabledTlsAlgs("MD5"); + } + if (debug) System.setProperty("javax.net.debug", "all"); /* * Start the tests. */ - new IPAddressDNSIdentities(); + new IPAddressDNSIdentities(args[0], args[1]); } Thread clientThread = null; @@ -778,7 +224,9 @@ public class IPAddressDNSIdentities { * * Fork off the other side, then do your work. */ - IPAddressDNSIdentities() throws Exception { + IPAddressDNSIdentities(String protocol, String signatureAlgo) throws Exception { + super(protocol, signatureAlgo); + if (separateServerThread) { startServer(true); startClient(false); @@ -854,64 +302,17 @@ public class IPAddressDNSIdentities { } } - // get the ssl context - private static SSLContext getSSLContext(String trusedCertStr, - String keyCertStr, byte[] modulus, - byte[] privateExponent, char[] passphrase) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - ByteArrayInputStream is = - new ByteArrayInputStream(trusedCertStr.getBytes()); - Certificate trusedCert = cf.generateCertificate(is); - is.close(); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - ks.setCertificateEntry("RSA Export Signer", trusedCert); - - if (keyCertStr != null) { - // generate the private key. - RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec( - new BigInteger(modulus), - new BigInteger(privateExponent)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - - // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLS"); - - if (keyCertStr != null) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; + @Override + protected CertificateBuilder customizeServerCert(CertificateBuilder builder) + throws Exception { + return builder.addExtension(CertificateBuilder.createDNSSubjectAltNameExt( + true, "localhost")); } + @Override + protected CertificateBuilder customizeClientCert(CertificateBuilder builder) + throws Exception { + return builder.addExtension(CertificateBuilder.createDNSSubjectAltNameExt( + true, "localhost")); + } } diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java index a15093c821e..864b8cfdfb9 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java @@ -26,387 +26,41 @@ // system properties in samevm/agentvm mode. // -/* @test +/* @test id=tls12 * @summary X509 certificate hostname checking is broken in JDK1.6.0_10 * @library /test/lib * @bug 6766775 - * @run main/othervm IPAddressIPIdentities + * @run main/othervm IPAddressIPIdentities TLSv1.2 MD5withRSA * @author Xuelei Fan */ -import java.net.*; -import java.util.*; -import java.io.*; -import javax.net.ssl.*; -import java.security.Security; -import java.security.KeyStore; -import java.security.KeyFactory; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; -import java.math.BigInteger; -import jdk.test.lib.net.URIBuilder; - -/* - * Certificates and key used in the test. - * - * TLS server certificate: - * server private key: - * -----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,D9AE407F6D0E389A - * - * WPrA7TFol/cQCcp9oHnXWNpYlvRbbIcQj0m+RKT2Iuzfus+DHt3Zadf8nJpKfX2e - * h2rnhlzCN9M7djRDooZKDOPCsdBn51Au7HlZF3S3Opgo7D8XFM1a8t1Je4ke14oI - * nw6QKYsBblRziPnP2PZ0zvX24nOv7bbY8beynlJHGs00VWSFdoH2DS0aE1p6D+3n - * ptJuJ75dVfZFK4X7162APlNXevX8D6PEQpSiRw1rjjGGcnvQ4HdWk3BxDVDcCNJb - * Y1aGNRxsjTDvPi3R9Qx2M+W03QzEPx4SR3ZHVskeSJHaetM0TM/w/45Paq4GokXP - * ZeTnbEx1xmjkA7h+t4doLL4watx5F6yLsJzu8xB3lt/1EtmkYtLz1t7X4BetPAXz - * zS69X/VwhKfsOI3qXBWuL2oHPyhDmT1gcaUQwEPSV6ogHEEQEDXdiUS8heNK13KF - * TCQYFkETvV2BLxUhV1hypPzRQ6tUpJiAbD5KmoK2lD9slshG2QtvKQq0/bgkDY5J - * LhDHV2dtcZ3kDPkkZXpbcJQvoeH3d09C5sIsuTFo2zgNR6oETHUc5TzP6FY2YYRa - * QcK5HcmtsRRiXFm01ac+aMejJUIujjFt84SiKWT/73vC8AmY4tYcJBLjCg4XIxSH - * fdDFLL1YZENNO5ivlp8mdiHqcawx+36L7DrEZQ8RZt6cqST5t/+XTdM74s6k81GT - * pNsa82P2K2zmIUZ/DL2mKjW1vfRByw1NQFEBkN3vdyZxYfM/JyUzX4hbjXBEkh9Q - * QYrcwLKLjis2QzSvK04B3bvRzRb+4ocWiso8ZPAXAIxZFBWDpTMM2A== - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICXAIBAAKBgQClrFscN6LdmYktsnm4j9VIpecchBeNaZzGrG358h0fORna03Ie - * buxEzHCk3LoAMPagTz1UemFqzFfQCn+VKBg/mtmU8hvIJIh+/p0PPftXUwizIDPU - * PxdHFNHN6gjYDnVOr77M0uyvqXpJ38LZrLgkQJCmA1Yq0DAFQCxPq9l0iQIDAQAB - * AoGAbqcbg1E1mkR99uOJoNeQYKFOJyGiiXTMnXV1TseC4+PDfQBU7Dax35GcesBi - * CtapIpFKKS5D+ozY6b7ZT8ojxuQ/uHLPAvz0WDR3ds4iRF8tyu71Q1ZHcQsJa17y - * yO7UbkSSKn/Mp9Rb+/dKqftUGNXVFLqgHBOzN2s3We3bbbECQQDYBPKOg3hkaGHo - * OhpHKqtQ6EVkldihG/3i4WejRonelXN+HRh1KrB2HBx0M8D/qAzP1i3rNSlSHer4 - * 59YRTJnHAkEAxFX/sVYSn07BHv9Zhn6XXct/Cj43z/tKNbzlNbcxqQwQerw3IH51 - * 8UH2YOA+GD3lXbKp+MytoFLWv8zg4YT/LwJAfqan75Z1R6lLffRS49bIiq8jwE16 - * rTrUJ+kv8jKxMqc9B3vXkxpsS1M/+4E8bqgAmvpgAb8xcsvHsBd9ErdukQJBAKs2 - * j67W75BrPjBI34pQ1LEfp56IGWXOrq1kF8IbCjxv3+MYRT6Z6UJFkpRymNPNDjsC - * dgUYgITiGJHUGXuw3lMCQHEHqo9ZtXz92yFT+VhsNc29B8m/sqUJdtCcMd/jGpAF - * u6GHufjqIZBpQsk63wbwESAPZZ+kk1O1kS5GIRLX608= - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * publicExponent: 65537 (0x10001) - * privateExponent: - * 6e:a7:1b:83:51:35:9a:44:7d:f6:e3:89:a0:d7:90: - * 60:a1:4e:27:21:a2:89:74:cc:9d:75:75:4e:c7:82: - * e3:e3:c3:7d:00:54:ec:36:b1:df:91:9c:7a:c0:62: - * 0a:d6:a9:22:91:4a:29:2e:43:fa:8c:d8:e9:be:d9: - * 4f:ca:23:c6:e4:3f:b8:72:cf:02:fc:f4:58:34:77: - * 76:ce:22:44:5f:2d:ca:ee:f5:43:56:47:71:0b:09: - * 6b:5e:f2:c8:ee:d4:6e:44:92:2a:7f:cc:a7:d4:5b: - * fb:f7:4a:a9:fb:54:18:d5:d5:14:ba:a0:1c:13:b3: - * 37:6b:37:59:ed:db:6d:b1 - * prime1: - * 00:d8:04:f2:8e:83:78:64:68:61:e8:3a:1a:47:2a: - * ab:50:e8:45:64:95:d8:a1:1b:fd:e2:e1:67:a3:46: - * 89:de:95:73:7e:1d:18:75:2a:b0:76:1c:1c:74:33: - * c0:ff:a8:0c:cf:d6:2d:eb:35:29:52:1d:ea:f8:e7: - * d6:11:4c:99:c7 - * prime2: - * 00:c4:55:ff:b1:56:12:9f:4e:c1:1e:ff:59:86:7e: - * 97:5d:cb:7f:0a:3e:37:cf:fb:4a:35:bc:e5:35:b7: - * 31:a9:0c:10:7a:bc:37:20:7e:75:f1:41:f6:60:e0: - * 3e:18:3d:e5:5d:b2:a9:f8:cc:ad:a0:52:d6:bf:cc: - * e0:e1:84:ff:2f - * exponent1: - * 7e:a6:a7:ef:96:75:47:a9:4b:7d:f4:52:e3:d6:c8: - * 8a:af:23:c0:4d:7a:ad:3a:d4:27:e9:2f:f2:32:b1: - * 32:a7:3d:07:7b:d7:93:1a:6c:4b:53:3f:fb:81:3c: - * 6e:a8:00:9a:fa:60:01:bf:31:72:cb:c7:b0:17:7d: - * 12:b7:6e:91 - * exponent2: - * 00:ab:36:8f:ae:d6:ef:90:6b:3e:30:48:df:8a:50: - * d4:b1:1f:a7:9e:88:19:65:ce:ae:ad:64:17:c2:1b: - * 0a:3c:6f:df:e3:18:45:3e:99:e9:42:45:92:94:72: - * 98:d3:cd:0e:3b:02:76:05:18:80:84:e2:18:91:d4: - * 19:7b:b0:de:53 - * coefficient: - * 71:07:aa:8f:59:b5:7c:fd:db:21:53:f9:58:6c:35: - * cd:bd:07:c9:bf:b2:a5:09:76:d0:9c:31:df:e3:1a: - * 90:05:bb:a1:87:b9:f8:ea:21:90:69:42:c9:3a:df: - * 06:f0:11:20:0f:65:9f:a4:93:53:b5:91:2e:46:21: - * 12:d7:eb:4f - * - * - * server certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 7 (0x7) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:27:57 2008 GMT - * Not After : Aug 25 03:27:57 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Server, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * ED:6E:DB:F4:B5:56:C8:FB:1A:06:61:3F:0F:08:BB:A6:04:D8:16:54 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * IP Address:127.0.0.1 - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICnzCCAgigAwIBAgIBBzANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3NTdaFw0yODA4MjUwMzI3NTdaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3 - * ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6 - * YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS - * 7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjbjBsMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB - * MA0GCSqGSIb3DQEBBAUAA4GBAFJjItCtCBZcjD69wdqfIbKmRFa6eJAjR6LcoDva - * cKC/sDOLelpspiZ66Zb0Xdv5qQ7QrfOXt3K8QqJKRMdZLF9WfUfy0gJDM32ub91h - * pu+TmcGPs+6RdrAQcuvU1ZDV9X8SMj7BtKaim4d5sqFw1npncKiA5xFn8vOYwdun - * nZif - * -----END CERTIFICATE----- - * - * - * TLS client certificate: - * client private key: - * ----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,FA2A435CD35A9390 - * - * Z+Y2uaETbsUWIyJUyVu1UV2G4rgFYJyACZT6Tp1KjRtxflSh2kXkJ9MpuXMXA0V4 - * Yy3fDzPqCL9NJmQAYRlAx/W/+j4F5EyMWDIx8fUxzONRZyoiwF7jLm+KscAfv6Pf - * q7ItWOdj3z7IYrwlB8YIGd3F2cDKT3S+lYRk7rKb/qT7itbuHnY4Ardh3yl+MZak - * jBp+ELUlRsUqSr1V0LoM+0rCCykarpyfhpxEcqsrl0v9Cyi5uhU50/oKv5zql3SH - * l2ImgDjp3batAs8+Bd4NF2aqi0a7Hy44JUHxRm4caZryU/i/D9N1MbuM6882HLat - * 5N0G+NaIUfywa8mjwq2D5aiit18HqKA6XeRRYeJ5Dvu9DCO4GeFSwcUFIBMI0L46 - * 7s114+oDodg57pMgITi+04vmUxvqlN9aiyd7f5Fgd7PeHGeOdbMz1NaJLJaPI9++ - * NakK8eK9iwT/Gdq0Uap5/CHW7vCT5PO+h3HY0STH0lWStXhdWnFO04zTdywsbSp+ - * DLpHeFT66shfeUlxR0PsCbG9vPRt/QmGLeYQZITppWo/ylSq4j+pRIuXvuWHdBRN - * rTZ8QF4Y7AxQUXVz1j1++s6ZMHTzaK2i9HrhmDs1MbJl+QwWre3Xpv3LvTVz3k5U - * wX8kuY1m3STt71QCaRWENq5sRaMImLxZbxc/ivFl9RAzUqo4NCxLod/QgA4iLqtO - * ztnlpzwlC/F8HbQ1oqYWwnZAPhzU/cULtstl+Yrws2c2atO323LbPXZqbASySgig - * sNpFXQMObdfP6LN23bY+1SvtK7V4NUTNhpdIc6INQAQ= - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICWwIBAAKBgQC78EA2rCZUTvSjWgAvaSFvuXo6k+yi9uGOx2PYLxIwmS6w8o/4 - * Jy0keCiE9wG/jUR53TvSVfPOPLJbIX3v/TNKsaP/xsibuQ98QTWX+ds6BWAFFa9Z - * F5KjEK0WHOQHU6+odqJWKpLT+SjgeM9eH0irXBnd4WdDunWN9YKsQ5JEGwIDAQAB - * AoGAEbdqNj0wN85hnWyEi/ObJU8UyKTdL9eaF72QGfcF/fLSxfd3vurihIeXOkGW - * tpn4lIxYcVGM9CognhqgJpl11jFTQzn1KqZ+NEJRKkCHA4hDabKJbSC9fXHvRwrf - * BsFpZqgiNxp3HseUTiwnaUVeyPgMt/jAj5nB5Sib+UyUxrECQQDnNQBiF2aifEg6 - * zbJOOC7he5CHAdkFxSxWVFVHL6EfXfqdLVkUohMbgZv+XxyIeU2biOExSg49Kds3 - * FOKgTau1AkEA0Bd1haj6QuCo8I0AXm2WO+MMTZMTvtHD/bGjKNM+fT4I8rKYnQRX - * 1acHdqS9Xx2rNJqZgkMmpESIdPR2fc4yjwJALFeM6EMmqvj8/VIf5UJ/Mz14fXwM - * PEARfckUxd9LnnFutCBTWlKvKXJVEZb6KO5ixPaegc57Jp3Vbh3yTN44lQJADD/1 - * SSMDaIB1MYP7a5Oj7m6VQNPRq8AJe5vDcRnOae0G9dKRrVyeFxO4GsHj6/+BHp2j - * P8nYMn9eURQ7DXjf/QJAAQzMlWnKGSO8pyTDtnQx3hRMoUkOEhmNq4bQhLkYqtnY - * FcqpUQ2qMjW+NiNWk5HnTrMS3L9EdJobMUzaNZLy4w== - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * publicExponent: 65537 (0x10001) - * privateExponent: - * 11:b7:6a:36:3d:30:37:ce:61:9d:6c:84:8b:f3:9b: - * 25:4f:14:c8:a4:dd:2f:d7:9a:17:bd:90:19:f7:05: - * fd:f2:d2:c5:f7:77:be:ea:e2:84:87:97:3a:41:96: - * b6:99:f8:94:8c:58:71:51:8c:f4:2a:20:9e:1a:a0: - * 26:99:75:d6:31:53:43:39:f5:2a:a6:7e:34:42:51: - * 2a:40:87:03:88:43:69:b2:89:6d:20:bd:7d:71:ef: - * 47:0a:df:06:c1:69:66:a8:22:37:1a:77:1e:c7:94: - * 4e:2c:27:69:45:5e:c8:f8:0c:b7:f8:c0:8f:99:c1: - * e5:28:9b:f9:4c:94:c6:b1 - * prime1: - * 00:e7:35:00:62:17:66:a2:7c:48:3a:cd:b2:4e:38: - * 2e:e1:7b:90:87:01:d9:05:c5:2c:56:54:55:47:2f: - * a1:1f:5d:fa:9d:2d:59:14:a2:13:1b:81:9b:fe:5f: - * 1c:88:79:4d:9b:88:e1:31:4a:0e:3d:29:db:37:14: - * e2:a0:4d:ab:b5 - * prime2: - * 00:d0:17:75:85:a8:fa:42:e0:a8:f0:8d:00:5e:6d: - * 96:3b:e3:0c:4d:93:13:be:d1:c3:fd:b1:a3:28:d3: - * 3e:7d:3e:08:f2:b2:98:9d:04:57:d5:a7:07:76:a4: - * bd:5f:1d:ab:34:9a:99:82:43:26:a4:44:88:74:f4: - * 76:7d:ce:32:8f - * exponent1: - * 2c:57:8c:e8:43:26:aa:f8:fc:fd:52:1f:e5:42:7f: - * 33:3d:78:7d:7c:0c:3c:40:11:7d:c9:14:c5:df:4b: - * 9e:71:6e:b4:20:53:5a:52:af:29:72:55:11:96:fa: - * 28:ee:62:c4:f6:9e:81:ce:7b:26:9d:d5:6e:1d:f2: - * 4c:de:38:95 - * exponent2: - * 0c:3f:f5:49:23:03:68:80:75:31:83:fb:6b:93:a3: - * ee:6e:95:40:d3:d1:ab:c0:09:7b:9b:c3:71:19:ce: - * 69:ed:06:f5:d2:91:ad:5c:9e:17:13:b8:1a:c1:e3: - * eb:ff:81:1e:9d:a3:3f:c9:d8:32:7f:5e:51:14:3b: - * 0d:78:df:fd - * coefficient: - * 01:0c:cc:95:69:ca:19:23:bc:a7:24:c3:b6:74:31: - * de:14:4c:a1:49:0e:12:19:8d:ab:86:d0:84:b9:18: - * aa:d9:d8:15:ca:a9:51:0d:aa:32:35:be:36:23:56: - * 93:91:e7:4e:b3:12:dc:bf:44:74:9a:1b:31:4c:da: - * 35:92:f2:e3 - * - * client certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 6 (0x6) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:27:34 2008 GMT - * Not After : Aug 25 03:27:34 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * IP Address:127.0.0.1 - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICnzCCAgigAwIBAgIBBjANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3MzRaFw0yODA4MjUwMzI3MzRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas - * JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV - * 8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq - * ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjbjBsMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB - * MA0GCSqGSIb3DQEBBAUAA4GBACjj9PS+W6XOF7toFMwMOv/AemZeBOpcEF1Ei1Hx - * HjvB6EOHkMY8tFm5OPzkiWiK3+s3awpSW0jWdzMYwrQJ3/klMsPDpI7PEuirqwHP - * i5Wyl/vk7jmfWVcBO9MVhPUo4BYl4vS9aj6JA5QbkbkB95LOgT/BowY0WmHeVsXC - * I9aw - * -----END CERTIFICATE----- - * - * - * - * Trusted CA certificate: - * Certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 0 (0x0) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 02:43:36 2008 GMT - * Not After : Aug 25 02:43:36 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: - * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: - * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: - * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: - * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: - * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: - * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: - * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: - * 89:2a:95:12:4c:d8:09:2a:e9 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Subject Key Identifier: - * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org - * serial:00 - * - * X509v3 Basic Constraints: - * CA:TRUE - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB - * gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX - * 4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj - * 7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G - * A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ - * hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt - * U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw - * DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA - * ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ - * LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P - * 6Mvf0r1PNTY2hwTJLJmKtg== - * -----END CERTIFICATE--- +/* @test id=tls13 + * @summary X509 certificate hostname checking is broken in JDK1.6.0_10 + * @library /test/lib + * @bug 6766775 + * @run main/othervm IPAddressIPIdentities TLSv1.3 SHA256withRSA + * @author Xuelei Fan */ -public class IPAddressIPIdentities { - static Map cookies; - ServerSocket ss; + +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.security.SecurityUtils; +import java.util.List; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; + + +public class IPAddressIPIdentities extends IdentitiesBase { /* * ============================================================= @@ -421,211 +75,6 @@ public class IPAddressIPIdentities { */ static boolean separateServerThread = true; - /* - * Where do we find the keystores? - */ - static String trusedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + - "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + - "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + - "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + - "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + - "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + - "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + - "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + - "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + - "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + - "6Mvf0r1PNTY2hwTJLJmKtg==\n" + - "-----END CERTIFICATE-----"; - - static String serverCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICnzCCAgigAwIBAgIBBzANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3NTdaFw0yODA4MjUwMzI3NTdaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3\n" + - "ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6\n" + - "YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS\n" + - "7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjbjBsMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB\n" + - "MA0GCSqGSIb3DQEBBAUAA4GBAFJjItCtCBZcjD69wdqfIbKmRFa6eJAjR6LcoDva\n" + - "cKC/sDOLelpspiZ66Zb0Xdv5qQ7QrfOXt3K8QqJKRMdZLF9WfUfy0gJDM32ub91h\n" + - "pu+TmcGPs+6RdrAQcuvU1ZDV9X8SMj7BtKaim4d5sqFw1npncKiA5xFn8vOYwdun\n" + - "nZif\n" + - "-----END CERTIFICATE-----"; - - static String clientCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICnzCCAgigAwIBAgIBBjANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3MzRaFw0yODA4MjUwMzI3MzRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + - "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + - "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + - "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjbjBsMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB\n" + - "MA0GCSqGSIb3DQEBBAUAA4GBACjj9PS+W6XOF7toFMwMOv/AemZeBOpcEF1Ei1Hx\n" + - "HjvB6EOHkMY8tFm5OPzkiWiK3+s3awpSW0jWdzMYwrQJ3/klMsPDpI7PEuirqwHP\n" + - "i5Wyl/vk7jmfWVcBO9MVhPUo4BYl4vS9aj6JA5QbkbkB95LOgT/BowY0WmHeVsXC\n" + - "I9aw\n" + - "-----END CERTIFICATE-----"; - - - static byte serverPrivateExponent[] = { - (byte)0x6e, (byte)0xa7, (byte)0x1b, (byte)0x83, - (byte)0x51, (byte)0x35, (byte)0x9a, (byte)0x44, - (byte)0x7d, (byte)0xf6, (byte)0xe3, (byte)0x89, - (byte)0xa0, (byte)0xd7, (byte)0x90, (byte)0x60, - (byte)0xa1, (byte)0x4e, (byte)0x27, (byte)0x21, - (byte)0xa2, (byte)0x89, (byte)0x74, (byte)0xcc, - (byte)0x9d, (byte)0x75, (byte)0x75, (byte)0x4e, - (byte)0xc7, (byte)0x82, (byte)0xe3, (byte)0xe3, - (byte)0xc3, (byte)0x7d, (byte)0x00, (byte)0x54, - (byte)0xec, (byte)0x36, (byte)0xb1, (byte)0xdf, - (byte)0x91, (byte)0x9c, (byte)0x7a, (byte)0xc0, - (byte)0x62, (byte)0x0a, (byte)0xd6, (byte)0xa9, - (byte)0x22, (byte)0x91, (byte)0x4a, (byte)0x29, - (byte)0x2e, (byte)0x43, (byte)0xfa, (byte)0x8c, - (byte)0xd8, (byte)0xe9, (byte)0xbe, (byte)0xd9, - (byte)0x4f, (byte)0xca, (byte)0x23, (byte)0xc6, - (byte)0xe4, (byte)0x3f, (byte)0xb8, (byte)0x72, - (byte)0xcf, (byte)0x02, (byte)0xfc, (byte)0xf4, - (byte)0x58, (byte)0x34, (byte)0x77, (byte)0x76, - (byte)0xce, (byte)0x22, (byte)0x44, (byte)0x5f, - (byte)0x2d, (byte)0xca, (byte)0xee, (byte)0xf5, - (byte)0x43, (byte)0x56, (byte)0x47, (byte)0x71, - (byte)0x0b, (byte)0x09, (byte)0x6b, (byte)0x5e, - (byte)0xf2, (byte)0xc8, (byte)0xee, (byte)0xd4, - (byte)0x6e, (byte)0x44, (byte)0x92, (byte)0x2a, - (byte)0x7f, (byte)0xcc, (byte)0xa7, (byte)0xd4, - (byte)0x5b, (byte)0xfb, (byte)0xf7, (byte)0x4a, - (byte)0xa9, (byte)0xfb, (byte)0x54, (byte)0x18, - (byte)0xd5, (byte)0xd5, (byte)0x14, (byte)0xba, - (byte)0xa0, (byte)0x1c, (byte)0x13, (byte)0xb3, - (byte)0x37, (byte)0x6b, (byte)0x37, (byte)0x59, - (byte)0xed, (byte)0xdb, (byte)0x6d, (byte)0xb1 - }; - - static byte serverModulus[] = { - (byte)0x00, - (byte)0xa5, (byte)0xac, (byte)0x5b, (byte)0x1c, - (byte)0x37, (byte)0xa2, (byte)0xdd, (byte)0x99, - (byte)0x89, (byte)0x2d, (byte)0xb2, (byte)0x79, - (byte)0xb8, (byte)0x8f, (byte)0xd5, (byte)0x48, - (byte)0xa5, (byte)0xe7, (byte)0x1c, (byte)0x84, - (byte)0x17, (byte)0x8d, (byte)0x69, (byte)0x9c, - (byte)0xc6, (byte)0xac, (byte)0x6d, (byte)0xf9, - (byte)0xf2, (byte)0x1d, (byte)0x1f, (byte)0x39, - (byte)0x19, (byte)0xda, (byte)0xd3, (byte)0x72, - (byte)0x1e, (byte)0x6e, (byte)0xec, (byte)0x44, - (byte)0xcc, (byte)0x70, (byte)0xa4, (byte)0xdc, - (byte)0xba, (byte)0x00, (byte)0x30, (byte)0xf6, - (byte)0xa0, (byte)0x4f, (byte)0x3d, (byte)0x54, - (byte)0x7a, (byte)0x61, (byte)0x6a, (byte)0xcc, - (byte)0x57, (byte)0xd0, (byte)0x0a, (byte)0x7f, - (byte)0x95, (byte)0x28, (byte)0x18, (byte)0x3f, - (byte)0x9a, (byte)0xd9, (byte)0x94, (byte)0xf2, - (byte)0x1b, (byte)0xc8, (byte)0x24, (byte)0x88, - (byte)0x7e, (byte)0xfe, (byte)0x9d, (byte)0x0f, - (byte)0x3d, (byte)0xfb, (byte)0x57, (byte)0x53, - (byte)0x08, (byte)0xb3, (byte)0x20, (byte)0x33, - (byte)0xd4, (byte)0x3f, (byte)0x17, (byte)0x47, - (byte)0x14, (byte)0xd1, (byte)0xcd, (byte)0xea, - (byte)0x08, (byte)0xd8, (byte)0x0e, (byte)0x75, - (byte)0x4e, (byte)0xaf, (byte)0xbe, (byte)0xcc, - (byte)0xd2, (byte)0xec, (byte)0xaf, (byte)0xa9, - (byte)0x7a, (byte)0x49, (byte)0xdf, (byte)0xc2, - (byte)0xd9, (byte)0xac, (byte)0xb8, (byte)0x24, - (byte)0x40, (byte)0x90, (byte)0xa6, (byte)0x03, - (byte)0x56, (byte)0x2a, (byte)0xd0, (byte)0x30, - (byte)0x05, (byte)0x40, (byte)0x2c, (byte)0x4f, - (byte)0xab, (byte)0xd9, (byte)0x74, (byte)0x89 - }; - - static byte clientPrivateExponent[] = { - (byte)0x11, (byte)0xb7, (byte)0x6a, (byte)0x36, - (byte)0x3d, (byte)0x30, (byte)0x37, (byte)0xce, - (byte)0x61, (byte)0x9d, (byte)0x6c, (byte)0x84, - (byte)0x8b, (byte)0xf3, (byte)0x9b, (byte)0x25, - (byte)0x4f, (byte)0x14, (byte)0xc8, (byte)0xa4, - (byte)0xdd, (byte)0x2f, (byte)0xd7, (byte)0x9a, - (byte)0x17, (byte)0xbd, (byte)0x90, (byte)0x19, - (byte)0xf7, (byte)0x05, (byte)0xfd, (byte)0xf2, - (byte)0xd2, (byte)0xc5, (byte)0xf7, (byte)0x77, - (byte)0xbe, (byte)0xea, (byte)0xe2, (byte)0x84, - (byte)0x87, (byte)0x97, (byte)0x3a, (byte)0x41, - (byte)0x96, (byte)0xb6, (byte)0x99, (byte)0xf8, - (byte)0x94, (byte)0x8c, (byte)0x58, (byte)0x71, - (byte)0x51, (byte)0x8c, (byte)0xf4, (byte)0x2a, - (byte)0x20, (byte)0x9e, (byte)0x1a, (byte)0xa0, - (byte)0x26, (byte)0x99, (byte)0x75, (byte)0xd6, - (byte)0x31, (byte)0x53, (byte)0x43, (byte)0x39, - (byte)0xf5, (byte)0x2a, (byte)0xa6, (byte)0x7e, - (byte)0x34, (byte)0x42, (byte)0x51, (byte)0x2a, - (byte)0x40, (byte)0x87, (byte)0x03, (byte)0x88, - (byte)0x43, (byte)0x69, (byte)0xb2, (byte)0x89, - (byte)0x6d, (byte)0x20, (byte)0xbd, (byte)0x7d, - (byte)0x71, (byte)0xef, (byte)0x47, (byte)0x0a, - (byte)0xdf, (byte)0x06, (byte)0xc1, (byte)0x69, - (byte)0x66, (byte)0xa8, (byte)0x22, (byte)0x37, - (byte)0x1a, (byte)0x77, (byte)0x1e, (byte)0xc7, - (byte)0x94, (byte)0x4e, (byte)0x2c, (byte)0x27, - (byte)0x69, (byte)0x45, (byte)0x5e, (byte)0xc8, - (byte)0xf8, (byte)0x0c, (byte)0xb7, (byte)0xf8, - (byte)0xc0, (byte)0x8f, (byte)0x99, (byte)0xc1, - (byte)0xe5, (byte)0x28, (byte)0x9b, (byte)0xf9, - (byte)0x4c, (byte)0x94, (byte)0xc6, (byte)0xb1 - }; - - static byte clientModulus[] = { - (byte)0x00, - (byte)0xbb, (byte)0xf0, (byte)0x40, (byte)0x36, - (byte)0xac, (byte)0x26, (byte)0x54, (byte)0x4e, - (byte)0xf4, (byte)0xa3, (byte)0x5a, (byte)0x00, - (byte)0x2f, (byte)0x69, (byte)0x21, (byte)0x6f, - (byte)0xb9, (byte)0x7a, (byte)0x3a, (byte)0x93, - (byte)0xec, (byte)0xa2, (byte)0xf6, (byte)0xe1, - (byte)0x8e, (byte)0xc7, (byte)0x63, (byte)0xd8, - (byte)0x2f, (byte)0x12, (byte)0x30, (byte)0x99, - (byte)0x2e, (byte)0xb0, (byte)0xf2, (byte)0x8f, - (byte)0xf8, (byte)0x27, (byte)0x2d, (byte)0x24, - (byte)0x78, (byte)0x28, (byte)0x84, (byte)0xf7, - (byte)0x01, (byte)0xbf, (byte)0x8d, (byte)0x44, - (byte)0x79, (byte)0xdd, (byte)0x3b, (byte)0xd2, - (byte)0x55, (byte)0xf3, (byte)0xce, (byte)0x3c, - (byte)0xb2, (byte)0x5b, (byte)0x21, (byte)0x7d, - (byte)0xef, (byte)0xfd, (byte)0x33, (byte)0x4a, - (byte)0xb1, (byte)0xa3, (byte)0xff, (byte)0xc6, - (byte)0xc8, (byte)0x9b, (byte)0xb9, (byte)0x0f, - (byte)0x7c, (byte)0x41, (byte)0x35, (byte)0x97, - (byte)0xf9, (byte)0xdb, (byte)0x3a, (byte)0x05, - (byte)0x60, (byte)0x05, (byte)0x15, (byte)0xaf, - (byte)0x59, (byte)0x17, (byte)0x92, (byte)0xa3, - (byte)0x10, (byte)0xad, (byte)0x16, (byte)0x1c, - (byte)0xe4, (byte)0x07, (byte)0x53, (byte)0xaf, - (byte)0xa8, (byte)0x76, (byte)0xa2, (byte)0x56, - (byte)0x2a, (byte)0x92, (byte)0xd3, (byte)0xf9, - (byte)0x28, (byte)0xe0, (byte)0x78, (byte)0xcf, - (byte)0x5e, (byte)0x1f, (byte)0x48, (byte)0xab, - (byte)0x5c, (byte)0x19, (byte)0xdd, (byte)0xe1, - (byte)0x67, (byte)0x43, (byte)0xba, (byte)0x75, - (byte)0x8d, (byte)0xf5, (byte)0x82, (byte)0xac, - (byte)0x43, (byte)0x92, (byte)0x44, (byte)0x1b - }; - - static char passphrase[] = "passphrase".toCharArray(); - /* * Is the server ready to serve? */ @@ -636,10 +85,6 @@ public class IPAddressIPIdentities { */ volatile static boolean closeReady = false; - /* - * Turn on SSL debugging? - */ - static boolean debug = false; private SSLServerSocket sslServerSocket = null; @@ -650,8 +95,7 @@ public class IPAddressIPIdentities { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLContext context = getSSLContext(trusedCertStr, serverCertStr, - serverModulus, serverPrivateExponent, passphrase); + SSLContext context = getServerSSLContext(); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); // doClientSide() connects to the loopback address @@ -706,8 +150,7 @@ public class IPAddressIPIdentities { void doClientSide() throws Exception { SSLContext reservedSSLContext = SSLContext.getDefault(); try { - SSLContext context = getSSLContext(trusedCertStr, clientCertStr, - clientModulus, clientPrivateExponent, passphrase); + SSLContext context = getClientSSLContext(); SSLContext.setDefault(context); @@ -757,11 +200,11 @@ public class IPAddressIPIdentities { volatile Exception clientException = null; public static void main(String args[]) throws Exception { - // MD5 is used in this test case, don't disable MD5 algorithm. - Security.setProperty("jdk.certpath.disabledAlgorithms", - "MD2, RSA keySize < 1024"); - Security.setProperty("jdk.tls.disabledAlgorithms", - "SSLv3, RC4, DH keySize < 768"); + if (args[1].contains("MD5")) { + SecurityUtils.removeFromDisabledAlgs( + "jdk.certpath.disabledAlgorithms", List.of("MD5")); + SecurityUtils.removeFromDisabledTlsAlgs("MD5"); + } if (debug) System.setProperty("javax.net.debug", "all"); @@ -769,7 +212,7 @@ public class IPAddressIPIdentities { /* * Start the tests. */ - new IPAddressIPIdentities(); + new IPAddressIPIdentities(args[0], args[1]); } Thread clientThread = null; @@ -779,7 +222,9 @@ public class IPAddressIPIdentities { * * Fork off the other side, then do your work. */ - IPAddressIPIdentities() throws Exception { + IPAddressIPIdentities(String protocol, String signatureAlg) throws Exception { + super(protocol, signatureAlg); + if (separateServerThread) { startServer(true); startClient(false); @@ -854,65 +299,4 @@ public class IPAddressIPIdentities { doClientSide(); } } - - // get the ssl context - private static SSLContext getSSLContext(String trusedCertStr, - String keyCertStr, byte[] modulus, - byte[] privateExponent, char[] passphrase) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - ByteArrayInputStream is = - new ByteArrayInputStream(trusedCertStr.getBytes()); - Certificate trusedCert = cf.generateCertificate(is); - is.close(); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - ks.setCertificateEntry("RSA Export Signer", trusedCert); - - if (keyCertStr != null) { - // generate the private key. - RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec( - new BigInteger(modulus), - new BigInteger(privateExponent)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - - // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLSv1.2"); - - if (keyCertStr != null) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; - } - } diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java deleted file mode 100644 index 9ce71064b54..00000000000 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -// -// SunJSSE does not support dynamic system properties, no way to re-use -// system properties in samevm/agentvm mode. -// - -/* @test - * @summary X509 certificate hostname checking is broken in JDK1.6.0_10 - * @bug 6766775 - * @library /test/lib - * @run main/othervm IPIdentities - * @author Xuelei Fan - */ - - -import java.io.PrintStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.URL; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.KeyStore; -import java.security.SecureRandom; -import java.security.Security; -import java.security.cert.X509Certificate; - -import java.security.cert.Certificate; -import java.math.BigInteger; -import jdk.test.lib.net.URIBuilder; -import jdk.test.lib.security.CertificateBuilder; -import jdk.test.lib.security.CertificateBuilder.KeyUsage; -import sun.security.x509.AuthorityKeyIdentifierExtension; -import sun.security.x509.GeneralName; -import sun.security.x509.GeneralNames; -import sun.security.x509.KeyIdentifier; -import sun.security.x509.SerialNumber; -import sun.security.x509.X500Name; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLServerSocket; -import javax.net.ssl.SSLServerSocketFactory; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.TrustManagerFactory; - - -public class IPIdentities { - - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ - - /* - * Should we run the client or server in a separate thread? - * Both sides can throw exceptions, but do you have a preference - * as to which side should be the main thread. - */ - static boolean separateServerThread = true; - - static X509Certificate trustedCert; - - static X509Certificate serverCert; - - static X509Certificate clientCert; - - static KeyPair serverKeys; - static KeyPair clientKeys; - - static char passphrase[] = "passphrase".toCharArray(); - - /* - * Is the server ready to serve? - */ - volatile static boolean serverReady = false; - - /* - * Is the connection ready to close? - */ - volatile static boolean closeReady = false; - - /* - * Turn on SSL debugging? - */ - static boolean debug = Boolean.getBoolean("test.debug"); - - private SSLServerSocket sslServerSocket = null; - - /* - * Define the server side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doServerSide() throws Exception { - SSLContext context = getSSLContext(trustedCert, serverCert, - serverKeys, passphrase); - SSLServerSocketFactory sslssf = context.getServerSocketFactory(); - - // doClientSide() connects to the loopback address - InetAddress loopback = InetAddress.getLoopbackAddress(); - InetSocketAddress address = new InetSocketAddress(loopback, serverPort); - - sslServerSocket = - (SSLServerSocket) sslssf.createServerSocket(); - sslServerSocket.bind(address); - serverPort = sslServerSocket.getLocalPort(); - - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; - - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); - sslSocket.setNeedClientAuth(true); - - PrintStream out = - new PrintStream(sslSocket.getOutputStream()); - - try { - // ignore request data - - // send the response - out.print("HTTP/1.1 200 OK\r\n"); - out.print("Content-Type: text/html; charset=iso-8859-1\r\n"); - out.print("Content-Length: "+ 9 +"\r\n"); - out.print("\r\n"); - out.print("Testing\r\n"); - out.flush(); - } finally { - // close the socket - while (!closeReady) { - Thread.sleep(50); - } - - System.out.println("Server closing socket"); - sslSocket.close(); - serverReady = false; - } - - } - - /* - * Define the client side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doClientSide() throws Exception { - SSLContext reservedSSLContext = SSLContext.getDefault(); - try { - SSLContext context = getSSLContext(trustedCert, clientCert, - clientKeys, passphrase); - SSLContext.setDefault(context); - - /* - * Wait for server to get started. - */ - while (!serverReady) { - Thread.sleep(50); - } - - HttpsURLConnection http = null; - - /* establish http connection to server */ - URL url = URIBuilder.newBuilder() - .scheme("https") - .loopback() - .port(serverPort) - .path("/") - .toURL(); - System.out.println("url is "+url.toString()); - - try { - http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY); - - int respCode = http.getResponseCode(); - System.out.println("respCode = "+respCode); - } finally { - if (http != null) { - http.disconnect(); - } - closeReady = true; - } - } finally { - SSLContext.setDefault(reservedSSLContext); - } - } - - /* - * ============================================================= - * The remainder is just support stuff - */ - - // use any free port by default - volatile int serverPort = 0; - - volatile Exception serverException = null; - volatile Exception clientException = null; - - private static X509Certificate createTrustedCert(KeyPair caKeys) throws Exception { - SecureRandom random = new SecureRandom(); - - KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic()); - GeneralNames gns = new GeneralNames(); - GeneralName name = new GeneralName(new X500Name( - "O=Some-Org, L=Some-City, ST=Some-State, C=US")); - gns.add(name); - BigInteger serialNumber = BigInteger.valueOf(random.nextLong(1000000)+1); - return CertificateBuilder.newCertificateBuilder( - "O=Some-Org, L=Some-City, ST=Some-State, C=US", - caKeys.getPublic(), caKeys.getPublic()) - .setSerialNumber(serialNumber) - .addExtension(new AuthorityKeyIdentifierExtension(kid, gns, - new SerialNumber(serialNumber))) - .addBasicConstraintsExt(true, true, -1) - .setOneHourValidity() - .build(null, caKeys.getPrivate(), "MD5WithRSA"); - } - - private static void setupCertificates() throws Exception { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); - KeyPair caKeys = kpg.generateKeyPair(); - serverKeys = kpg.generateKeyPair(); - clientKeys = kpg.generateKeyPair(); - - trustedCert = createTrustedCert(caKeys); - if (debug) { - System.out.println("----------- Trusted Cert -----------"); - CertificateBuilder.printCertificate(trustedCert, System.out); - } - - serverCert = CertificateBuilder.newCertificateBuilder( - "O=Some-Org, L=Some-City, ST=Some-State, C=US", - serverKeys.getPublic(), caKeys.getPublic(), - KeyUsage.DIGITAL_SIGNATURE, KeyUsage.NONREPUDIATION, KeyUsage.KEY_ENCIPHERMENT) - .addBasicConstraintsExt(false, false, -1) - .addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1")) - .setOneHourValidity() - .build(trustedCert, caKeys.getPrivate(), "MD5WithRSA"); - if (debug) { - System.out.println("----------- Server Cert -----------"); - CertificateBuilder.printCertificate(serverCert, System.out); - } - - clientCert = CertificateBuilder.newCertificateBuilder( - "CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US", - clientKeys.getPublic(), caKeys.getPublic(), - KeyUsage.DIGITAL_SIGNATURE, KeyUsage.NONREPUDIATION, KeyUsage.KEY_ENCIPHERMENT) - .addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1")) - .addBasicConstraintsExt(false, false, -1) - .setOneHourValidity() - .build(trustedCert, caKeys.getPrivate(), "MD5WithRSA"); - if (debug) { - System.out.println("----------- Client Cert -----------"); - CertificateBuilder.printCertificate(clientCert, System.out); - } - } - - public static void main(String args[]) throws Exception { - // MD5 is used in this test case, don't disable MD5 algorithm. - Security.setProperty("jdk.certpath.disabledAlgorithms", - "MD2, RSA keySize < 1024"); - Security.setProperty("jdk.tls.disabledAlgorithms", - "SSLv3, RC4, DH keySize < 768"); - - if (debug) { - System.setProperty("javax.net.debug", "all"); - } - - setupCertificates(); - - /* - * Start the tests. - */ - new IPIdentities(); - } - - Thread clientThread = null; - Thread serverThread = null; - /* - * Primary constructor, used to drive remainder of the test. - * - * Fork off the other side, then do your work. - */ - IPIdentities() throws Exception { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } - - /* - * When we get here, the test is pretty much over. - * - * If the main thread excepted, that propagates back - * immediately. If the other thread threw an exception, we - * should report back. - */ - if (serverException != null) - throw serverException; - if (clientException != null) - throw clientException; - } - - void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; - } - } - }; - serverThread.start(); - } else { - doServerSide(); - } - } - - void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } - } - }; - clientThread.start(); - } else { - doClientSide(); - } - } - - // get the ssl context - private static SSLContext getSSLContext(X509Certificate trustedCert, - X509Certificate keyCert, KeyPair key, char[] passphrase) throws Exception { - - // create a key store - KeyStore ks = KeyStore.getInstance("PKCS12"); - ks.load(null, null); - - // import the trused cert - ks.setCertificateEntry("RSA Export Signer", trustedCert); - - if (keyCert != null) { - Certificate[] chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trustedCert; - - // import the key entry. - ks.setKeyEntry("Whatever", key.getPrivate(), passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLSv1.2"); - - if (keyCert != null) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; - } - -} diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java index 53960c05895..d7c69ba98a2 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java @@ -26,386 +26,47 @@ // system properties in samevm/agentvm mode. // -/* @test +/* @test id=tls12 * @bug 6766775 * @summary X509 certificate hostname checking is broken in JDK1.6.0_10 - * @run main/othervm Identities + * @library /test/lib + * @run main/othervm Identities TLSv1.2 MD5withRSA * @author Xuelei Fan */ -import java.net.*; -import java.util.*; -import java.io.*; -import javax.net.ssl.*; -import java.security.Security; -import java.security.KeyStore; -import java.security.KeyFactory; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; -import java.math.BigInteger; -/* - * Certificates and key used in the test. - * - * TLS server certificate: - * server private key: - * -----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,D9AE407F6D0E389A - * - * WPrA7TFol/cQCcp9oHnXWNpYlvRbbIcQj0m+RKT2Iuzfus+DHt3Zadf8nJpKfX2e - * h2rnhlzCN9M7djRDooZKDOPCsdBn51Au7HlZF3S3Opgo7D8XFM1a8t1Je4ke14oI - * nw6QKYsBblRziPnP2PZ0zvX24nOv7bbY8beynlJHGs00VWSFdoH2DS0aE1p6D+3n - * ptJuJ75dVfZFK4X7162APlNXevX8D6PEQpSiRw1rjjGGcnvQ4HdWk3BxDVDcCNJb - * Y1aGNRxsjTDvPi3R9Qx2M+W03QzEPx4SR3ZHVskeSJHaetM0TM/w/45Paq4GokXP - * ZeTnbEx1xmjkA7h+t4doLL4watx5F6yLsJzu8xB3lt/1EtmkYtLz1t7X4BetPAXz - * zS69X/VwhKfsOI3qXBWuL2oHPyhDmT1gcaUQwEPSV6ogHEEQEDXdiUS8heNK13KF - * TCQYFkETvV2BLxUhV1hypPzRQ6tUpJiAbD5KmoK2lD9slshG2QtvKQq0/bgkDY5J - * LhDHV2dtcZ3kDPkkZXpbcJQvoeH3d09C5sIsuTFo2zgNR6oETHUc5TzP6FY2YYRa - * QcK5HcmtsRRiXFm01ac+aMejJUIujjFt84SiKWT/73vC8AmY4tYcJBLjCg4XIxSH - * fdDFLL1YZENNO5ivlp8mdiHqcawx+36L7DrEZQ8RZt6cqST5t/+XTdM74s6k81GT - * pNsa82P2K2zmIUZ/DL2mKjW1vfRByw1NQFEBkN3vdyZxYfM/JyUzX4hbjXBEkh9Q - * QYrcwLKLjis2QzSvK04B3bvRzRb+4ocWiso8ZPAXAIxZFBWDpTMM2A== - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICXAIBAAKBgQClrFscN6LdmYktsnm4j9VIpecchBeNaZzGrG358h0fORna03Ie - * buxEzHCk3LoAMPagTz1UemFqzFfQCn+VKBg/mtmU8hvIJIh+/p0PPftXUwizIDPU - * PxdHFNHN6gjYDnVOr77M0uyvqXpJ38LZrLgkQJCmA1Yq0DAFQCxPq9l0iQIDAQAB - * AoGAbqcbg1E1mkR99uOJoNeQYKFOJyGiiXTMnXV1TseC4+PDfQBU7Dax35GcesBi - * CtapIpFKKS5D+ozY6b7ZT8ojxuQ/uHLPAvz0WDR3ds4iRF8tyu71Q1ZHcQsJa17y - * yO7UbkSSKn/Mp9Rb+/dKqftUGNXVFLqgHBOzN2s3We3bbbECQQDYBPKOg3hkaGHo - * OhpHKqtQ6EVkldihG/3i4WejRonelXN+HRh1KrB2HBx0M8D/qAzP1i3rNSlSHer4 - * 59YRTJnHAkEAxFX/sVYSn07BHv9Zhn6XXct/Cj43z/tKNbzlNbcxqQwQerw3IH51 - * 8UH2YOA+GD3lXbKp+MytoFLWv8zg4YT/LwJAfqan75Z1R6lLffRS49bIiq8jwE16 - * rTrUJ+kv8jKxMqc9B3vXkxpsS1M/+4E8bqgAmvpgAb8xcsvHsBd9ErdukQJBAKs2 - * j67W75BrPjBI34pQ1LEfp56IGWXOrq1kF8IbCjxv3+MYRT6Z6UJFkpRymNPNDjsC - * dgUYgITiGJHUGXuw3lMCQHEHqo9ZtXz92yFT+VhsNc29B8m/sqUJdtCcMd/jGpAF - * u6GHufjqIZBpQsk63wbwESAPZZ+kk1O1kS5GIRLX608= - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * publicExponent: 65537 (0x10001) - * privateExponent: - * 6e:a7:1b:83:51:35:9a:44:7d:f6:e3:89:a0:d7:90: - * 60:a1:4e:27:21:a2:89:74:cc:9d:75:75:4e:c7:82: - * e3:e3:c3:7d:00:54:ec:36:b1:df:91:9c:7a:c0:62: - * 0a:d6:a9:22:91:4a:29:2e:43:fa:8c:d8:e9:be:d9: - * 4f:ca:23:c6:e4:3f:b8:72:cf:02:fc:f4:58:34:77: - * 76:ce:22:44:5f:2d:ca:ee:f5:43:56:47:71:0b:09: - * 6b:5e:f2:c8:ee:d4:6e:44:92:2a:7f:cc:a7:d4:5b: - * fb:f7:4a:a9:fb:54:18:d5:d5:14:ba:a0:1c:13:b3: - * 37:6b:37:59:ed:db:6d:b1 - * prime1: - * 00:d8:04:f2:8e:83:78:64:68:61:e8:3a:1a:47:2a: - * ab:50:e8:45:64:95:d8:a1:1b:fd:e2:e1:67:a3:46: - * 89:de:95:73:7e:1d:18:75:2a:b0:76:1c:1c:74:33: - * c0:ff:a8:0c:cf:d6:2d:eb:35:29:52:1d:ea:f8:e7: - * d6:11:4c:99:c7 - * prime2: - * 00:c4:55:ff:b1:56:12:9f:4e:c1:1e:ff:59:86:7e: - * 97:5d:cb:7f:0a:3e:37:cf:fb:4a:35:bc:e5:35:b7: - * 31:a9:0c:10:7a:bc:37:20:7e:75:f1:41:f6:60:e0: - * 3e:18:3d:e5:5d:b2:a9:f8:cc:ad:a0:52:d6:bf:cc: - * e0:e1:84:ff:2f - * exponent1: - * 7e:a6:a7:ef:96:75:47:a9:4b:7d:f4:52:e3:d6:c8: - * 8a:af:23:c0:4d:7a:ad:3a:d4:27:e9:2f:f2:32:b1: - * 32:a7:3d:07:7b:d7:93:1a:6c:4b:53:3f:fb:81:3c: - * 6e:a8:00:9a:fa:60:01:bf:31:72:cb:c7:b0:17:7d: - * 12:b7:6e:91 - * exponent2: - * 00:ab:36:8f:ae:d6:ef:90:6b:3e:30:48:df:8a:50: - * d4:b1:1f:a7:9e:88:19:65:ce:ae:ad:64:17:c2:1b: - * 0a:3c:6f:df:e3:18:45:3e:99:e9:42:45:92:94:72: - * 98:d3:cd:0e:3b:02:76:05:18:80:84:e2:18:91:d4: - * 19:7b:b0:de:53 - * coefficient: - * 71:07:aa:8f:59:b5:7c:fd:db:21:53:f9:58:6c:35: - * cd:bd:07:c9:bf:b2:a5:09:76:d0:9c:31:df:e3:1a: - * 90:05:bb:a1:87:b9:f8:ea:21:90:69:42:c9:3a:df: - * 06:f0:11:20:0f:65:9f:a4:93:53:b5:91:2e:46:21: - * 12:d7:eb:4f - * - * - * server certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 4 (0x4) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:21:16 2008 GMT - * Not After : Aug 25 03:21:16 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Server, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * ED:6E:DB:F4:B5:56:C8:FB:1A:06:61:3F:0F:08:BB:A6:04:D8:16:54 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * IP Address:127.0.0.1, DNS:localhost - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICqjCCAhOgAwIBAgIBBDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzIxMTZaFw0yODA4MjUwMzIxMTZaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3 - * ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6 - * YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS - * 7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjeTB3MAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAdBgNVHREBAf8EEzARhwR/AAAB - * gglsb2NhbGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAWTrftGaL73lKLgRTrChGR+F6 - * //qvs0OM94IOKVeHz36NO49cMJmhJSbKdiGIkppBgpLIBoWxZlN9NOO9oSXFYZsZ - * rHaAe9/lWMtQM7XpjqjhWVhB5VPvWFbkorQFMtRYLf7pkonGPFq8GOO1s0TKhogC - * jtYCdzlrU4v+om/J3H8= - * -----END CERTIFICATE----- - * - * - * TLS client certificate: - * client private key: - * ----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,FA2A435CD35A9390 - * - * Z+Y2uaETbsUWIyJUyVu1UV2G4rgFYJyACZT6Tp1KjRtxflSh2kXkJ9MpuXMXA0V4 - * Yy3fDzPqCL9NJmQAYRlAx/W/+j4F5EyMWDIx8fUxzONRZyoiwF7jLm+KscAfv6Pf - * q7ItWOdj3z7IYrwlB8YIGd3F2cDKT3S+lYRk7rKb/qT7itbuHnY4Ardh3yl+MZak - * jBp+ELUlRsUqSr1V0LoM+0rCCykarpyfhpxEcqsrl0v9Cyi5uhU50/oKv5zql3SH - * l2ImgDjp3batAs8+Bd4NF2aqi0a7Hy44JUHxRm4caZryU/i/D9N1MbuM6882HLat - * 5N0G+NaIUfywa8mjwq2D5aiit18HqKA6XeRRYeJ5Dvu9DCO4GeFSwcUFIBMI0L46 - * 7s114+oDodg57pMgITi+04vmUxvqlN9aiyd7f5Fgd7PeHGeOdbMz1NaJLJaPI9++ - * NakK8eK9iwT/Gdq0Uap5/CHW7vCT5PO+h3HY0STH0lWStXhdWnFO04zTdywsbSp+ - * DLpHeFT66shfeUlxR0PsCbG9vPRt/QmGLeYQZITppWo/ylSq4j+pRIuXvuWHdBRN - * rTZ8QF4Y7AxQUXVz1j1++s6ZMHTzaK2i9HrhmDs1MbJl+QwWre3Xpv3LvTVz3k5U - * wX8kuY1m3STt71QCaRWENq5sRaMImLxZbxc/ivFl9RAzUqo4NCxLod/QgA4iLqtO - * ztnlpzwlC/F8HbQ1oqYWwnZAPhzU/cULtstl+Yrws2c2atO323LbPXZqbASySgig - * sNpFXQMObdfP6LN23bY+1SvtK7V4NUTNhpdIc6INQAQ= - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICWwIBAAKBgQC78EA2rCZUTvSjWgAvaSFvuXo6k+yi9uGOx2PYLxIwmS6w8o/4 - * Jy0keCiE9wG/jUR53TvSVfPOPLJbIX3v/TNKsaP/xsibuQ98QTWX+ds6BWAFFa9Z - * F5KjEK0WHOQHU6+odqJWKpLT+SjgeM9eH0irXBnd4WdDunWN9YKsQ5JEGwIDAQAB - * AoGAEbdqNj0wN85hnWyEi/ObJU8UyKTdL9eaF72QGfcF/fLSxfd3vurihIeXOkGW - * tpn4lIxYcVGM9CognhqgJpl11jFTQzn1KqZ+NEJRKkCHA4hDabKJbSC9fXHvRwrf - * BsFpZqgiNxp3HseUTiwnaUVeyPgMt/jAj5nB5Sib+UyUxrECQQDnNQBiF2aifEg6 - * zbJOOC7he5CHAdkFxSxWVFVHL6EfXfqdLVkUohMbgZv+XxyIeU2biOExSg49Kds3 - * FOKgTau1AkEA0Bd1haj6QuCo8I0AXm2WO+MMTZMTvtHD/bGjKNM+fT4I8rKYnQRX - * 1acHdqS9Xx2rNJqZgkMmpESIdPR2fc4yjwJALFeM6EMmqvj8/VIf5UJ/Mz14fXwM - * PEARfckUxd9LnnFutCBTWlKvKXJVEZb6KO5ixPaegc57Jp3Vbh3yTN44lQJADD/1 - * SSMDaIB1MYP7a5Oj7m6VQNPRq8AJe5vDcRnOae0G9dKRrVyeFxO4GsHj6/+BHp2j - * P8nYMn9eURQ7DXjf/QJAAQzMlWnKGSO8pyTDtnQx3hRMoUkOEhmNq4bQhLkYqtnY - * FcqpUQ2qMjW+NiNWk5HnTrMS3L9EdJobMUzaNZLy4w== - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * publicExponent: 65537 (0x10001) - * privateExponent: - * 11:b7:6a:36:3d:30:37:ce:61:9d:6c:84:8b:f3:9b: - * 25:4f:14:c8:a4:dd:2f:d7:9a:17:bd:90:19:f7:05: - * fd:f2:d2:c5:f7:77:be:ea:e2:84:87:97:3a:41:96: - * b6:99:f8:94:8c:58:71:51:8c:f4:2a:20:9e:1a:a0: - * 26:99:75:d6:31:53:43:39:f5:2a:a6:7e:34:42:51: - * 2a:40:87:03:88:43:69:b2:89:6d:20:bd:7d:71:ef: - * 47:0a:df:06:c1:69:66:a8:22:37:1a:77:1e:c7:94: - * 4e:2c:27:69:45:5e:c8:f8:0c:b7:f8:c0:8f:99:c1: - * e5:28:9b:f9:4c:94:c6:b1 - * prime1: - * 00:e7:35:00:62:17:66:a2:7c:48:3a:cd:b2:4e:38: - * 2e:e1:7b:90:87:01:d9:05:c5:2c:56:54:55:47:2f: - * a1:1f:5d:fa:9d:2d:59:14:a2:13:1b:81:9b:fe:5f: - * 1c:88:79:4d:9b:88:e1:31:4a:0e:3d:29:db:37:14: - * e2:a0:4d:ab:b5 - * prime2: - * 00:d0:17:75:85:a8:fa:42:e0:a8:f0:8d:00:5e:6d: - * 96:3b:e3:0c:4d:93:13:be:d1:c3:fd:b1:a3:28:d3: - * 3e:7d:3e:08:f2:b2:98:9d:04:57:d5:a7:07:76:a4: - * bd:5f:1d:ab:34:9a:99:82:43:26:a4:44:88:74:f4: - * 76:7d:ce:32:8f - * exponent1: - * 2c:57:8c:e8:43:26:aa:f8:fc:fd:52:1f:e5:42:7f: - * 33:3d:78:7d:7c:0c:3c:40:11:7d:c9:14:c5:df:4b: - * 9e:71:6e:b4:20:53:5a:52:af:29:72:55:11:96:fa: - * 28:ee:62:c4:f6:9e:81:ce:7b:26:9d:d5:6e:1d:f2: - * 4c:de:38:95 - * exponent2: - * 0c:3f:f5:49:23:03:68:80:75:31:83:fb:6b:93:a3: - * ee:6e:95:40:d3:d1:ab:c0:09:7b:9b:c3:71:19:ce: - * 69:ed:06:f5:d2:91:ad:5c:9e:17:13:b8:1a:c1:e3: - * eb:ff:81:1e:9d:a3:3f:c9:d8:32:7f:5e:51:14:3b: - * 0d:78:df:fd - * coefficient: - * 01:0c:cc:95:69:ca:19:23:bc:a7:24:c3:b6:74:31: - * de:14:4c:a1:49:0e:12:19:8d:ab:86:d0:84:b9:18: - * aa:d9:d8:15:ca:a9:51:0d:aa:32:35:be:36:23:56: - * 93:91:e7:4e:b3:12:dc:bf:44:74:9a:1b:31:4c:da: - * 35:92:f2:e3 - * - * client certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 5 (0x5) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:22:10 2008 GMT - * Not After : Aug 25 03:22:10 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * IP Address:127.0.0.1, DNS:localhost - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICqjCCAhOgAwIBAgIBBTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzIyMTBaFw0yODA4MjUwMzIyMTBaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas - * JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV - * 8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq - * ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjeTB3MAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAdBgNVHREBAf8EEzARhwR/AAAB - * gglsb2NhbGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAwDc4f13abs9ZeEkrl5WV2Z74 - * BlmBhXu8ExtAvoF9q6Ug6xV1MDpxbD124KfUHHL0kNMhMB1WIpC0kOnQBxziNpfS - * 7u6GOc3tWLSxw/sHoJGCefnRBllLZOoQuSBrWB8qgilL6HRmZ4UqDcXu4UCaLBZ0 - * KGDT5ASEN6Lq2GtiP4Y= - * -----END CERTIFICATE----- - * - * - * - * Trusted CA certificate: - * Certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 0 (0x0) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 02:43:36 2008 GMT - * Not After : Aug 25 02:43:36 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: - * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: - * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: - * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: - * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: - * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: - * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: - * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: - * 89:2a:95:12:4c:d8:09:2a:e9 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Subject Key Identifier: - * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org - * serial:00 - * - * X509v3 Basic Constraints: - * CA:TRUE - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB - * gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX - * 4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj - * 7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G - * A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ - * hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt - * U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw - * DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA - * ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ - * LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P - * 6Mvf0r1PNTY2hwTJLJmKtg== - * -----END CERTIFICATE--- +/* @test id=tls13 + * @bug 6766775 + * @summary X509 certificate hostname checking is broken in JDK1.6.0_10 + * @library /test/lib + * @run main/othervm Identities TLSv1.3 SHA256withRSA + * @author Xuelei Fan */ +import jdk.test.lib.security.CertificateBuilder; +import jdk.test.lib.security.SecurityUtils; +import sun.security.x509.DNSName; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.IPAddressName; +import sun.security.x509.SubjectAlternativeNameExtension; -public class Identities { - static Map cookies; - ServerSocket ss; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.util.List; + + + +public class Identities extends IdentitiesBase { /* * ============================================================= * Set the various variables needed for the tests, then @@ -419,210 +80,6 @@ public class Identities { */ static boolean separateServerThread = true; - /* - * Where do we find the keystores? - */ - static String trusedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + - "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + - "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + - "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + - "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + - "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + - "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + - "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + - "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + - "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + - "6Mvf0r1PNTY2hwTJLJmKtg==\n" + - "-----END CERTIFICATE-----"; - - static String serverCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICqjCCAhOgAwIBAgIBBDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzIxMTZaFw0yODA4MjUwMzIxMTZaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3\n" + - "ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6\n" + - "YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS\n" + - "7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjeTB3MAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAdBgNVHREBAf8EEzARhwR/AAAB\n" + - "gglsb2NhbGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAWTrftGaL73lKLgRTrChGR+F6\n" + - "//qvs0OM94IOKVeHz36NO49cMJmhJSbKdiGIkppBgpLIBoWxZlN9NOO9oSXFYZsZ\n" + - "rHaAe9/lWMtQM7XpjqjhWVhB5VPvWFbkorQFMtRYLf7pkonGPFq8GOO1s0TKhogC\n" + - "jtYCdzlrU4v+om/J3H8=\n" + - "-----END CERTIFICATE-----"; - - static String clientCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICqjCCAhOgAwIBAgIBBTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzIyMTBaFw0yODA4MjUwMzIyMTBaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + - "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + - "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + - "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjeTB3MAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAdBgNVHREBAf8EEzARhwR/AAAB\n" + - "gglsb2NhbGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAwDc4f13abs9ZeEkrl5WV2Z74\n" + - "BlmBhXu8ExtAvoF9q6Ug6xV1MDpxbD124KfUHHL0kNMhMB1WIpC0kOnQBxziNpfS\n" + - "7u6GOc3tWLSxw/sHoJGCefnRBllLZOoQuSBrWB8qgilL6HRmZ4UqDcXu4UCaLBZ0\n" + - "KGDT5ASEN6Lq2GtiP4Y=\n" + - "-----END CERTIFICATE-----"; - - static byte serverPrivateExponent[] = { - (byte)0x6e, (byte)0xa7, (byte)0x1b, (byte)0x83, - (byte)0x51, (byte)0x35, (byte)0x9a, (byte)0x44, - (byte)0x7d, (byte)0xf6, (byte)0xe3, (byte)0x89, - (byte)0xa0, (byte)0xd7, (byte)0x90, (byte)0x60, - (byte)0xa1, (byte)0x4e, (byte)0x27, (byte)0x21, - (byte)0xa2, (byte)0x89, (byte)0x74, (byte)0xcc, - (byte)0x9d, (byte)0x75, (byte)0x75, (byte)0x4e, - (byte)0xc7, (byte)0x82, (byte)0xe3, (byte)0xe3, - (byte)0xc3, (byte)0x7d, (byte)0x00, (byte)0x54, - (byte)0xec, (byte)0x36, (byte)0xb1, (byte)0xdf, - (byte)0x91, (byte)0x9c, (byte)0x7a, (byte)0xc0, - (byte)0x62, (byte)0x0a, (byte)0xd6, (byte)0xa9, - (byte)0x22, (byte)0x91, (byte)0x4a, (byte)0x29, - (byte)0x2e, (byte)0x43, (byte)0xfa, (byte)0x8c, - (byte)0xd8, (byte)0xe9, (byte)0xbe, (byte)0xd9, - (byte)0x4f, (byte)0xca, (byte)0x23, (byte)0xc6, - (byte)0xe4, (byte)0x3f, (byte)0xb8, (byte)0x72, - (byte)0xcf, (byte)0x02, (byte)0xfc, (byte)0xf4, - (byte)0x58, (byte)0x34, (byte)0x77, (byte)0x76, - (byte)0xce, (byte)0x22, (byte)0x44, (byte)0x5f, - (byte)0x2d, (byte)0xca, (byte)0xee, (byte)0xf5, - (byte)0x43, (byte)0x56, (byte)0x47, (byte)0x71, - (byte)0x0b, (byte)0x09, (byte)0x6b, (byte)0x5e, - (byte)0xf2, (byte)0xc8, (byte)0xee, (byte)0xd4, - (byte)0x6e, (byte)0x44, (byte)0x92, (byte)0x2a, - (byte)0x7f, (byte)0xcc, (byte)0xa7, (byte)0xd4, - (byte)0x5b, (byte)0xfb, (byte)0xf7, (byte)0x4a, - (byte)0xa9, (byte)0xfb, (byte)0x54, (byte)0x18, - (byte)0xd5, (byte)0xd5, (byte)0x14, (byte)0xba, - (byte)0xa0, (byte)0x1c, (byte)0x13, (byte)0xb3, - (byte)0x37, (byte)0x6b, (byte)0x37, (byte)0x59, - (byte)0xed, (byte)0xdb, (byte)0x6d, (byte)0xb1 - }; - - static byte serverModulus[] = { - (byte)0x00, - (byte)0xa5, (byte)0xac, (byte)0x5b, (byte)0x1c, - (byte)0x37, (byte)0xa2, (byte)0xdd, (byte)0x99, - (byte)0x89, (byte)0x2d, (byte)0xb2, (byte)0x79, - (byte)0xb8, (byte)0x8f, (byte)0xd5, (byte)0x48, - (byte)0xa5, (byte)0xe7, (byte)0x1c, (byte)0x84, - (byte)0x17, (byte)0x8d, (byte)0x69, (byte)0x9c, - (byte)0xc6, (byte)0xac, (byte)0x6d, (byte)0xf9, - (byte)0xf2, (byte)0x1d, (byte)0x1f, (byte)0x39, - (byte)0x19, (byte)0xda, (byte)0xd3, (byte)0x72, - (byte)0x1e, (byte)0x6e, (byte)0xec, (byte)0x44, - (byte)0xcc, (byte)0x70, (byte)0xa4, (byte)0xdc, - (byte)0xba, (byte)0x00, (byte)0x30, (byte)0xf6, - (byte)0xa0, (byte)0x4f, (byte)0x3d, (byte)0x54, - (byte)0x7a, (byte)0x61, (byte)0x6a, (byte)0xcc, - (byte)0x57, (byte)0xd0, (byte)0x0a, (byte)0x7f, - (byte)0x95, (byte)0x28, (byte)0x18, (byte)0x3f, - (byte)0x9a, (byte)0xd9, (byte)0x94, (byte)0xf2, - (byte)0x1b, (byte)0xc8, (byte)0x24, (byte)0x88, - (byte)0x7e, (byte)0xfe, (byte)0x9d, (byte)0x0f, - (byte)0x3d, (byte)0xfb, (byte)0x57, (byte)0x53, - (byte)0x08, (byte)0xb3, (byte)0x20, (byte)0x33, - (byte)0xd4, (byte)0x3f, (byte)0x17, (byte)0x47, - (byte)0x14, (byte)0xd1, (byte)0xcd, (byte)0xea, - (byte)0x08, (byte)0xd8, (byte)0x0e, (byte)0x75, - (byte)0x4e, (byte)0xaf, (byte)0xbe, (byte)0xcc, - (byte)0xd2, (byte)0xec, (byte)0xaf, (byte)0xa9, - (byte)0x7a, (byte)0x49, (byte)0xdf, (byte)0xc2, - (byte)0xd9, (byte)0xac, (byte)0xb8, (byte)0x24, - (byte)0x40, (byte)0x90, (byte)0xa6, (byte)0x03, - (byte)0x56, (byte)0x2a, (byte)0xd0, (byte)0x30, - (byte)0x05, (byte)0x40, (byte)0x2c, (byte)0x4f, - (byte)0xab, (byte)0xd9, (byte)0x74, (byte)0x89 - }; - - static byte clientPrivateExponent[] = { - (byte)0x11, (byte)0xb7, (byte)0x6a, (byte)0x36, - (byte)0x3d, (byte)0x30, (byte)0x37, (byte)0xce, - (byte)0x61, (byte)0x9d, (byte)0x6c, (byte)0x84, - (byte)0x8b, (byte)0xf3, (byte)0x9b, (byte)0x25, - (byte)0x4f, (byte)0x14, (byte)0xc8, (byte)0xa4, - (byte)0xdd, (byte)0x2f, (byte)0xd7, (byte)0x9a, - (byte)0x17, (byte)0xbd, (byte)0x90, (byte)0x19, - (byte)0xf7, (byte)0x05, (byte)0xfd, (byte)0xf2, - (byte)0xd2, (byte)0xc5, (byte)0xf7, (byte)0x77, - (byte)0xbe, (byte)0xea, (byte)0xe2, (byte)0x84, - (byte)0x87, (byte)0x97, (byte)0x3a, (byte)0x41, - (byte)0x96, (byte)0xb6, (byte)0x99, (byte)0xf8, - (byte)0x94, (byte)0x8c, (byte)0x58, (byte)0x71, - (byte)0x51, (byte)0x8c, (byte)0xf4, (byte)0x2a, - (byte)0x20, (byte)0x9e, (byte)0x1a, (byte)0xa0, - (byte)0x26, (byte)0x99, (byte)0x75, (byte)0xd6, - (byte)0x31, (byte)0x53, (byte)0x43, (byte)0x39, - (byte)0xf5, (byte)0x2a, (byte)0xa6, (byte)0x7e, - (byte)0x34, (byte)0x42, (byte)0x51, (byte)0x2a, - (byte)0x40, (byte)0x87, (byte)0x03, (byte)0x88, - (byte)0x43, (byte)0x69, (byte)0xb2, (byte)0x89, - (byte)0x6d, (byte)0x20, (byte)0xbd, (byte)0x7d, - (byte)0x71, (byte)0xef, (byte)0x47, (byte)0x0a, - (byte)0xdf, (byte)0x06, (byte)0xc1, (byte)0x69, - (byte)0x66, (byte)0xa8, (byte)0x22, (byte)0x37, - (byte)0x1a, (byte)0x77, (byte)0x1e, (byte)0xc7, - (byte)0x94, (byte)0x4e, (byte)0x2c, (byte)0x27, - (byte)0x69, (byte)0x45, (byte)0x5e, (byte)0xc8, - (byte)0xf8, (byte)0x0c, (byte)0xb7, (byte)0xf8, - (byte)0xc0, (byte)0x8f, (byte)0x99, (byte)0xc1, - (byte)0xe5, (byte)0x28, (byte)0x9b, (byte)0xf9, - (byte)0x4c, (byte)0x94, (byte)0xc6, (byte)0xb1 - }; - - static byte clientModulus[] = { - (byte)0x00, - (byte)0xbb, (byte)0xf0, (byte)0x40, (byte)0x36, - (byte)0xac, (byte)0x26, (byte)0x54, (byte)0x4e, - (byte)0xf4, (byte)0xa3, (byte)0x5a, (byte)0x00, - (byte)0x2f, (byte)0x69, (byte)0x21, (byte)0x6f, - (byte)0xb9, (byte)0x7a, (byte)0x3a, (byte)0x93, - (byte)0xec, (byte)0xa2, (byte)0xf6, (byte)0xe1, - (byte)0x8e, (byte)0xc7, (byte)0x63, (byte)0xd8, - (byte)0x2f, (byte)0x12, (byte)0x30, (byte)0x99, - (byte)0x2e, (byte)0xb0, (byte)0xf2, (byte)0x8f, - (byte)0xf8, (byte)0x27, (byte)0x2d, (byte)0x24, - (byte)0x78, (byte)0x28, (byte)0x84, (byte)0xf7, - (byte)0x01, (byte)0xbf, (byte)0x8d, (byte)0x44, - (byte)0x79, (byte)0xdd, (byte)0x3b, (byte)0xd2, - (byte)0x55, (byte)0xf3, (byte)0xce, (byte)0x3c, - (byte)0xb2, (byte)0x5b, (byte)0x21, (byte)0x7d, - (byte)0xef, (byte)0xfd, (byte)0x33, (byte)0x4a, - (byte)0xb1, (byte)0xa3, (byte)0xff, (byte)0xc6, - (byte)0xc8, (byte)0x9b, (byte)0xb9, (byte)0x0f, - (byte)0x7c, (byte)0x41, (byte)0x35, (byte)0x97, - (byte)0xf9, (byte)0xdb, (byte)0x3a, (byte)0x05, - (byte)0x60, (byte)0x05, (byte)0x15, (byte)0xaf, - (byte)0x59, (byte)0x17, (byte)0x92, (byte)0xa3, - (byte)0x10, (byte)0xad, (byte)0x16, (byte)0x1c, - (byte)0xe4, (byte)0x07, (byte)0x53, (byte)0xaf, - (byte)0xa8, (byte)0x76, (byte)0xa2, (byte)0x56, - (byte)0x2a, (byte)0x92, (byte)0xd3, (byte)0xf9, - (byte)0x28, (byte)0xe0, (byte)0x78, (byte)0xcf, - (byte)0x5e, (byte)0x1f, (byte)0x48, (byte)0xab, - (byte)0x5c, (byte)0x19, (byte)0xdd, (byte)0xe1, - (byte)0x67, (byte)0x43, (byte)0xba, (byte)0x75, - (byte)0x8d, (byte)0xf5, (byte)0x82, (byte)0xac, - (byte)0x43, (byte)0x92, (byte)0x44, (byte)0x1b - }; - - static char passphrase[] = "passphrase".toCharArray(); - /* * Is the server ready to serve? */ @@ -633,13 +90,26 @@ public class Identities { */ volatile static boolean closeReady = false; - /* - * Turn on SSL debugging? - */ - static boolean debug = false; private SSLServerSocket sslServerSocket = null; + + @Override + protected CertificateBuilder customizeServerCert(CertificateBuilder builder) throws Exception { + GeneralNames gns = new GeneralNames(); + gns.add(new GeneralName(new IPAddressName("127.0.0.1"))); + gns.add(new GeneralName(new DNSName("localhost"))); + return builder.addExtension(new SubjectAlternativeNameExtension(true, gns)); + } + + @Override + protected CertificateBuilder customizeClientCert(CertificateBuilder builder) throws Exception { + GeneralNames gns = new GeneralNames(); + gns.add(new GeneralName(new IPAddressName("127.0.0.1"))); + gns.add(new GeneralName(new DNSName("localhost"))); + return builder.addExtension(new SubjectAlternativeNameExtension(true, gns)); + } + /* * Define the server side of the test. * @@ -647,8 +117,7 @@ public class Identities { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLContext context = getSSLContext(trusedCertStr, serverCertStr, - serverModulus, serverPrivateExponent, passphrase); + SSLContext context = getServerSSLContext(); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); // doClientSide() connects to "localhost" @@ -703,8 +172,7 @@ public class Identities { void doClientSide() throws Exception { SSLContext reservedSSLContext = SSLContext.getDefault(); try { - SSLContext context = getSSLContext(trusedCertStr, clientCertStr, - clientModulus, clientPrivateExponent, passphrase); + SSLContext context = getClientSSLContext(); SSLContext.setDefault(context); @@ -749,19 +217,18 @@ public class Identities { volatile Exception clientException = null; public static void main(String args[]) throws Exception { - // MD5 is used in this test case, don't disable MD5 algorithm. - Security.setProperty("jdk.certpath.disabledAlgorithms", - "MD2, RSA keySize < 1024"); - Security.setProperty("jdk.tls.disabledAlgorithms", - "SSLv3, RC4, DH keySize < 768"); - + if (args[1].contains("MD5")) { + SecurityUtils.removeFromDisabledAlgs( + "jdk.certpath.disabledAlgorithms", List.of("MD5")); + SecurityUtils.removeFromDisabledTlsAlgs("MD5"); + } if (debug) System.setProperty("javax.net.debug", "all"); /* * Start the tests. */ - new Identities(); + new Identities(args[0], args[1]); } Thread clientThread = null; @@ -771,7 +238,9 @@ public class Identities { * * Fork off the other side, then do your work. */ - Identities() throws Exception { + Identities(String protocol, String signatureAlg) throws Exception { + super(protocol, signatureAlg); + if (separateServerThread) { startServer(true); startClient(false); @@ -846,65 +315,4 @@ public class Identities { doClientSide(); } } - - // get the ssl context - private static SSLContext getSSLContext(String trusedCertStr, - String keyCertStr, byte[] modulus, - byte[] privateExponent, char[] passphrase) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - ByteArrayInputStream is = - new ByteArrayInputStream(trusedCertStr.getBytes()); - Certificate trusedCert = cf.generateCertificate(is); - is.close(); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - ks.setCertificateEntry("RSA Export Signer", trusedCert); - - if (keyCertStr != null) { - // generate the private key. - RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec( - new BigInteger(modulus), - new BigInteger(privateExponent)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - - // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLSv1.2"); - - if (keyCertStr != null) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; - } - } diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IdentitiesBase.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IdentitiesBase.java new file mode 100644 index 00000000000..88d3d92a8a1 --- /dev/null +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IdentitiesBase.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import jdk.test.lib.security.CertificateBuilder; +import sun.security.x509.AuthorityKeyIdentifierExtension; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.KeyIdentifier; +import sun.security.x509.SerialNumber; +import sun.security.x509.X500Name; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +public abstract class IdentitiesBase { + static X509Certificate trustedCert; + static X509Certificate serverCert; + static X509Certificate clientCert; + static KeyPair serverKeys; + static KeyPair clientKeys; + static char[] passphrase = "passphrase".toCharArray(); + + protected final String protocol; + protected final String signatureAlg; + + /* + * Turn on SSL debugging? + */ + static boolean debug = Boolean.getBoolean("test.debug"); + + public IdentitiesBase(String protocol, String signatureAlg) throws Exception { + this.protocol = protocol; + this.signatureAlg = signatureAlg; + + setupCertificates(); + } + + protected String getTrustedDname() { + return "O=Some-Org, L=Some-City, ST=Some-State, C=US"; + } + + protected String getServerDname() { + return "CN=localhost, OU=SSL-Server, O=Some-Org, L=Some-City, ST=Some-State, C=US"; + } + + protected String getClientDname() { + return "CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US"; + } + + protected CertificateBuilder customizeServerCert(CertificateBuilder builder) throws Exception { + return builder; + } + + protected CertificateBuilder customizeClientCert(CertificateBuilder builder) throws Exception { + return builder; + } + + private void setupCertificates() throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + KeyPair caKeys = kpg.generateKeyPair(); + serverKeys = kpg.generateKeyPair(); + clientKeys = kpg.generateKeyPair(); + + trustedCert = createTrustedCert(getTrustedDname(), caKeys, signatureAlg); + if (debug) { + System.out.println("----------- Trusted Cert -----------"); + CertificateBuilder.printCertificate(trustedCert, System.out); + } + + CertificateBuilder builder = CertificateBuilder.newCertificateBuilder( + getServerDname(), + serverKeys.getPublic(), caKeys.getPublic(), + CertificateBuilder.KeyUsage.DIGITAL_SIGNATURE, + CertificateBuilder.KeyUsage.NONREPUDIATION, + CertificateBuilder.KeyUsage.KEY_ENCIPHERMENT) + .addBasicConstraintsExt(false, false, -1) + .addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1", "::1")) + .setOneHourValidity(); + serverCert = customizeServerCert(builder) + .build(trustedCert, caKeys.getPrivate(), signatureAlg); + if (debug) { + System.out.println("----------- Server Cert -----------"); + CertificateBuilder.printCertificate(serverCert, System.out); + } + + builder = CertificateBuilder.newCertificateBuilder( + getClientDname(), + clientKeys.getPublic(), caKeys.getPublic(), + CertificateBuilder.KeyUsage.DIGITAL_SIGNATURE, + CertificateBuilder.KeyUsage.NONREPUDIATION, + CertificateBuilder.KeyUsage.KEY_ENCIPHERMENT) + .addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1", "::1")) + .addBasicConstraintsExt(false, false, -1) + .setOneHourValidity(); + builder = customizeClientCert(builder); + clientCert = builder.build(trustedCert, caKeys.getPrivate(), signatureAlg); + if (debug) { + System.out.println("----------- Client Cert -----------"); + CertificateBuilder.printCertificate(clientCert, System.out); + } + } + + protected static X509Certificate createTrustedCert(String dname, KeyPair caKeys, + String signatureAlgo) throws Exception { + SecureRandom random = new SecureRandom(); + + KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic()); + GeneralNames gns = new GeneralNames(); + GeneralName name = new GeneralName(new X500Name(dname)); + gns.add(name); + BigInteger serialNumber = BigInteger.valueOf(random.nextLong(1000000) + 1); + return CertificateBuilder.newCertificateBuilder(dname, + caKeys.getPublic(), caKeys.getPublic()) + .setSerialNumber(serialNumber) + .addExtension(new AuthorityKeyIdentifierExtension(kid, gns, + new SerialNumber(serialNumber))) + .addBasicConstraintsExt(true, true, -1) + .setOneHourValidity() + .build(null, caKeys.getPrivate(), signatureAlgo); + } + + protected SSLContext getClientSSLContext() throws Exception { + return getSSLContext(trustedCert, clientCert, clientKeys, passphrase); + } + + protected SSLContext getServerSSLContext() throws Exception { + return getSSLContext(trustedCert, serverCert, serverKeys, passphrase); + } + + // get the ssl context + private SSLContext getSSLContext(X509Certificate trustedCert, + X509Certificate keyCert, KeyPair key, char[] passphrase) + throws Exception { + + // create a key store + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + + // import the trused cert + ks.setCertificateEntry("RSA Export Signer", trustedCert); + + Certificate[] chain = new Certificate[2]; + chain[0] = keyCert; + chain[1] = trustedCert; + + // import the key entry. + ks.setKeyEntry("Whatever", key.getPrivate(), passphrase, chain); + + // create SSL context + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ks); + + SSLContext ctx = SSLContext.getInstance(protocol); + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + return ctx; + } +} diff --git a/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java b/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java index eacc0337cb6..23f5fc3d6a1 100644 --- a/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java +++ b/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ */ import jdk.test.lib.process.ProcessTools; +import jtreg.SkippedException; import org.testng.annotations.Test; import java.security.Provider; @@ -47,8 +48,7 @@ public class ReadConfInUTF16Env { public static void main(String[] args) throws Exception { Provider p = Security.getProvider("SunPKCS11"); if (p == null) { - System.out.println("Skipping test - no PKCS11 provider available"); - return; + throw new SkippedException("No PKCS11 provider available"); } System.out.println(p.getName()); } diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index 0e8d2d61d53..3b09f845f8e 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -828,7 +828,7 @@ public abstract class PKCS11Test { private void premain(Provider p) throws Exception { if (skipTest(p)) { - return; + throw new SkippedException("See logs for details"); } long start = System.currentTimeMillis(); diff --git a/test/jdk/sun/security/pkcs11/Provider/Absolute.java b/test/jdk/sun/security/pkcs11/Provider/Absolute.java index c298c076b30..07a934030db 100644 --- a/test/jdk/sun/security/pkcs11/Provider/Absolute.java +++ b/test/jdk/sun/security/pkcs11/Provider/Absolute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ * @summary load DLLs and launch executables using fully qualified path */ +import jtreg.SkippedException; + import java.security.InvalidParameterException; import java.security.Provider; @@ -40,12 +42,11 @@ public class Absolute { try { Provider p = PKCS11Test.getSunPKCS11(config); if (p == null) { - System.out.println("Skipping test - no PKCS11 provider available"); + throw new SkippedException("Skipping test - no PKCS11 provider available"); } } catch (InvalidParameterException ipe) { Throwable ex = ipe.getCause(); - if (ex.getMessage().indexOf( - "Absolute path required for library value:") != -1) { + if (ex.getMessage().contains("Absolute path required for library value:")) { System.out.println("Test Passed: expected exception thrown"); } else { // rethrow diff --git a/test/jdk/sun/security/pkcs11/Provider/ConfigShortPath.java b/test/jdk/sun/security/pkcs11/Provider/ConfigShortPath.java index f229360f1af..120f289d211 100644 --- a/test/jdk/sun/security/pkcs11/Provider/ConfigShortPath.java +++ b/test/jdk/sun/security/pkcs11/Provider/ConfigShortPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,17 @@ * @bug 6581254 6986789 7196009 8062170 * @summary Allow '~', '+', and quoted paths in config file * @author Valerie Peng + * @library /test/lib */ -import java.security.*; -import java.io.*; -import java.lang.reflect.*; +import jtreg.SkippedException; + +import java.io.File; +import java.io.IOException; +import java.security.InvalidParameterException; +import java.security.Provider; +import java.security.ProviderException; +import java.security.Security; public class ConfigShortPath { @@ -43,8 +49,7 @@ public class ConfigShortPath { public static void main(String[] args) throws Exception { Provider p = Security.getProvider("SunPKCS11"); if (p == null) { - System.out.println("Skipping test - no PKCS11 provider available"); - return; + throw new SkippedException("Skipping test - no PKCS11 provider available"); } String osInfo = System.getProperty("os.name", ""); @@ -65,7 +70,7 @@ public class ConfigShortPath { if (cause.getClass().getName().equals ("sun.security.pkcs11.ConfigurationException")) { // Error occurred during parsing - if (cause.getMessage().indexOf("Unexpected") != -1) { + if (cause.getMessage().contains("Unexpected")) { throw (ProviderException) cause; } } diff --git a/test/jdk/sun/security/pkcs11/Provider/LoginISE.java b/test/jdk/sun/security/pkcs11/Provider/LoginISE.java index 5027770c5e6..d131a857216 100644 --- a/test/jdk/sun/security/pkcs11/Provider/LoginISE.java +++ b/test/jdk/sun/security/pkcs11/Provider/LoginISE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,16 +21,22 @@ * questions. */ -import java.io.*; -import java.util.*; -import java.security.*; -import javax.security.auth.callback.*; +import jtreg.SkippedException; + +import java.io.IOException; +import java.security.AuthProvider; +import java.security.Provider; +import java.security.Security; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; /** * @test * @bug 8130648 * @summary make sure IllegalStateException is thrown for uninitialized * SunPKCS11 provider instance + * @library /test/lib */ public class LoginISE { @@ -38,8 +44,7 @@ public class LoginISE { Provider p = Security.getProvider("SunPKCS11"); if (p == null) { - System.out.println("No un-initialized PKCS11 provider available; skip"); - return; + throw new SkippedException("No un-initialized PKCS11 provider available; skip"); } if (!(p instanceof AuthProvider)) { throw new RuntimeException("Error: expect AuthProvider!"); diff --git a/test/jdk/sun/security/pkcs11/Secmod/AddPrivateKey.java b/test/jdk/sun/security/pkcs11/Secmod/AddPrivateKey.java index 29950d762e0..34a813ab858 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/AddPrivateKey.java +++ b/test/jdk/sun/security/pkcs11/Secmod/AddPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,9 +62,7 @@ public class AddPrivateKey extends SecmodTest { private static final byte[] DATA = generateData(DATA_LENGTH); public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); String configName = BASE + SEP + "nss.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java b/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java index 7b4a5075da8..aaa38fe1c71 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java +++ b/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java @@ -31,7 +31,6 @@ * @run main/othervm AddTrustedCert */ -import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.security.KeyStore; @@ -47,9 +46,7 @@ import java.util.TreeSet; public class AddTrustedCert extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); X509Certificate cert; try (InputStream in = new FileInputStream(BASE + SEP + "anchor.cer")) { diff --git a/test/jdk/sun/security/pkcs11/Secmod/Crypto.java b/test/jdk/sun/security/pkcs11/Secmod/Crypto.java index 1b4c0883e80..e9e9bd73321 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/Crypto.java +++ b/test/jdk/sun/security/pkcs11/Secmod/Crypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ * @run main/othervm Crypto */ -import java.io.File; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Provider; @@ -40,9 +39,7 @@ import java.security.Signature; public class Crypto extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); String configName = BASE + SEP + "nsscrypto.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/GetPrivateKey.java b/test/jdk/sun/security/pkcs11/Secmod/GetPrivateKey.java index e89cafb920c..8d613ee63d2 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/GetPrivateKey.java +++ b/test/jdk/sun/security/pkcs11/Secmod/GetPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ * @run main/othervm GetPrivateKey */ -import java.io.File; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Provider; @@ -46,9 +45,7 @@ import java.util.TreeSet; public class GetPrivateKey extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); String configName = BASE + SEP + "nss.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/JksSetPrivateKey.java b/test/jdk/sun/security/pkcs11/Secmod/JksSetPrivateKey.java index d6c084c882d..8549a338a58 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/JksSetPrivateKey.java +++ b/test/jdk/sun/security/pkcs11/Secmod/JksSetPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ * @run main/othervm JksSetPrivateKey */ -import java.io.File; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.PrivateKey; @@ -45,9 +44,7 @@ import java.util.TreeSet; public class JksSetPrivateKey extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); String configName = BASE + SEP + "nss.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/LoadKeystore.java b/test/jdk/sun/security/pkcs11/Secmod/LoadKeystore.java index 55c473ce90e..d657d805ca0 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/LoadKeystore.java +++ b/test/jdk/sun/security/pkcs11/Secmod/LoadKeystore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * @run main/othervm LoadKeystore */ -import java.io.File; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -42,9 +41,7 @@ import java.util.Collections; public class LoadKeystore extends SecmodTest { public static void main(String[] args) throws Exception { - if (!initSecmod()) { - return; - } + initSecmod(); String configName = BASE + SEP + "nss.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/TestNssDbSqlite.java b/test/jdk/sun/security/pkcs11/Secmod/TestNssDbSqlite.java index 7b22a4abfc6..57309749e93 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/TestNssDbSqlite.java +++ b/test/jdk/sun/security/pkcs11/Secmod/TestNssDbSqlite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2017, 2025, Red Hat, Inc. and/or its affiliates. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -46,6 +46,7 @@ import java.security.KeyStore; import java.security.Provider; import java.security.Signature; +import jtreg.SkippedException; import sun.security.rsa.SunRsaSign; import sun.security.jca.ProviderList; import sun.security.jca.Providers; @@ -66,9 +67,7 @@ public final class TestNssDbSqlite extends SecmodTest { public static void main(String[] args) throws Exception { - if (!initialize()) { - return; - } + initializeProvider(); if (enableDebug) { System.out.println("SunPKCS11 provider: " + @@ -110,16 +109,9 @@ public final class TestNssDbSqlite extends SecmodTest { } } - private static boolean initialize() throws Exception { - return initializeProvider(); - } - - private static boolean initializeProvider() throws Exception { + private static void initializeProvider() throws Exception { useSqlite(true); - if (!initSecmod()) { - System.out.println("Cannot init security module database, skipping"); - return false; - } + initSecmod(); sunPKCS11NSSProvider = getSunPKCS11(BASE + SEP + "nss-sqlite.cfg"); sunJCEProvider = new com.sun.crypto.provider.SunJCE(); @@ -135,7 +127,5 @@ public final class TestNssDbSqlite extends SecmodTest { gen.generate(2048); privateKey = gen.getPrivateKey(); certificate = gen.getSelfCertificate(new X500Name("CN=Me"), 365); - - return true; } } diff --git a/test/jdk/sun/security/pkcs11/Secmod/TrustAnchors.java b/test/jdk/sun/security/pkcs11/Secmod/TrustAnchors.java index efe34478a9e..14977fde340 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/TrustAnchors.java +++ b/test/jdk/sun/security/pkcs11/Secmod/TrustAnchors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ * @run main/othervm TrustAnchors */ -import java.io.File; import java.security.KeyStore; import java.security.Provider; import java.security.Security; @@ -43,9 +42,7 @@ import java.util.TreeSet; public class TrustAnchors extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); // our secmod.db file says nssckbi.*so*, so NSS does not find the // *DLL* on Windows nor the *DYLIB* on Mac OSX. diff --git a/test/jdk/sun/security/pkcs11/SecmodTest.java b/test/jdk/sun/security/pkcs11/SecmodTest.java index 8201548bf9d..1979066e26a 100644 --- a/test/jdk/sun/security/pkcs11/SecmodTest.java +++ b/test/jdk/sun/security/pkcs11/SecmodTest.java @@ -42,7 +42,7 @@ public class SecmodTest extends PKCS11Test { useSqlite = b; } - static boolean initSecmod() throws Exception { + static void initSecmod() throws Exception { useNSS(); LIBPATH = getNSSLibDir(); // load all the libraries except libnss3 into memory @@ -60,7 +60,7 @@ public class SecmodTest extends PKCS11Test { System.setProperty("pkcs11test.nss.db", DBDIR); } File dbdirFile = new File(DBDIR); - if (dbdirFile.exists() == false) { + if (!dbdirFile.exists()) { dbdirFile.mkdir(); } @@ -73,7 +73,6 @@ public class SecmodTest extends PKCS11Test { copyFile("key3.db", BASE, DBDIR); copyFile("cert8.db", BASE, DBDIR); } - return true; } private static void copyFile(String name, String srcDir, String dstDir) throws IOException { diff --git a/test/jdk/sun/security/pkcs11/ec/ReadCertificates.java b/test/jdk/sun/security/pkcs11/ec/ReadCertificates.java index e2bfa3dc048..4ff17356eb6 100644 --- a/test/jdk/sun/security/pkcs11/ec/ReadCertificates.java +++ b/test/jdk/sun/security/pkcs11/ec/ReadCertificates.java @@ -55,6 +55,7 @@ import java.util.List; import java.util.Map; import javax.security.auth.x500.X500Principal; import jdk.test.lib.security.Providers; +import jtreg.SkippedException; public class ReadCertificates extends PKCS11Test { @@ -78,8 +79,7 @@ public class ReadCertificates extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("Signature", "SHA1withECDSA") == null) { - System.out.println("Provider does not support ECDSA, skipping..."); - return; + throw new SkippedException("Provider does not support ECDSA"); } /* diff --git a/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java b/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java index 15a5b14ec40..eea360b64fe 100644 --- a/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java +++ b/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java @@ -54,6 +54,7 @@ import java.util.List; import java.util.Map; import java.util.Random; import jdk.test.lib.security.Providers; +import jtreg.SkippedException; public class ReadPKCS12 extends PKCS11Test { @@ -66,8 +67,7 @@ public class ReadPKCS12 extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("Signature", "SHA1withECDSA") == null) { - System.out.println("Provider does not support ECDSA, skipping..."); - return; + throw new SkippedException("Provider does not support ECDSA"); } /* diff --git a/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java b/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java index d23c302f38f..94453dd649d 100644 --- a/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java +++ b/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,8 @@ * @run main/othervm TestKeyFactory */ +import jtreg.SkippedException; + import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; @@ -126,8 +128,7 @@ public class TestKeyFactory extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("KeyFactory", "EC") == null) { - System.out.println("Provider does not support EC, skipping"); - return; + throw new SkippedException("Provider does not support EC, skipping"); } int[] keyLengths = {256, 521}; KeyFactory kf = KeyFactory.getInstance("EC", p); diff --git a/test/jdk/sun/security/pkcs11/rsa/KeyWrap.java b/test/jdk/sun/security/pkcs11/rsa/KeyWrap.java index 4fd4082f523..8d71b5e26ca 100644 --- a/test/jdk/sun/security/pkcs11/rsa/KeyWrap.java +++ b/test/jdk/sun/security/pkcs11/rsa/KeyWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ * @run main/othervm KeyWrap */ +import jtreg.SkippedException; + import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.Key; @@ -54,8 +56,7 @@ public class KeyWrap extends PKCS11Test { try { Cipher.getInstance("RSA/ECB/PKCS1Padding", p); } catch (GeneralSecurityException e) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } KeyPair kp; try { @@ -74,8 +75,7 @@ public class KeyWrap extends PKCS11Test { kp = new KeyPair(pub, priv); } catch (NoSuchAlgorithmException | InvalidKeyException ee) { ee.printStackTrace(); - System.out.println("Provider does not support RSA, skipping"); - return; + throw new SkippedException("Provider does not support RSA, skipping"); } } System.out.println(kp); diff --git a/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java b/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java index c125464659b..2630d9e310b 100644 --- a/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java +++ b/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java @@ -40,6 +40,7 @@ import java.security.Provider; import java.security.Security; import jdk.test.lib.security.Providers; +import jtreg.SkippedException; public class ClientJSSEServerJSSE extends PKCS11Test { @@ -58,8 +59,7 @@ public class ClientJSSEServerJSSE extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("KeyFactory", "EC") == null) { - System.out.println("Provider does not support EC, skipping"); - return; + throw new SkippedException("Provider does not support EC, skipping"); } Providers.setAt(p, 1); CipherTest.main(new JSSEFactory(), cmdArgs); diff --git a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java index 977ae5338bd..682c09bab41 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java +++ b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ import java.io.BufferedReader; import java.nio.file.Files; import java.nio.file.Paths; -import java.security.InvalidAlgorithmParameterException; import java.security.Provider; import java.security.ProviderException; import java.util.Arrays; @@ -45,6 +44,7 @@ import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import jtreg.SkippedException; import sun.security.internal.spec.TlsKeyMaterialParameterSpec; import sun.security.internal.spec.TlsKeyMaterialSpec; @@ -60,8 +60,7 @@ public class TestKeyMaterial extends PKCS11Test { @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyGenerator", "SunTlsKeyMaterial") == null) { - System.out.println("Provider does not support algorithm, skipping"); - return; + throw new SkippedException("Provider does not support algorithm, skipping"); } try (BufferedReader reader = Files.newBufferedReader( diff --git a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterialChaCha20.java b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterialChaCha20.java index 51471fca65a..b784a3127c6 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterialChaCha20.java +++ b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterialChaCha20.java @@ -35,6 +35,8 @@ import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import java.security.Provider; import java.security.NoSuchAlgorithmException; + +import jtreg.SkippedException; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; import sun.security.internal.spec.TlsMasterSecretParameterSpec; import sun.security.internal.spec.TlsKeyMaterialParameterSpec; @@ -52,20 +54,17 @@ public class TestKeyMaterialChaCha20 extends PKCS11Test { try { kg1 = KeyGenerator.getInstance("SunTlsRsaPremasterSecret", provider); } catch (Exception e) { - System.out.println("Skipping, SunTlsRsaPremasterSecret KeyGenerator not supported"); - return; + throw new SkippedException("Skipping, SunTlsRsaPremasterSecret KeyGenerator not supported"); } try { kg2 = KeyGenerator.getInstance("SunTls12MasterSecret", provider); } catch (Exception e) { - System.out.println("Skipping, SunTls12MasterSecret KeyGenerator not supported"); - return; + throw new SkippedException("Skipping, SunTls12MasterSecret KeyGenerator not supported"); } try { kg3 = KeyGenerator.getInstance("SunTls12KeyMaterial", provider); } catch (Exception e) { - System.out.println("Skipping, SunTls12KeyMaterial KeyGenerator not supported"); - return; + throw new SkippedException("Skipping, SunTls12KeyMaterial KeyGenerator not supported"); } kg1.init(new TlsRsaPremasterSecretParameterSpec(0x0303, 0x0303)); diff --git a/test/jdk/sun/security/pkcs11/tls/TestMasterSecret.java b/test/jdk/sun/security/pkcs11/tls/TestMasterSecret.java index 52e2327cfc9..f969aece532 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestMasterSecret.java +++ b/test/jdk/sun/security/pkcs11/tls/TestMasterSecret.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,8 @@ import java.util.Arrays; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; + +import jtreg.SkippedException; import sun.security.internal.interfaces.TlsMasterSecret; import sun.security.internal.spec.TlsMasterSecretParameterSpec; @@ -56,8 +58,7 @@ public class TestMasterSecret extends PKCS11Test { @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyGenerator", "SunTlsMasterSecret") == null) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } try (BufferedReader reader = Files.newBufferedReader( diff --git a/test/jdk/sun/security/pkcs11/tls/TestPRF.java b/test/jdk/sun/security/pkcs11/tls/TestPRF.java index ada1716c98b..662383095a9 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestPRF.java +++ b/test/jdk/sun/security/pkcs11/tls/TestPRF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,8 @@ import java.util.Arrays; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; + +import jtreg.SkippedException; import sun.security.internal.spec.TlsPrfParameterSpec; public class TestPRF extends PKCS11Test { @@ -53,8 +55,7 @@ public class TestPRF extends PKCS11Test { @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyGenerator", "SunTlsPrf") == null) { - System.out.println("Provider does not support algorithm, skipping"); - return; + throw new SkippedException("Provider does not support algorithm, skipping"); } try (BufferedReader reader = Files.newBufferedReader( diff --git a/test/jdk/sun/security/pkcs11/tls/TestPremaster.java b/test/jdk/sun/security/pkcs11/tls/TestPremaster.java index 9ee1dddb8e5..d34330fa073 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestPremaster.java +++ b/test/jdk/sun/security/pkcs11/tls/TestPremaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,8 @@ import java.security.Provider; import java.security.InvalidAlgorithmParameterException; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; + +import jtreg.SkippedException; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; public class TestPremaster extends PKCS11Test { @@ -48,8 +50,7 @@ public class TestPremaster extends PKCS11Test { public void main(Provider provider) throws Exception { if (provider.getService( "KeyGenerator", "SunTlsRsaPremasterSecret") == null) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } KeyGenerator kg; kg = KeyGenerator.getInstance("SunTlsRsaPremasterSecret", provider); @@ -87,8 +88,7 @@ public class TestPremaster extends PKCS11Test { } catch (InvalidAlgorithmParameterException iape) { // S12 removed support for SSL v3.0 if (clientVersion == 0x300 || serverVersion == 0x300) { - System.out.println("Skip testing SSLv3 due to no support"); - return; + throw new SkippedException("Skip testing SSLv3 due to no support"); } // unexpected, pass it up throw iape; diff --git a/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java index c227e99d12b..8799f2305bf 100644 --- a/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java +++ b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java @@ -71,6 +71,7 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManagerFactory; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; import sun.security.internal.spec.TlsMasterSecretParameterSpec; import sun.security.internal.spec.TlsPrfParameterSpec; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; @@ -94,12 +95,11 @@ public final class FipsModeTLS extends SecmodTest { try { initialize(); } catch (Exception e) { - System.out.println("Test skipped: failure during" + - " initialization"); if (enableDebug) { System.out.println(e); } - return; + throw new SkippedException("Test skipped: failure during" + + " initialization"); } if (shouldRun()) { @@ -112,8 +112,8 @@ public final class FipsModeTLS extends SecmodTest { System.out.println("Test PASS - OK"); } else { - System.out.println("Test skipped: TLS 1.2 mechanisms" + - " not supported by current SunPKCS11 back-end"); + throw new SkippedException("Test skipped: TLS 1.2 mechanisms" + + " not supported by current SunPKCS11 back-end"); } } @@ -456,9 +456,8 @@ public final class FipsModeTLS extends SecmodTest { // 2. SUN (to handle X.509 certificates) // 3. SunJSSE (for a TLS engine) - if (initSecmod() == false) { - return; - } + initSecmod(); + String configName = BASE + SEP + "nss.cfg"; sunPKCS11NSSProvider = getSunPKCS11(configName); System.out.println("SunPKCS11 provider: " + sunPKCS11NSSProvider); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java index 0be6cf685f6..09a46ecb7d1 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java @@ -149,7 +149,11 @@ public final class LauncherAsServiceVerifier { applyToAdditionalLauncher(target); } target.test().ifPresent(pkg -> { - pkg.addInstallVerifier(this::verifyLauncherExecuted); + pkg.addInstallVerifier(cmd -> { + if (!MacHelper.isForAppStore(cmd)) { + verifyLauncherExecuted(cmd); + } + }); }); } @@ -239,7 +243,9 @@ public final class LauncherAsServiceVerifier { } static boolean launcherAsService(JPackageCommand cmd, String launcherName) { - if (cmd.isMainLauncher(launcherName)) { + if (MacHelper.isForAppStore(cmd)) { + return false; + } else if (cmd.isMainLauncher(launcherName)) { return PropertyFinder.findLauncherProperty(cmd, null, PropertyFinder.cmdlineBooleanOption("--launcher-as-service"), PropertyFinder.nop(), diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index a6d24af2b25..caeb0a206fc 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -797,6 +797,15 @@ public final class MacHelper { ).orElseGet(cmd::name); } + public static boolean isForAppStore(JPackageCommand cmd) { + return PropertyFinder.findAppProperty(cmd, + PropertyFinder.cmdlineBooleanOption("--mac-app-store"), + PropertyFinder.appImageFile(appImageFile -> { + return Boolean.toString(appImageFile.macAppStore()); + }) + ).map(Boolean::parseBoolean).orElse(false); + } + public static boolean isXcodeDevToolsInstalled() { return Inner.XCODE_DEV_TOOLS_INSTALLED; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PropertyFinder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PropertyFinder.java index 6c612fa9ba5..3d7ac490350 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PropertyFinder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PropertyFinder.java @@ -106,7 +106,11 @@ final class PropertyFinder { static Finder cmdlineBooleanOption(String optionName) { return target -> { - return Optional.of(target.hasArgument(optionName)).map(Boolean::valueOf).map(Object::toString); + if (target.hasArgument(optionName)) { + return Optional.of(Boolean.TRUE.toString()); + } else { + return Optional.empty(); + } }; } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java index 41142382c39..246b3722cbf 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java @@ -36,6 +36,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.function.BiFunction; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.JUnitAdapter; @@ -58,7 +60,9 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { // Print the tool version build().args("--version").expectVersion(), // Print the tool version - build().args("foo", "bar").expectErrors(I18N.format("error.non-option-arguments", 2)), + // Additional error messages may be printed if the default bundling operation + // can not be identified; don't verify these errors in the output. + build().args("foo", "bar").stderrMatchType(OutputMatchType.STARTS_WITH).expectErrors(I18N.format("error.non-option-arguments", 2)), // Valid command line requesting to print the full help. build().args("-h").expectFullHelp(), // Valid command line requesting to build a package and print the full help. @@ -68,12 +72,14 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { // Valid command line requesting to print the full help and the version of the tool. build().args("--help", "--version").expectVersionWithHelp(), // Invalid command line requesting to print the version of the tool. - build().args("foo", "--version").expectErrors(I18N.format("error.non-option-arguments", 1)) + // Additional error messages may be printed if the default bundling operation + // can not be identified; don't verify these errors in the output. + build().args("foo", "--version").stderrMatchType(OutputMatchType.STARTS_WITH).expectErrors(I18N.format("error.non-option-arguments", 1)) ).map(TestSpec.Builder::create).toList(); } - record TestSpec(List args, int expectedExitCode, List expectedStdout, List expectedStderr) { + record TestSpec(List args, int expectedExitCode, ExpectedOutput expectedStdout, ExpectedOutput expectedStderr) { TestSpec { Objects.requireNonNull(args); @@ -84,15 +90,19 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { void run() { var result = ExecutionResult.create(args.toArray(String[]::new)); assertEquals(expectedExitCode, result.exitCode()); - assertEquals(expectedStdout, result.stdout()); - assertEquals(expectedStderr, result.stderr()); + expectedStdout.test(result.stdout()); + expectedStderr.test(result.stderr()); } static final class Builder { TestSpec create() { - return new TestSpec(args, expectedExitCode, expectedStdout, expectedStderr); + return new TestSpec( + args, + expectedExitCode, + new ExpectedOutput(expectedStdout, Optional.ofNullable(stdoutMatchType).orElse(OutputMatchType.EQUALS)), + new ExpectedOutput(expectedStderr, Optional.ofNullable(stderrMatchType).orElse(OutputMatchType.EQUALS))); } Builder args(String... v) { @@ -104,6 +114,16 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { return this; } + Builder stdoutMatchType(OutputMatchType v) { + stdoutMatchType = v; + return this; + } + + Builder stderrMatchType(OutputMatchType v) { + stderrMatchType = v; + return this; + } + Builder expectStdout(String... lines) { return expectStdout(List.of(lines)); } @@ -164,6 +184,8 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { private List args = new ArrayList<>(); private int expectedExitCode; + private OutputMatchType stdoutMatchType; + private OutputMatchType stderrMatchType; private List expectedStdout = new ArrayList<>(); private List expectedStderr = new ArrayList<>(); } @@ -188,6 +210,37 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { } + private enum OutputMatchType { + EQUALS((_, actual) -> actual), + STARTS_WITH((expected, actual) -> { + if (expected.size() < actual.size()) { + return actual.subList(0, expected.size()); + } + return actual; + }), + ; + + OutputMatchType(BiFunction, List, List> mapper) { + this.mapper = Objects.requireNonNull(mapper); + } + + private final BiFunction, List, List> mapper; + } + + + private record ExpectedOutput(List content, OutputMatchType type) { + ExpectedOutput { + Objects.requireNonNull(content); + Objects.requireNonNull(type); + } + + void test(List lines) { + var filteredLines = type.mapper.apply(content, lines); + assertEquals(content, filteredLines); + } + } + + private static TestSpec.Builder build() { return new TestSpec.Builder(); } diff --git a/test/jdk/tools/jpackage/macosx/PkgScriptsTest.java b/test/jdk/tools/jpackage/macosx/PkgScriptsTest.java index f52191f4a05..9ee85ae5245 100644 --- a/test/jdk/tools/jpackage/macosx/PkgScriptsTest.java +++ b/test/jdk/tools/jpackage/macosx/PkgScriptsTest.java @@ -22,6 +22,7 @@ */ import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -32,6 +33,7 @@ import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; +import jdk.jpackage.test.MacHelper; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; @@ -50,24 +52,23 @@ import jdk.jpackage.test.TKit; */ public class PkgScriptsTest { - public static Collection input() { - return List.of(new Object[][]{ - { new PkgInstallScript[]{ - PkgInstallScript.PREINSTALL, - PkgInstallScript.POSTINSTALL }, - }, - { new PkgInstallScript[]{ - PkgInstallScript.PREINSTALL }, - }, - { new PkgInstallScript[]{ - PkgInstallScript.POSTINSTALL }, - }, - }); + public static Collection input() { + List data = new ArrayList<>(); + for (var appStore : List.of(true, false)) { + for (var scriptRoles : List.of( + List.of(PkgInstallScript.PREINSTALL, PkgInstallScript.POSTINSTALL), + List.of(PkgInstallScript.PREINSTALL), + List.of(PkgInstallScript.POSTINSTALL) + )) { + data.add(new Object[] {scriptRoles.toArray(PkgInstallScript[]::new), appStore}); + } + } + return data; } @Test @ParameterSupplier("input") - public void test(PkgInstallScript[] customScriptRoles) { + public void test(PkgInstallScript[] customScriptRoles, boolean appStore) { var responseDir = TKit.createTempDirectory("response"); var customScripts = Stream.of(customScriptRoles).map(role -> { @@ -80,6 +81,9 @@ public class PkgScriptsTest { .forTypes(PackageType.MAC_PKG) .configureHelloApp() .addInitializer(cmd -> { + if (appStore) { + cmd.addArgument("--mac-app-store"); + } cmd.addArguments("--resource-dir", TKit.createTempDirectory("resources")); customScripts.forEach(customScript -> { customScript.createFor(cmd); @@ -156,10 +160,13 @@ public class PkgScriptsTest { } void verify(JPackageCommand cmd) { + var scriptsEnabled = !MacHelper.isForAppStore(cmd); if (cmd.isPackageUnpacked()) { - role.verifyExists(cmd, true); - } else { + role.verifyExists(cmd, scriptsEnabled); + } else if (scriptsEnabled) { TKit.assertFileExists(responseFilePath(cmd)); + } else { + TKit.assertPathExists(responseFilePath(cmd), false); } } diff --git a/test/jdk/tools/jpackage/share/ServiceTest.java b/test/jdk/tools/jpackage/share/ServiceTest.java index 226f8f16bdc..94d3421a2cd 100644 --- a/test/jdk/tools/jpackage/share/ServiceTest.java +++ b/test/jdk/tools/jpackage/share/ServiceTest.java @@ -33,6 +33,7 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.stream.Stream; import jdk.jpackage.test.AdditionalLauncher; +import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.ConfigurationTarget; @@ -155,14 +156,21 @@ public class ServiceTest { } @Test - @Parameter("true") - @Parameter("false") - public void testAddL(boolean mainLauncherAsService) { + @Parameter(value = {"true", "false"}) + @Parameter(value = {"false", "false"}) + @Parameter(value = {"true", "true"}, ifOS = OperatingSystem.MACOS) + @Parameter(value = {"false", "true"}, ifOS = OperatingSystem.MACOS) + public void testAddL(boolean mainLauncherAsService, boolean isMacAppStore) { final var uniqueOutputFile = uniqueOutputFile(); createPackageTest() .addHelloAppInitializer("com.buz.AddLaunchersServiceTest") + .addInitializer(cmd -> { + if (isMacAppStore) { + cmd.addArgument("--mac-app-store"); + } + }) .mutate(test -> { if (mainLauncherAsService) { LauncherAsServiceVerifier.build() @@ -199,9 +207,11 @@ public class ServiceTest { } @Test - @Parameter("true") - @Parameter("false") - public void testAddLFromAppImage(boolean mainLauncherAsService) { + @Parameter(value = {"true", "false"}) + @Parameter(value = {"false", "false"}) + @Parameter(value = {"true", "true"}, ifOS = OperatingSystem.MACOS) + @Parameter(value = {"false", "true"}, ifOS = OperatingSystem.MACOS) + public void testAddLFromAppImage(boolean mainLauncherAsService, boolean isMacAppStore) { var uniqueOutputFile = uniqueOutputFile(); @@ -213,6 +223,10 @@ public class ServiceTest { appImageCmd.addInitializer(JPackageCommand::ignoreFakeRuntime); } + if (isMacAppStore) { + appImageCmd.cmd().orElseThrow().addArgument("--mac-app-store"); + } + if (mainLauncherAsService) { LauncherAsServiceVerifier.build() .mutate(uniqueOutputFile).appendAppOutputFileNamePrefix("-") diff --git a/test/langtools/jdk/javadoc/doclet/testClassCrossReferences/TestClassCrossReferences.java b/test/langtools/jdk/javadoc/doclet/testClassCrossReferences/TestClassCrossReferences.java index 982e38dafaa..1e9461454f7 100644 --- a/test/langtools/jdk/javadoc/doclet/testClassCrossReferences/TestClassCrossReferences.java +++ b/test/langtools/jdk/javadoc/doclet/testClassCrossReferences/TestClassCrossReferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 4652655 4857717 8025633 8026567 8071982 8164407 8182765 8205593 8240169 + * 8369531 * @summary This test verifies that class cross references work properly. * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -58,18 +59,18 @@ public class TestClassCrossReferences extends JavadocTester { "Link to math package""", "Link to AttributeContext inn\ - erclass""", + javax/swing/text/AbstractDocument.AttributeContext.html" title="interface in jav\ + ax.swing.text" class="external-link">Link to AttributeContext innerclass""", "Link to external class BigDecimal""", + java/math/BigDecimal.html" title="class in java.math" class="external-link">Link to external class BigDecimal""", "Link to external member gcd""", + java/math/BigInteger.html#gcd-java.math.BigInteger-" class="external-link">Link to external member gcd""", "Link to external member URI""", + javax/tools/SimpleJavaFileObject.html#uri" class="external-link">Link to e\ + xternal member URI""", """
    Overrides:
    @@ -95,18 +96,18 @@ public class TestClassCrossReferences extends JavadocTester { "Link to math package""", "Link to AttributeContext inn\ - erclass""", + javax/swing/text/AbstractDocument.AttributeContext.html" title="interface in jav\ + ax.swing.text" class="external-link">Link to AttributeContext innerclass""", "Link to external class BigDecimal""", + java/math/BigDecimal.html" title="class in java.math" class="external-link">Link to external class BigDecimal""", "Link to external member gcd""", + java/math/BigInteger.html#gcd-java.math.BigInteger-" class="external-link">Link to external member gcd""", "Link to external member URI""", + javax/tools/SimpleJavaFileObject.html#uri" class="external-link">Link to e\ + xternal member URI""", """
    Overrides:
    diff --git a/test/langtools/jdk/javadoc/doclet/testDocRootInlineTag/TestDocRootInlineTag.java b/test/langtools/jdk/javadoc/doclet/testDocRootInlineTag/TestDocRootInlineTag.java index 04d1e0f14db..a1f97282c50 100644 --- a/test/langtools/jdk/javadoc/doclet/testDocRootInlineTag/TestDocRootInlineTag.java +++ b/test/langtools/jdk/javadoc/doclet/testDocRootInlineTag/TestDocRootInlineTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,11 +57,11 @@ public class TestDocRootInlineTag extends JavadocTester { checkOutput("TestDocRootTag.html", true, "File""", + /java/io/File.html" title="class in java.io" class="external-link">File""", """ index""", "Second File Link""", + /java/io/File.html" title="class in java.io" class="external-link">Second File Link""", "The value of @docRoot is \"./\""); checkOutput("index-all.html", true, diff --git a/test/langtools/jdk/javadoc/doclet/testExternalOverriddenMethod/TestExternalOverriddenMethod.java b/test/langtools/jdk/javadoc/doclet/testExternalOverriddenMethod/TestExternalOverriddenMethod.java index 889b2edd1b5..7fd5c054f89 100644 --- a/test/langtools/jdk/javadoc/doclet/testExternalOverriddenMethod/TestExternalOverriddenMethod.java +++ b/test/langtools/jdk/javadoc/doclet/testExternalOverriddenMethod/TestExternalOverriddenMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 4857717 8025633 8026567 8164407 8182765 8205593 + * @bug 4857717 8025633 8026567 8164407 8182765 8205593 8369531 * @summary Test to make sure that externally overridden and implemented methods * are documented properly. The method should still include "implements" or * "overrides" documentation even though the method is external. @@ -56,15 +56,17 @@ public class TestExternalOverriddenMethod extends JavadocTester { """
    Overrides:
    read in class FilterReader
    """, + /java/io/FilterReader.html#read--" class="external-link">read in \ + class Filter\ + Reader""", """
    Specified by:
    readInt in interface DataInput
    """ + /java/io/DataInput.html#readInt--" class="external-link">readInt \ + in interface DataI\ + nput""" ); } } diff --git a/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java b/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java index b6317a1e581..72554ef34fe 100644 --- a/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java +++ b/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8177280 8262992 8259499 8307377 8352249 + * @bug 8177280 8262992 8259499 8307377 8352249 8369531 * @summary see and link tag syntax should allow generic types * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -53,13 +53,13 @@ public class TestGenericTypeLink extends JavadocTester { checkOutput("pkg1/A.html", true, """
    List<\ - ;String> - List<? extends CharSequence> + ist.html" title="interface in java.util" class="external-link">List<String> + List<? extends CharSequence> someMethod(ArrayList<Integer>\ ;, int) otherMethod(Map<String, Stri\ @@ -72,20 +72,19 @@ public class TestGenericTypeLink extends JavadocTester {
    """); @@ -148,10 +145,10 @@ public class TestGenericTypeLink extends JavadocTester { /a>
    Here's a generic link: A<Object, \ - RuntimeExcepti\ - on>.Inner"""); + html" title="class in java.lang" class="external-link">Object, RuntimeException>.Inner"""); } /** diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOption.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOption.java index a645ef31dec..d13e6617247 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOption.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOption.java @@ -24,7 +24,7 @@ /* * @test * @bug 4720957 5020118 8026567 8038976 8184969 8164407 8182765 8205593 - * 8216497 + * 8216497 8369531 * @summary Test to make sure that -link and -linkoffline link to * right files, and URLs with and without trailing slash are accepted. * @library ../../lib @@ -73,8 +73,8 @@ public class TestLinkOption extends JavadocTester { checkOutput("pkg/C.html", true, "Link to String Class""", + java/lang/String.html" title="class in java.lang" class="external-link">Li\ + nk to String Class""", //Make sure the parameters are formatted properly when the -link option is used. """ (int p1, @@ -84,20 +84,20 @@ public class TestLinkOption extends JavadocTester { (int p1, int p2, Object p3)"""); + java/lang/Object.html" title="class in java.lang" class="external-link">Object p3)"""); checkOutput("pkg/B.html", true, """
    A method with html tag the method getSystemClassLoader() \ - as the parent class loader.
    """, + java/lang/ClassLoader.html#getSystemClassLoader--" class="external-link"><\ + b>getSystemClassLoader() as the parent class loader.
    """, """
    is equivalent to invoking createTempFile(prefix, s\ uffix, null).
    """, "Link-Plain to String Class""", + java/lang/String.html" title="class in java.lang" class="external-link">Link-Pla\ + in to String Class""", "getSystemClassLoader()", "createTempFile(prefix, suffix, null)", """ @@ -121,8 +121,8 @@ public class TestLinkOption extends JavadocTester {
    public abstract class StringBuilderChild extends Object
    """ + java/lang/Object.html" title="class in java.lang" class="external-link">Object""" ); // Generate the documentation using -linkoffline and a relative path as the first parameter. @@ -137,7 +137,7 @@ public class TestLinkOption extends JavadocTester { checkOutput("pkg2/C2.html", true, """ This is a link to Class C.""" + /pkg/C.html" title="class in pkg" class="external-link">Class C.""" ); String out3 = "out3"; @@ -168,12 +168,12 @@ public class TestLinkOption extends JavadocTester { extends java.lang.Object
    + link to mylib.lang.StringBuilderChild\ + . """ ); @@ -193,12 +193,11 @@ public class TestLinkOption extends JavadocTester { extends java.lang.Object + link to mylib.lang.StringBuilderChild. """ ); diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithAutomaticModule.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithAutomaticModule.java index fb31822d0e9..3f1682946b3 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithAutomaticModule.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithAutomaticModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,7 @@ public class TestLinkOptionWithAutomaticModule extends JavadocTester { checkExit(Exit.OK); checkOutput("p/MyClass.html", true, """ - extends LibClass"""); } @@ -129,7 +129,7 @@ public class TestLinkOptionWithAutomaticModule extends JavadocTester { checkExit(Exit.OK); checkOutput("my.module/p/MyClass.html", true, """ - extends LibClass"""); } @@ -154,7 +154,7 @@ public class TestLinkOptionWithAutomaticModule extends JavadocTester { checkExit(Exit.OK); checkOutput("my.module/p/MyClass.html", true, """ - extends LibClass"""); } } diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java index 113cde3c60d..f2f095b255b 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,7 @@ public class TestLinkOptionWithModule extends JavadocTester { checkExit(Exit.OK); checkOutput("com.ex2/com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -98,7 +98,7 @@ public class TestLinkOptionWithModule extends JavadocTester { checkExit(Exit.OK); checkOutput("com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -121,7 +121,7 @@ public class TestLinkOptionWithModule extends JavadocTester { + "in ../out3a/ are in the unnamed module"); checkOutput("com.ex2/com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -143,7 +143,7 @@ public class TestLinkOptionWithModule extends JavadocTester { + "in ../out4a/ are in named modules"); checkOutput("com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -167,7 +167,7 @@ public class TestLinkOptionWithModule extends JavadocTester { + "in ../out5a/ are in the unnamed module"); checkOutput("com.ex2/com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -193,7 +193,7 @@ public class TestLinkOptionWithModule extends JavadocTester { + "in ../out6a/ are in named modules"); checkOutput("com/ex2/B.html", true, """ - A"""); + A"""); } void initModulesAndPackages() throws Exception{ diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java index 3c51b938396..2a415141229 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java @@ -162,11 +162,12 @@ public class TestRedirectLinks extends JavadocTester { checkExit(Exit.OK); checkOutput("pkg/B.html", true, "Link-Plain to String Class"""); checkOutput("pkg/C.html", true, "Object"""); + /java.base/java/lang/Object.html" title="class in java.lang" class=\ + "external-link">Object"""); } private Path libApi = Path.of("libApi"); @@ -272,10 +273,10 @@ public class TestRedirectLinks extends JavadocTester { "warning: URL " + oldURL + "/element-list was redirected to " + newURL + "/element-list"); checkOutput("mC/p5/C5.html", true, "extends C1"""); + /mA/p1/C1.html" title="class in p1" class="external-link">C1"""); checkOutput("mC/p6/C6.html", true, "C4"""); + /mB/p4/C4.html" title="class in p4" class="external-link">C4"""); } finally { if (oldServer != null) { out.println("Stopping old server on " + oldServer.getAddress()); diff --git a/test/langtools/jdk/javadoc/doclet/testLinkPlatform/TestLinkPlatform.java b/test/langtools/jdk/javadoc/doclet/testLinkPlatform/TestLinkPlatform.java index 5c22d6abb6d..5b2a751a295 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkPlatform/TestLinkPlatform.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkPlatform/TestLinkPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8216497 8297437 + * @bug 8216497 8297437 8369531 * @summary javadoc should auto-link to platform classes * @library /tools/lib ../../lib * @modules @@ -106,15 +106,15 @@ public class TestLinkPlatform extends JavadocTester { if (version <= 9) { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } else { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } } } @@ -136,15 +136,15 @@ public class TestLinkPlatform extends JavadocTester { if (version <= 9) { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } else { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } } } @@ -166,15 +166,15 @@ public class TestLinkPlatform extends JavadocTester { if (version <= 9) { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } else { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } } } diff --git a/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletWithModule.java b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletWithModule.java index b10c746bde4..1b30fe365a4 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletWithModule.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletWithModule.java @@ -107,20 +107,15 @@ public class TestLinkTagletWithModule extends JavadocTester { + Lib + class link + Lib.method(String) """); } @@ -164,9 +159,9 @@ public class TestLinkTagletWithModule extends JavadocTester { """); diff --git a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownLinks.java b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownLinks.java index 7bfb17d6864..76fa87f4fff 100644 --- a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownLinks.java @@ -245,19 +245,19 @@ public class TestMarkdownLinks extends JavadocTester { "/api/java.base/java/util/package-summary.html\" class=\"external-link\">java.util", "class String", + "/api/java.base/java/lang/String.html\" title=\"class in java.lang\" class=\"external-link\">String", "interface Runnable", + "/api/java.base/java/lang/Runnable.html\" title=\"interface in java.lang\" class=\"external-link\">Runnable", "a field String.CASE_INSENSITIVE_ORDER", + "/api/java.base/java/lang/String.html#CASE_INSENSITIVE_ORDER\" class=\"external-link\">String.CASE_INSENSITIVE_ORDER", "a constructor String()
  • ", + "/api/java.base/java/lang/String.html#%3Cinit%3E()\" class=\"external-link\">String()", "a method String.chars()"); + "/api/java.base/java/lang/String.html#chars()\" class=\"external-link\">String.chars()"); } /// Test the ability to include array elements in method signatures for @@ -346,4 +346,4 @@ public class TestMarkdownLinks extends JavadocTester { """); } -} \ No newline at end of file +} diff --git a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java index 5f140cc2c03..33a7249b596 100644 --- a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java +++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java @@ -1331,8 +1331,8 @@ public class TestModules extends JavadocTester { checkOutput("moduleB/testpkg3mdlB/package-summary.html", true, """ Link to \ - String Class"""); + ml" title="class in java.lang" class="external-link">Link to String Class<\ + /code>"""); checkOutput("moduleB/testpkg3mdlB/package-summary.html", true, """ TestPreviewDeclaration"); checkOutput("m/pkg/TestPreviewAPIUse.html", true, - "CorePREVIEW"); checkOutput("m/pkg/DocAnnotation.html", true, "public @interface DocAnnotation"); @@ -254,7 +254,7 @@ public class TestPreview extends JavadocTester { checkOutput("api2/api/API.html", true, "

    test()

    ", "

    testNoPreviewInSig()

    ", - "title=\"class or interface in java.util\" class=\"external-link\">List<List<APIPREVIEW>"); checkOutput("api2/api/API2.html", true, diff --git a/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java b/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java index 626e4870401..f59de2e5e70 100644 --- a/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java +++ b/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,11 @@ public class TestSeeLinkAnchor extends JavadocTester { """ Link to heading in package p2""", """ - Plain link to sub heading above""", + Plain link to heading in Class2""", + """ +
  • unqualified link to heading above
  • +
  • qualified link to heading above
  • + """, """
  • See main heading in p2.Class2
  • See heading in p2
  • @@ -89,13 +93,19 @@ public class TestSeeLinkAnchor extends JavadocTester { Plain link to Class1."""); checkOrder("p2/package-summary.html", """ - See sub heading in p2.Class2"""); +
  • See sub heading in p2.Class2
  • +
  • local qualified link
  • +
  • local unqualified link
  • + """); checkOrder("p2/doc-files/file.html", """ Plain link to heading in p1.ClassA.""", """ - See main heading in p2.ClassB"""); +
  • See main heading in p2.ClassB
  • +
  • package link
  • +
  • local anchor
  • + """); } @Test @@ -112,12 +122,57 @@ public class TestSeeLinkAnchor extends JavadocTester { checkOrder("m1/module-summary.html", """ See main heading in Class2"""); + checkOrder("m1/com/m1/package-summary.html", + """ +
    Link to local anchor. + """, + """ + package-anchor
    + """, + """ + + """); checkOrder("m1/com/m1/Class1.html", """ sub heading in Class2.""", """ -
  • See main heading in Class2
  • -
  • See heading in module m1
  • +

    More links: +

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

      Class1 Main

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

      Class1 Sub

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

      Package p2

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

      Package p2 HTML File

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

      More links: + *

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

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

      Package com.m2

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

      Module m2 HTML File

      + +

      Module m2 HTML File

      Link to {@link com.m2.Class2##main-heading heading in Class2}. + {@linkplain ##docfile-heading Plain link to local anchor}. + @see m1/##module-m1-heading Heading in module m1 + @see ##docfile-heading See local anchor """); @@ -297,4 +410,4 @@ public class TestSeeLinkAnchor extends JavadocTester { """) .write(src); } -} \ No newline at end of file +} diff --git a/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTagWithModule.java b/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTagWithModule.java index 810db378394..9c4c4da70e3 100644 --- a/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTagWithModule.java +++ b/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTagWithModule.java @@ -113,19 +113,15 @@ public class TestSeeTagWithModule extends JavadocTester {
    • m1
    • m1
    • m1/com.m1.lib
    • -
    • Lib
    • -
    • Lib.method(String)
    • -
    • Lib.method(String)
    • +
    • Lib
    • +
    • Lib.method(String)
    • +
    • Lib.method(String)
    • m2
    • m2
    • m2/com.m2.lib
    • -
    • Lib
    • -
    • Lib.method(String)
    • -
    • Lib.method(String)
    • +
    • Lib
    • +
    • Lib.method(String)
    • +
    • Lib.method(String)
    • """); } @@ -175,9 +171,9 @@ public class TestSeeTagWithModule extends JavadocTester {
    • com.ex1
    • com.ex1
    • com.ex1/com.ex1
    • -
    • A
    • -
    • A.m()
    • -
    • A.m()
    • +
    • A
    • +
    • A.m()
    • +
    • A.m()
    • com.ex2
    • com.ex2
    • """); diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java index be60a114040..c8b91dcba67 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java @@ -1123,7 +1123,7 @@ First line // @highlight : } String output = fileManager.getFileString(DOCUMENTATION_OUTPUT, "A.html"); // use the [^<>] regex to select HTML elements that immediately enclose "content" - Matcher m = Pattern.compile("(?is)(]*\" title=\"[^<>]*\" class=\"[^<>]*\">)" + Matcher m = Pattern.compile("(?is)(]*\" class=\"[^<>]*\">)" + LABEL_PLACEHOLDER + "()").matcher(output); if (!m.find()) { throw new IOException(output); diff --git a/test/langtools/jdk/javadoc/doclet/testTitleInHref/TestTitleInHref.java b/test/langtools/jdk/javadoc/doclet/testTitleInHref/TestTitleInHref.java index 98ffc9e99a4..70a77fad5a7 100644 --- a/test/langtools/jdk/javadoc/doclet/testTitleInHref/TestTitleInHref.java +++ b/test/langtools/jdk/javadoc/doclet/testTitleInHref/TestTitleInHref.java @@ -59,7 +59,7 @@ public class TestTitleInHref extends JavadocTester { """, //Test to make sure that the title shows up in cross link shows up "\ + /java/io/File.html" title="class in java.io" class="external-link">\ This is a cross link to class File"""); } } diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 6b147d32d00..37d50674855 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -798,6 +798,22 @@ public class SourceLauncherTest extends TestRunner { } } + @Test + public void testPrivateConstructor(Path base) throws IOException { + tb.writeJavaFiles(base, + """ + class PrivateConstructor { + private PrivateConstructor() {} + void main() {} + } + """); + testError(base.resolve("PrivateConstructor.java"), "", + """ + error: no non-private zero argument constructor found in class PrivateConstructor + remove private from existing constructor or define as: + public PrivateConstructor()"""); + } + @Test public void testAbstractClassInstanceMain(Path base) throws IOException { tb.writeJavaFiles(base, @@ -904,14 +920,6 @@ public class SourceLauncherTest extends TestRunner { } } - void checkContains(String name, String found, String expect) { - expect = expect.replace("\n", tb.lineSeparator); - out.println(name + ": " + found); - if (!found.contains(expect)) { - error("Expected output not found: " + expect); - } - } - void checkEqual(String name, List found, List expect) { out.println(name + ": " + found); tb.checkEqual(expect, found); @@ -939,7 +947,6 @@ public class SourceLauncherTest extends TestRunner { } void checkFault(String name, Throwable found, String expect) { - expect = expect.replace("\n", tb.lineSeparator); out.println(name + ": " + found); if (found == null) { error("No exception thrown; expected Fault"); @@ -947,8 +954,14 @@ public class SourceLauncherTest extends TestRunner { if (!(found instanceof Fault)) { error("Unexpected exception; expected Fault"); } - if (!(found.getMessage().equals(expect))) { - error("Unexpected detail message; expected: " + expect); + String actual = found.getMessage(); + List actualLines = actual.lines().toList(); + List expectLines = expect.lines().toList(); + if (!(actualLines.equals(expectLines))) { + error("Unexpected detail message; expected: \n" + + expect.indent(2) + + "\nactual:\n" + + actual.indent(2)); } } } diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index f8d02d0ddf1..9a37ce60654 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 + * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -32,11 +32,14 @@ * @run main AttrRecovery */ +import com.sun.source.tree.MemberReferenceTree; +import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; +import java.nio.file.Files; import java.nio.file.Path; import java.util.IdentityHashMap; import java.util.List; @@ -394,4 +397,102 @@ public class AttrRecovery extends TestRunner { error("Expected: " + expected + ", but got: " + actual); } } + + @Test //JDK-8372336 + public void testCompletionFailureNoBreakInvocation() throws Exception { + Path curPath = Path.of("."); + Path lib = curPath.resolve("lib"); + Path classes = lib.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .outdir(classes) + .sources(""" + package test; + public class Intermediate extends Base {} + """, + """ + package test; + public class Base { + public int get() { + return -1; + } + } + """) + .run() + .writeAll(); + + Files.delete(classes.resolve("test").resolve("Base.class")); + + record TestCase(String code, String... expectedErrors) {} + TestCase[] testCases = new TestCase[] { + new TestCase(""" + package test; + public class Test { + private void test(Intermediate i) { + int j = i != null ? i.get() : -1; + } + } + """, + "Test.java:4:30: compiler.err.cant.access: test.Base, (compiler.misc.class.file.not.found: test.Base)", + "1 error"), + new TestCase(""" + package test; + public class Test { + private void test(Intermediate i) { + i.get(); + } + } + """, + "Test.java:4:10: compiler.err.cant.access: test.Base, (compiler.misc.class.file.not.found: test.Base)", + "1 error") + }; + + for (TestCase tc : testCases) { + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev") + .classpath(classes) + .sources(tc.code()) + .outdir(curPath) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + @Override + public Void visitMethodInvocation(MethodInvocationTree node, Void p) { + if (!node.toString().contains("super")) { + verifyElement(); + } + return super.visitMethodInvocation(node, p); + } + @Override + public Void visitMemberReference(MemberReferenceTree node, Void p) { + verifyElement(); + return super.visitMemberReference(node, p); + } + private void verifyElement() { + Element el = trees.getElement(getCurrentPath()); + if (!el.getSimpleName().contentEquals("get")) { + error("Expected good Element, but got: " + el); + } + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of(tc.expectedErrors); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + } } diff --git a/test/lib/jdk/test/lib/security/CertificateBuilder.java b/test/lib/jdk/test/lib/security/CertificateBuilder.java index d35a21e7ab5..6bf554c3517 100644 --- a/test/lib/jdk/test/lib/security/CertificateBuilder.java +++ b/test/lib/jdk/test/lib/security/CertificateBuilder.java @@ -153,22 +153,26 @@ public class CertificateBuilder { * @throws IOException */ public static SubjectAlternativeNameExtension createDNSSubjectAltNameExt( - boolean critical, String dnsName) throws IOException { + boolean critical, String... dnsNames) throws IOException { GeneralNames gns = new GeneralNames(); - gns.add(new GeneralName(new DNSName(dnsName))); + for (String dnsName : dnsNames) { + gns.add(new GeneralName(new DNSName(dnsName))); + } return new SubjectAlternativeNameExtension(critical, gns); } /** * Create a Subject Alternative Name extension for the given IP address * @param critical Sets the extension to critical or non-critical - * @param ipAddress IP address to use in the extension + * @param ipAddresses IP addresses to use in the extension * @throws IOException */ public static SubjectAlternativeNameExtension createIPSubjectAltNameExt( - boolean critical, String ipAddress) throws IOException { + boolean critical, String... ipAddresses) throws IOException { GeneralNames gns = new GeneralNames(); - gns.add(new GeneralName(new IPAddressName(ipAddress))); + for (String ip : ipAddresses) { + gns.add(new GeneralName(new IPAddressName(ip))); + } return new SubjectAlternativeNameExtension(critical, gns); } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java b/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java deleted file mode 100644 index 60f36d9f157..00000000000 --- a/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package org.openjdk.bench.java.lang.foreign; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.CompilerControl; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.TearDown; -import org.openjdk.jmh.annotations.Warmup; -import jdk.internal.misc.Unsafe; - -import java.lang.foreign.Arena; -import java.lang.foreign.MemorySegment; -import java.nio.ByteBuffer; -import java.nio.IntBuffer; -import java.util.concurrent.TimeUnit; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_INT_UNALIGNED; - -@BenchmarkMode(Mode.AverageTime) -@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) -@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) -@State(org.openjdk.jmh.annotations.Scope.Thread) -@OutputTimeUnit(TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgs = { "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED" }) -public class BulkOps { - - static final Unsafe unsafe = Utils.unsafe; - - static final int ELEM_SIZE = 1_000_000; - static final int CARRIER_SIZE = (int)JAVA_INT.byteSize(); - static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; - - final Arena arena = Arena.ofShared(); - - final long unsafe_addr = unsafe.allocateMemory(ALLOC_SIZE); - final MemorySegment segment = arena.allocate(ALLOC_SIZE, 1); - - final IntBuffer buffer = IntBuffer.allocate(ELEM_SIZE); - - final int[] ints = new int[ELEM_SIZE]; - final MemorySegment bytesSegment = MemorySegment.ofArray(ints); - final long UNSAFE_INT_OFFSET = unsafe.arrayBaseOffset(int[].class); - - // large(ish) segments/buffers with same content, 0, for mismatch, non-multiple-of-8 sized - static final int SIZE_WITH_TAIL = (1024 * 1024) + 7; - final MemorySegment mismatchSegmentLarge1; - - { - mismatchSegmentLarge1 = arena.allocate(SIZE_WITH_TAIL, 1); - } - - final MemorySegment mismatchSegmentLarge2 = arena.allocate(SIZE_WITH_TAIL, 1); - final ByteBuffer mismatchBufferLarge1 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); - final ByteBuffer mismatchBufferLarge2 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); - - // mismatch at first byte - final MemorySegment mismatchSegmentSmall1 = arena.allocate(7, 1); - final MemorySegment mismatchSegmentSmall2 = arena.allocate(7, 1); - final ByteBuffer mismatchBufferSmall1 = ByteBuffer.allocateDirect(7); - final ByteBuffer mismatchBufferSmall2 = ByteBuffer.allocateDirect(7); - - @Setup - public void setup() { - mismatchSegmentSmall1.fill((byte) 0xFF); - mismatchBufferSmall1.put((byte) 0xFF).clear(); - // verify expected mismatch indices - long si = mismatchSegmentLarge1.mismatch(mismatchSegmentLarge2); - if (si != -1) - throw new AssertionError("Unexpected mismatch index:" + si); - int bi = mismatchBufferLarge1.mismatch(mismatchBufferLarge2); - if (bi != -1) - throw new AssertionError("Unexpected mismatch index:" + bi); - si = mismatchSegmentSmall1.mismatch(mismatchSegmentSmall2); - if (si != 0) - throw new AssertionError("Unexpected mismatch index:" + si); - bi = mismatchBufferSmall1.mismatch(mismatchBufferSmall2); - if (bi != 0) - throw new AssertionError("Unexpected mismatch index:" + bi); - - for (int i = 0; i < ints.length ; i++) { - ints[i] = i; - } - } - - @TearDown - public void tearDown() { - arena.close(); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void unsafe_fill() { - unsafe.setMemory(unsafe_addr, ALLOC_SIZE, (byte)42); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_fill() { - segment.fill((byte)42); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void unsafe_copy() { - unsafe.copyMemory(ints, UNSAFE_INT_OFFSET, null, unsafe_addr, ALLOC_SIZE); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy() { - segment.copyFrom(bytesSegment); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy_static() { - MemorySegment.copy(ints, 0, segment, JAVA_INT_UNALIGNED, 0, ints.length); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy_static_small() { - MemorySegment.copy(ints, 0, segment, JAVA_INT_UNALIGNED, 0, 10); - } - - @Benchmark - @CompilerControl(CompilerControl.Mode.DONT_INLINE) - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy_static_small_dontinline() { - MemorySegment.copy(ints, 0, segment, JAVA_INT_UNALIGNED, 0, 10); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void unsafe_copy_small() { - unsafe.copyMemory(ints, UNSAFE_INT_OFFSET, null, unsafe_addr, 10 * CARRIER_SIZE); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void buffer_copy_small() { - buffer.put(0, ints, 0, 10); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void buffer_copy() { - buffer.put(0, ints, 0, ints.length); - } - - @Benchmark - @CompilerControl(CompilerControl.Mode.DONT_INLINE) - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy_static_dontinline() { - MemorySegment.copy(ints, 0, segment, JAVA_INT_UNALIGNED, 0, ints.length); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public long mismatch_large_segment() { - return mismatchSegmentLarge1.mismatch(mismatchSegmentLarge2); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public int mismatch_large_bytebuffer() { - return mismatchBufferLarge1.mismatch(mismatchBufferLarge2); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public long mismatch_small_segment() { - return mismatchSegmentSmall1.mismatch(mismatchSegmentSmall2); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public int mismatch_small_bytebuffer() { - return mismatchBufferSmall1.mismatch(mismatchBufferSmall2); - } -} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java index ca6f21d20e9..83522bd4f3c 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,9 +38,13 @@ import org.openjdk.jmh.annotations.Warmup; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; import java.nio.ByteBuffer; +import java.util.Random; import java.util.concurrent.TimeUnit; +import static java.lang.foreign.ValueLayout.JAVA_LONG; + @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -49,63 +53,122 @@ import java.util.concurrent.TimeUnit; @Fork(value = 3) public class SegmentBulkCopy { - @Param({"2", "3", "4", "5", "6", "7", "8", "64", "512", - "4096", "32768", "262144", "2097152", "16777216", "134217728"}) - public int ELEM_SIZE; + @Param({"2", "4", "8", "12", "16", "64", "512", "4096", "32768", "262144", "2097152", "16777216", "134217728"}) + public int size; - byte[] srcArray; - byte[] dstArray; - MemorySegment heapSrcSegment; - MemorySegment heapDstSegment; - MemorySegment nativeSrcSegment; - MemorySegment nativeDstSegment; - ByteBuffer srcBuffer; - ByteBuffer dstBuffer; + public static class Array extends SegmentBulkCopy { + + byte[] srcArray; + byte[] dstArray; + + ByteBuffer srcBuffer; + ByteBuffer dstBuffer; + + @Setup + public void setup() { + srcArray = new byte[size]; + var rnd = new Random(42); + rnd.nextBytes(srcArray); + dstArray = new byte[size]; + srcBuffer = ByteBuffer.wrap(srcArray); + dstBuffer = ByteBuffer.wrap(dstArray); + } + + @Benchmark + public void arrayCopy() { + System.arraycopy(srcArray, 0, dstArray, 0, size); + } + + @Benchmark + public void bufferCopy() { + dstBuffer.put(0, srcBuffer, 0, size); + } - @Setup - public void setup() { - srcArray = new byte[ELEM_SIZE]; - dstArray = new byte[ELEM_SIZE]; - heapSrcSegment = MemorySegment.ofArray(srcArray); - heapDstSegment = MemorySegment.ofArray(dstArray); - nativeSrcSegment = Arena.ofAuto().allocate(ELEM_SIZE); - nativeDstSegment = Arena.ofAuto().allocate(ELEM_SIZE); - srcBuffer = ByteBuffer.wrap(srcArray); - dstBuffer = ByteBuffer.wrap(dstArray); } - @Benchmark - public void arrayCopy() { - System.arraycopy(srcArray, 0, dstArray, 0, ELEM_SIZE); - } + public static class Segment extends SegmentBulkCopy { - @Benchmark - public void bufferCopy() { - dstBuffer.put(srcBuffer); - } + enum SegmentType {HEAP, NATIVE} + enum Alignment {ALIGNED, UNALIGNED} - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) - @Benchmark - public void heapSegmentCopyJava() { - MemorySegment.copy(heapSrcSegment, 0, heapDstSegment, 0, ELEM_SIZE); - } + @Param({"HEAP", "NATIVE"}) + String segmentType; - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) - @Benchmark - public void heapSegmentCopyUnsafe() { - MemorySegment.copy(heapSrcSegment, 0, heapDstSegment, 0, ELEM_SIZE); - } + @Param({"ALIGNED", "UNALIGNED"}) + String alignment; - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) - @Benchmark - public void nativeSegmentCopyJava() { - MemorySegment.copy(nativeSrcSegment, 0, nativeDstSegment, 0, ELEM_SIZE); - } + MemorySegment srcSegment; + MemorySegment dstSegment; + + @Setup + public void setup() { + // A long array is likely to be aligned at 8-byte boundaries + long[] baseArray; + + baseArray = new long[size / Long.BYTES + 1]; + var rnd = new Random(42); + for (int i = 0; i < baseArray.length; i++) { + baseArray[i] = rnd.nextLong(); + } + + switch (SegmentType.valueOf(segmentType)) { + case HEAP -> { + srcSegment = MemorySegment.ofArray(baseArray); + dstSegment = MemorySegment.ofArray(baseArray.clone()); + } + case NATIVE -> { + srcSegment = Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + dstSegment = Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + } + } + switch (Alignment.valueOf(alignment)) { + case ALIGNED -> { + srcSegment = srcSegment.asSlice(0, size); + dstSegment = dstSegment.asSlice(0, size); + } + case UNALIGNED -> { + srcSegment = srcSegment.asSlice(1, size); + dstSegment = dstSegment.asSlice(1, size); + } + } + } + + @Benchmark + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) + public void copy() { + MemorySegment.copy(srcSegment, 0, dstSegment, 0, size); + } + + @Benchmark + public void copyLoopIntInt() { + for (int i = 0; i < (int) srcSegment.byteSize(); i++) { + final byte v = srcSegment.get(ValueLayout.JAVA_BYTE, i); + dstSegment.set(ValueLayout.JAVA_BYTE, i, v); + } + } + + @Benchmark + public void copyLoopIntLong() { + for (int i = 0; i < srcSegment.byteSize(); i++) { + final byte v = srcSegment.get(ValueLayout.JAVA_BYTE, i); + dstSegment.set(ValueLayout.JAVA_BYTE, i, v); + } + } + + @Benchmark + public void copyLoopLongLong() { + for (long i = 0; i < srcSegment.byteSize(); i++) { + final byte v = srcSegment.get(ValueLayout.JAVA_BYTE, i); + dstSegment.set(ValueLayout.JAVA_BYTE, i, v); + } + } + + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) + @Benchmark + public void copyUnsafe() { + MemorySegment.copy(srcSegment, 0, dstSegment, 0, size); + } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) - @Benchmark - public void nativeSegmentCopyUnsafe() { - MemorySegment.copy(nativeSrcSegment, 0, nativeDstSegment, 0, ELEM_SIZE); } } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java index 96cf62cc5f6..3c4770731b6 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,8 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.concurrent.TimeUnit; +import static java.lang.foreign.ValueLayout.JAVA_LONG; + @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -51,99 +53,105 @@ import java.util.concurrent.TimeUnit; @Fork(value = 3) public class SegmentBulkFill { - @Param({"2", "3", "4", "5", "6", "7", "8", "64", "512", - "4096", "32768", "262144", "2097152", "16777216", "134217728"}) - public int ELEM_SIZE; + private static final byte ZERO = 0; - byte[] array; - MemorySegment heapSegment; - MemorySegment nativeSegment; - MemorySegment unalignedSegment; - ByteBuffer buffer; + @Param({"2", "4", "8", "12", "16", "64", "512", "4096", "32768", "262144", "2097152", "16777216", "134217728"}) + public int size; - @Setup - public void setup() { - array = new byte[ELEM_SIZE]; - heapSegment = MemorySegment.ofArray(array); - nativeSegment = Arena.ofAuto().allocate(ELEM_SIZE, 8); - unalignedSegment = Arena.ofAuto().allocate(ELEM_SIZE + 1, 8).asSlice(1); - buffer = ByteBuffer.wrap(array); - } + public static class Array extends SegmentBulkFill { - @Benchmark - public void arraysFill() { - Arrays.fill(array, (byte) 0); - } + byte[] array; + ByteBuffer buffer; - @Benchmark - public void arraysFillLoop() { - for (int i = 0; i < array.length; i++) { - array[i] = 0; + @Setup + public void setup() { + array = new byte[size]; + buffer = ByteBuffer.wrap(array); } - } - @Benchmark - public void bufferFillLoop() { - for (int i = 0; i < array.length; i++) { - buffer.put(i, (byte)0); + @Benchmark + public void arraysFill() { + Arrays.fill(array, ZERO); } - } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) - @Benchmark - public void heapSegmentFillJava() { - heapSegment.fill((byte) 0); - } - - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) - @Benchmark - public void heapSegmentFillUnsafe() { - heapSegment.fill((byte) 0); - } - - @Benchmark - public void heapSegmentFillLoop() { - for (long i = 0; i < heapSegment.byteSize(); i++) { - heapSegment.set(ValueLayout.JAVA_BYTE, i, (byte) 0); + @Benchmark + public void arraysFillLoop() { + for (int i = 0; i < array.length; i++) { + array[i] = ZERO; + } } - } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) - @Benchmark - public void nativeSegmentFillJava() { - nativeSegment.fill((byte) 0); - } - - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) - @Benchmark - public void nativeSegmentFillUnsafe() { - nativeSegment.fill((byte) 0); - } - - @Benchmark - public void nativeSegmentFillLoop() { - for (long i = 0; i < nativeSegment.byteSize(); i++) { - nativeSegment.set(ValueLayout.JAVA_BYTE, i, (byte) 0); + @Benchmark + public void bufferFillLoop() { + for (int i = 0; i < array.length; i++) { + buffer.put(i, ZERO); + } } + } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) - @Benchmark - public void unalignedSegmentFillJava() { - unalignedSegment.fill((byte) 0); - } + public static class Segment extends SegmentBulkFill { - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) - @Benchmark - public void unalignedSegmentFillUnsafe() { - unalignedSegment.fill((byte) 0); - } + enum SegmentType {HEAP, NATIVE} + enum Alignment {ALIGNED, UNALIGNED} - @Benchmark - public void unalignedSegmentFillLoop() { - for (long i = 0; i < unalignedSegment.byteSize(); i++) { - unalignedSegment.set(ValueLayout.JAVA_BYTE, i, (byte) 0); + @Param({"HEAP", "NATIVE"}) + String segmentType; + + @Param({"ALIGNED", "UNALIGNED"}) + String alignment; + + MemorySegment segment; + + @Setup + public void setup() { + // A long array is likely to be aligned at 8-byte boundaries + long[] baseArray = new long[size / Long.BYTES + 1]; + var heapSegment = MemorySegment.ofArray(baseArray); + + segment = switch (SegmentType.valueOf(segmentType)) { + case HEAP -> heapSegment; + case NATIVE -> Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + }; + segment = switch (Alignment.valueOf(alignment)) { + case ALIGNED -> segment.asSlice(0, size); + case UNALIGNED -> segment.asSlice(1, size); + }; } + + @Benchmark + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) + public void fill() { + segment.fill(ZERO); + } + + @Benchmark + public void fillLoopIntInt() { + for (int i = 0; i < (int)segment.byteSize(); i++) { + segment.set(ValueLayout.JAVA_BYTE, i, ZERO); + } + } + + @Benchmark + public void fillLoopIntLong() { + for (int i = 0; i < segment.byteSize(); i++) { + segment.set(ValueLayout.JAVA_BYTE, i, ZERO); + } + } + + @Benchmark + public void fillLoopLongLong() { + for (long i = 0; i < segment.byteSize(); i++) { + segment.set(ValueLayout.JAVA_BYTE, i, ZERO); + } + } + + @Benchmark + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) + public void fillUnsafe() { + segment.fill(ZERO); + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkHash.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkHash.java index 927a7d3fb1f..0213916fcd6 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkHash.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkHash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ import java.util.Random; import java.util.concurrent.TimeUnit; import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -54,47 +55,98 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; @Fork(value = 3, jvmArgs = {"--add-exports=java.base/jdk.internal.foreign=ALL-UNNAMED"}) public class SegmentBulkHash { - @Param({"8", "64"}) - public int ELEM_SIZE; + @Param({"2", "4", "8", "12", "16", "64", "512", "4096", "32768", "262144", "2097152", "16777216", "134217728"}) + public int size; - byte[] array; - AbstractMemorySegmentImpl heapSegment; - AbstractMemorySegmentImpl nativeSegment; + public static class Array extends SegmentBulkHash { - @Setup - public void setup() { - // Always use the same alignment regardless of size - nativeSegment = (AbstractMemorySegmentImpl) Arena.ofAuto().allocate(ELEM_SIZE, 16); - var rnd = new Random(42); - for (int i = 0; i < ELEM_SIZE; i++) { - nativeSegment.set(JAVA_BYTE, i, (byte) rnd.nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE)); + byte[] array; + + @Setup + public void setup() { + byte[] randomArray = new byte[size + 1]; + var rnd = new Random(42); + rnd.nextBytes(randomArray); + + array = Arrays.copyOf(randomArray, size); } - array = nativeSegment.toArray(JAVA_BYTE); - heapSegment = (AbstractMemorySegmentImpl) MemorySegment.ofArray(array); - } - @Benchmark - public int array() { - return Arrays.hashCode(array); - } - - @Benchmark - public int heapSegment() { - return SegmentBulkOperations.contentHash(heapSegment, 0, ELEM_SIZE); - } - - @Benchmark - public int nativeSegment() { - return SegmentBulkOperations.contentHash(nativeSegment, 0, ELEM_SIZE); - } - - @Benchmark - public int nativeSegmentJava() { - int result = 1; - for (long i = 0; i < ELEM_SIZE; i++) { - result = 31 * result + nativeSegment.get(JAVA_BYTE, i); + @Benchmark + public int array() { + return Arrays.hashCode(array); } - return result; + + } + + public static class Segment extends SegmentBulkHash { + + enum SegmentType {HEAP, NATIVE} + enum Alignment {ALIGNED, UNALIGNED} + + @Param({"HEAP", "NATIVE"}) + String segmentType; + + @Param({"ALIGNED", "UNALIGNED"}) + String alignment; + + AbstractMemorySegmentImpl segment; + + @Setup + public void setup() { + // A long array is likely to be aligned at 8-byte boundaries + long[] baseArray; + + baseArray = new long[size / Long.BYTES + 1]; + var rnd = new Random(42); + for (int i = 0; i < baseArray.length; i++) { + baseArray[i] = rnd.nextLong(); + } + var heapSegment = MemorySegment.ofArray(baseArray); + + var s = switch (SegmentType.valueOf(segmentType)) { + case HEAP -> heapSegment; + case NATIVE -> Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + }; + s = switch (Alignment.valueOf(alignment)) { + case ALIGNED -> s.asSlice(0, size); + case UNALIGNED -> s.asSlice(1, size); + }; + + segment = (AbstractMemorySegmentImpl) s; + } + + @Benchmark + public int hash() { + return SegmentBulkOperations.contentHash(segment, 0, size); + } + + @Benchmark + public int hashLoopIntInt() { + int result = 1; + for (int i = 0; i < (int)segment.byteSize(); i++) { + result = 31 * result + segment.get(JAVA_BYTE, i); + } + return result; + } + + @Benchmark + public int hashLoopIntLong() { + int result = 1; + for (int i = 0; i < segment.byteSize(); i++) { + result = 31 * result + segment.get(JAVA_BYTE, i); + } + return result; + } + + @Benchmark + public int hashLoopLongLong() { + int result = 1; + for (long i = 0; i < segment.byteSize(); i++) { + result = 31 * result + segment.get(JAVA_BYTE, i); + } + return result; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java index 61ceb7b956e..aa4dd0b68f9 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import org.openjdk.jmh.annotations.Warmup; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; import java.util.Arrays; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -52,60 +53,122 @@ import static java.lang.foreign.ValueLayout.*; @Fork(value = 3) public class SegmentBulkMismatch { - @Param({"2", "3", "4", "5", "6", "7", "8", "64", "512", - "4096", "32768", "262144", "2097152", "16777216", "134217728"}) - public int ELEM_SIZE; + @Param({"2", "4", "8", "12", "16", "64", "512", "4096", "32768", "262144", "2097152", "16777216", "134217728"}) + public int size; - MemorySegment srcNative; - MemorySegment dstNative; - byte[] srcArray; - byte[] dstArray; - MemorySegment srcHeap; - MemorySegment dstHeap; + public static class Array extends SegmentBulkMismatch { - @Setup - public void setup() { - // Always use the same alignment regardless of size - srcNative = Arena.ofAuto().allocate(ELEM_SIZE,16); - dstNative = Arena.ofAuto().allocate(ELEM_SIZE, 16); - var rnd = new Random(42); - for (int i = 0; i < ELEM_SIZE; i++) { - srcNative.set(JAVA_BYTE, i, (byte) rnd.nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE)); + byte[] srcArray; + byte[] dstArray; + + @Setup + public void setup() { + srcArray = new byte[size]; + var rnd = new Random(42); + rnd.nextBytes(srcArray); + dstArray = Arrays.copyOf(srcArray, size); } - dstNative.copyFrom(srcNative); - srcArray = srcNative.toArray(JAVA_BYTE); - dstArray = dstNative.toArray(JAVA_BYTE); - srcHeap = MemorySegment.ofArray(srcArray); - dstHeap = MemorySegment.ofArray(dstArray); + + @Benchmark + public long array() { + return Arrays.mismatch(srcArray, dstArray); + } + } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) - @Benchmark - public long nativeSegmentJava() { - return srcNative.mismatch(dstNative); - } + public static class Segment extends SegmentBulkMismatch { - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) - @Benchmark - public long heapSegmentJava() { - return srcHeap.mismatch(dstHeap); - } + enum SegmentType {HEAP, NATIVE} + enum Alignment {ALIGNED, UNALIGNED} - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) - @Benchmark - public long nativeSegmentUnsafe() { - return srcNative.mismatch(dstNative); - } + @Param({"HEAP", "NATIVE"}) + String segmentType; - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) - @Benchmark - public long heapSegmentUnsafe() { - return srcHeap.mismatch(dstHeap); - } + @Param({"ALIGNED", "UNALIGNED"}) + String alignment; + + MemorySegment srcSegment; + MemorySegment dstSegment; + + @Setup + public void setup() { + // A long array is likely to be aligned at 8-byte boundaries + long[] baseArray; + + baseArray = new long[size / Long.BYTES + 1]; + var rnd = new Random(42); + for (int i = 0; i < baseArray.length; i++) { + baseArray[i] = rnd.nextLong(); + } + + switch (SegmentType.valueOf(segmentType)) { + case HEAP -> { + srcSegment = MemorySegment.ofArray(baseArray); + dstSegment = MemorySegment.ofArray(baseArray.clone()); + } + case NATIVE -> { + var s = MemorySegment.ofArray(baseArray); + srcSegment = Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + dstSegment = Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + } + } + switch (Alignment.valueOf(alignment)) { + case ALIGNED -> { + srcSegment = srcSegment.asSlice(0, size); + dstSegment = dstSegment.asSlice(0, size); + } + case UNALIGNED -> { + srcSegment = srcSegment.asSlice(1, size); + dstSegment = dstSegment.asSlice(1, size); + } + } + } + + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) + @Benchmark + public long mismatch() { + return srcSegment.mismatch(dstSegment); + } + + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) + @Benchmark + public long mismatchUnsafe() { + return srcSegment.mismatch(dstSegment); + } + + @Benchmark + public long mismatchLoopIntInt() { + // Simplified version that assumes the segments are of equal size + for (int i = 0; i < (int)srcSegment.byteSize(); i++) { + if (srcSegment.get(ValueLayout.JAVA_BYTE, i) != dstSegment.get(ValueLayout.JAVA_BYTE, i)) { + return i; + } + } + return -1; + } + + @Benchmark + public long mismatchLoopIntLong() { + // Simplified version that assumes the segments are of equal size + for (int i = 0; i < srcSegment.byteSize(); i++) { + if (srcSegment.get(ValueLayout.JAVA_BYTE, i) != dstSegment.get(ValueLayout.JAVA_BYTE, i)) { + return i; + } + } + return -1; + } + + @Benchmark + public long mismatchLoopLongLong() { + // Simplified version that assumes the segments are of equal size + for (long i = 0; i < srcSegment.byteSize(); i++) { + if (srcSegment.get(ValueLayout.JAVA_BYTE, i) != dstSegment.get(ValueLayout.JAVA_BYTE, i)) { + return i; + } + } + return -1; + } - @Benchmark - public long array() { - return Arrays.mismatch(srcArray, dstArray); } }