From 5fe731d55a54ace42de4a15d612dba310de9d977 Mon Sep 17 00:00:00 2001 From: Saranya Natarajan Date: Wed, 26 Nov 2025 09:27:31 +0000 Subject: [PATCH 01/81] 8349835: C2: Simplify IGV property printing Reviewed-by: rcastanedalo, dfenacci, chagedorn --- src/hotspot/share/opto/idealGraphPrinter.cpp | 211 +++++++++---------- src/hotspot/share/opto/idealGraphPrinter.hpp | 3 +- 2 files changed, 98 insertions(+), 116 deletions(-) diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 6a738878a1b..b28949e27c2 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -35,6 +35,96 @@ #ifndef PRODUCT +// Support for printing properties +class PrintProperties +{ +private: + IdealGraphPrinter* _printer; + +public: + PrintProperties(IdealGraphPrinter* printer) : _printer(printer) {} + void print_node_properties(Node* node); + void print_lrg_properties(const LRG& lrg, const char* buffer); + void print_property(int flag, const char* name); + void print_property(int flag, const char* name, const char* val); + void print_property(int flag, const char* name, int val); +}; + +void PrintProperties::print_node_properties(Node* node) { + const jushort flags = node->flags(); + print_property((flags & Node::Flag_is_Copy), "is_copy"); + print_property((flags & Node::Flag_rematerialize), "rematerialize"); + print_property((flags & Node::Flag_needs_anti_dependence_check), "needs_anti_dependence_check"); + print_property((flags & Node::Flag_is_macro), "is_macro"); + print_property((flags & Node::Flag_is_Con), "is_con"); + print_property((flags & Node::Flag_is_cisc_alternate), "is_cisc_alternate"); + print_property((flags & Node::Flag_is_dead_loop_safe), "is_dead_loop_safe"); + print_property((flags & Node::Flag_may_be_short_branch), "may_be_short_branch"); + print_property((flags & Node::Flag_has_call), "has_call"); + print_property((flags & Node::Flag_has_swapped_edges), "has_swapped_edges"); + Matcher* matcher = _printer->C->matcher(); + if (matcher != nullptr) { + print_property(matcher->is_shared(node),"is_shared"); + print_property(!(matcher->is_shared(node)), "is_shared", IdealGraphPrinter::FALSE_VALUE); + print_property(matcher->is_dontcare(node), "is_dontcare"); + print_property(!(matcher->is_dontcare(node)),"is_dontcare", IdealGraphPrinter::FALSE_VALUE); + Node* old = matcher->find_old_node(node); + if (old != nullptr) { + print_property(true, "old_node_idx", old->_idx); + } + } +} + +void PrintProperties::print_lrg_properties(const LRG &lrg, const char *buffer) { + print_property(true, "mask", buffer); + print_property(true, "mask_size", lrg.mask_size()); + if (lrg._degree_valid) { + print_property(true, "degree", lrg.degree()); + } + print_property(true, "num_regs", lrg.num_regs()); + print_property(true, "reg_pressure", lrg.reg_pressure()); + print_property(true, "cost", lrg._cost); + print_property(true, "area", lrg._area); + print_property(true, "score", lrg.score()); + print_property((lrg._risk_bias != 0), "risk_bias", lrg._risk_bias); + print_property((lrg._copy_bias != 0), "copy_bias", lrg._copy_bias); + print_property(lrg.is_singledef(), "is_singledef"); + print_property(lrg.is_multidef(), "is_multidef"); + print_property(lrg._is_oop, "is_oop"); + print_property(lrg._is_float, "is_float"); + print_property(lrg._is_vector, "is_vector"); + print_property(lrg._is_predicate, "is_predicate"); + print_property(lrg._is_scalable, "is_scalable"); + print_property(lrg._was_spilled1, "was_spilled1"); + print_property(lrg._was_spilled2, "was_spilled2"); + print_property(lrg._direct_conflict, "direct_conflict"); + print_property(lrg._fat_proj, "fat_proj"); + print_property(lrg._was_lo, "_was_lo"); + print_property(lrg._has_copy, "has_copy"); + print_property(lrg._at_risk, "at_risk"); + print_property(lrg._must_spill, "must_spill"); + print_property(lrg._is_bound, "is_bound"); + print_property((lrg._msize_valid && lrg._degree_valid && lrg.lo_degree()), "trivial"); +} + +void PrintProperties::print_property(int flag, const char* name) { + if (flag != 0) { + _printer->print_prop(name, IdealGraphPrinter::TRUE_VALUE); + } +} + +void PrintProperties::print_property(int flag, const char* name, const char* val) { + if (flag != 0) { + _printer->print_prop(name, val); + } +} + +void PrintProperties::print_property(int flag, const char* name, int val) { + if (flag != 0) { + _printer->print_prop(name, val); + } +} + // Constants // Keep consistent with Java constants const char *IdealGraphPrinter::INDENT = " "; @@ -522,54 +612,8 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) { print_prop("jvms", buffer); } - const jushort flags = node->flags(); - if (flags & Node::Flag_is_Copy) { - print_prop("is_copy", "true"); - } - if (flags & Node::Flag_rematerialize) { - print_prop("rematerialize", "true"); - } - if (flags & Node::Flag_needs_anti_dependence_check) { - print_prop("needs_anti_dependence_check", "true"); - } - if (flags & Node::Flag_is_macro) { - print_prop("is_macro", "true"); - } - if (flags & Node::Flag_is_Con) { - print_prop("is_con", "true"); - } - if (flags & Node::Flag_is_cisc_alternate) { - print_prop("is_cisc_alternate", "true"); - } - if (flags & Node::Flag_is_dead_loop_safe) { - print_prop("is_dead_loop_safe", "true"); - } - if (flags & Node::Flag_may_be_short_branch) { - print_prop("may_be_short_branch", "true"); - } - if (flags & Node::Flag_has_call) { - print_prop("has_call", "true"); - } - if (flags & Node::Flag_has_swapped_edges) { - print_prop("has_swapped_edges", "true"); - } - - if (C->matcher() != nullptr) { - if (C->matcher()->is_shared(node)) { - print_prop("is_shared", "true"); - } else { - print_prop("is_shared", "false"); - } - if (C->matcher()->is_dontcare(node)) { - print_prop("is_dontcare", "true"); - } else { - print_prop("is_dontcare", "false"); - } - Node* old = C->matcher()->find_old_node(node); - if (old != nullptr) { - print_prop("old_node_idx", old->_idx); - } - } + PrintProperties print_node(this); + print_node.print_node_properties(node); if (node->is_Proj()) { print_prop("con", (int)node->as_Proj()->_con); @@ -1145,73 +1189,10 @@ void IdealGraphPrinter::print(const char* name, Node* node, GrowableArray { - private: + friend class PrintProperties; +private: static const char *INDENT; static const char *TOP_ELEMENT; static const char *GROUP_ELEMENT; From 5291e1c1e1ddc19d814dbdb3a981049fe40575ea Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 26 Nov 2025 09:29:55 +0000 Subject: [PATCH 02/81] 8372513: Shenandoah: ShenandoahMaxRegionSize can produce an unaligned heap alignment Reviewed-by: jsikstro, eosterlund, shade --- .../share/gc/shenandoah/shenandoahArguments.cpp | 3 ++- src/hotspot/share/runtime/arguments.cpp | 1 + .../gc/shenandoah/options/TestRegionSizeArgs.java | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index a7cf8e638dd..c1fa4b964b7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -37,6 +37,7 @@ #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "utilities/defaultStream.hpp" +#include "utilities/powerOfTwo.hpp" void ShenandoahArguments::initialize() { #if !(defined AARCH64 || defined AMD64 || defined PPC64 || defined RISCV64) @@ -205,7 +206,7 @@ void ShenandoahArguments::initialize() { } size_t ShenandoahArguments::conservative_max_heap_alignment() { - size_t align = ShenandoahMaxRegionSize; + size_t align = next_power_of_2(ShenandoahMaxRegionSize); if (UseLargePages) { align = MAX2(align, os::large_page_size()); } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 55ee7641a5f..ff1de899bdd 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1482,6 +1482,7 @@ void Arguments::set_conservative_max_heap_alignment() { os::vm_allocation_granularity(), os::max_page_size(), GCArguments::compute_heap_alignment()); + assert(is_power_of_2(_conservative_max_heap_alignment), "Expected to be a power-of-2"); } jint Arguments::set_ergonomics_flags() { diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java index a8d5155584b..80962f0ffa6 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java @@ -192,6 +192,17 @@ public class TestRegionSizeArgs { output.shouldHaveExitValue(0); } + // This used to assert that _conservative_max_heap_alignment is not a power-of-2. + { + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", + "-XX:+UseShenandoahGC", + "-Xms100m", + "-Xmx1g", + "-XX:ShenandoahMaxRegionSize=33m", + "-version"); + output.shouldHaveExitValue(0); + } + } private static void testMaxRegionSize() throws Exception { From ac046628edaee66d1469c49864b70bdefee6570e Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 26 Nov 2025 10:06:51 +0000 Subject: [PATCH 03/81] 8372336: javac fails with an exception when a class is missing while evaluating conditional expression Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Resolve.java | 7 +- .../tools/javac/recovery/AttrRecovery.java | 103 +++++++++++++++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index eea766f57c1..07f2a742bcb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -2810,7 +2810,12 @@ public class Resolve { Symbol resolveQualifiedMethod(DiagnosticPosition pos, Env env, Symbol location, Type site, Name name, List argtypes, List typeargtypes) { - return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); + try { + return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); + } catch (CompletionFailure cf) { + chk.completionError(pos, cf); + return methodNotFound.access(name, site.tsym); + } } private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext, DiagnosticPosition pos, Env env, diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index f8d02d0ddf1..9a37ce60654 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 + * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -32,11 +32,14 @@ * @run main AttrRecovery */ +import com.sun.source.tree.MemberReferenceTree; +import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; +import java.nio.file.Files; import java.nio.file.Path; import java.util.IdentityHashMap; import java.util.List; @@ -394,4 +397,102 @@ public class AttrRecovery extends TestRunner { error("Expected: " + expected + ", but got: " + actual); } } + + @Test //JDK-8372336 + public void testCompletionFailureNoBreakInvocation() throws Exception { + Path curPath = Path.of("."); + Path lib = curPath.resolve("lib"); + Path classes = lib.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .outdir(classes) + .sources(""" + package test; + public class Intermediate extends Base {} + """, + """ + package test; + public class Base { + public int get() { + return -1; + } + } + """) + .run() + .writeAll(); + + Files.delete(classes.resolve("test").resolve("Base.class")); + + record TestCase(String code, String... expectedErrors) {} + TestCase[] testCases = new TestCase[] { + new TestCase(""" + package test; + public class Test { + private void test(Intermediate i) { + int j = i != null ? i.get() : -1; + } + } + """, + "Test.java:4:30: compiler.err.cant.access: test.Base, (compiler.misc.class.file.not.found: test.Base)", + "1 error"), + new TestCase(""" + package test; + public class Test { + private void test(Intermediate i) { + i.get(); + } + } + """, + "Test.java:4:10: compiler.err.cant.access: test.Base, (compiler.misc.class.file.not.found: test.Base)", + "1 error") + }; + + for (TestCase tc : testCases) { + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev") + .classpath(classes) + .sources(tc.code()) + .outdir(curPath) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + @Override + public Void visitMethodInvocation(MethodInvocationTree node, Void p) { + if (!node.toString().contains("super")) { + verifyElement(); + } + return super.visitMethodInvocation(node, p); + } + @Override + public Void visitMemberReference(MemberReferenceTree node, Void p) { + verifyElement(); + return super.visitMemberReference(node, p); + } + private void verifyElement() { + Element el = trees.getElement(getCurrentPath()); + if (!el.getSimpleName().contentEquals("get")) { + error("Expected good Element, but got: " + el); + } + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of(tc.expectedErrors); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + } } From 4ae2f31f3d2027daa0a5ccba6180e7bb27413aa5 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 26 Nov 2025 12:49:42 +0000 Subject: [PATCH 04/81] 8371626: [linux] use icf=all for linking libraries Reviewed-by: goetz, erikj --- make/autoconf/flags-ldflags.m4 | 7 +++++++ make/autoconf/toolchain.m4 | 1 + 2 files changed, 8 insertions(+) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index ad131b20e27..572790b567b 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -50,7 +50,14 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # add -z,relro (mark relocations read only) for all libs # add -z,now ("full relro" - more of the Global Offset Table GOT is marked read only) # add --no-as-needed to disable default --as-needed link flag on some GCC toolchains + # add --icf=all (Identical Code Folding — merges identical functions) BASIC_LDFLAGS="-Wl,-z,defs -Wl,-z,relro -Wl,-z,now -Wl,--no-as-needed -Wl,--exclude-libs,ALL" + if test "x$LINKER_TYPE" = "xgold"; then + if test x$DEBUG_LEVEL = xrelease; then + BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--icf=all" + fi + fi + # Linux : remove unused code+data in link step if test "x$ENABLE_LINKTIME_GC" = xtrue; then if test "x$OPENJDK_TARGET_CPU" = xs390x; then diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 4662c62d901..15210efe4a7 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -516,6 +516,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_LD_VERSION], if [ [[ "$LINKER_VERSION_STRING" == *gold* ]] ]; then [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*) .*/\1/'` ] + LINKER_TYPE=gold else [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*/\1/'` ] From c146805da5708b479bf8dd0180acd06657b72788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Wed, 26 Nov 2025 13:05:41 +0000 Subject: [PATCH 05/81] 8368551: Core dump warning may be confusing Reviewed-by: stuefe, dholmes --- src/hotspot/os/linux/os_linux.cpp | 2 +- src/hotspot/os/posix/os_posix.cpp | 39 ++++++++++++++----- .../TestCrashOnOutOfMemoryError.java | 6 +-- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 30033903ca3..efeeec6f484 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -5163,7 +5163,7 @@ int os::get_core_path(char* buffer, size_t bufferSize) { if (core_pattern[0] == '|') { written = jio_snprintf(buffer, bufferSize, - "\"%s\" (or dumping to %s/core.%d)", + "\"%s\" (alternatively, falling back to %s/core.%d)", &core_pattern[1], p, current_process_id()); } else if (pid_pos != nullptr) { *pid_pos = '\0'; diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 1a04cbba0de..8f1f07dd055 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -108,41 +108,60 @@ size_t os::_os_min_stack_allowed = PTHREAD_STACK_MIN; // Check core dump limit and report possible place where core can be found void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) { + stringStream buf(buffer, bufferSize); if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) { - jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line"); - VMError::record_coredump_status(buffer, false); + buf.print("CreateCoredumpOnCrash is disabled from command line"); + VMError::record_coredump_status(buf.freeze(), false); } else { struct rlimit rlim; bool success = true; bool warn = true; char core_path[PATH_MAX]; if (get_core_path(core_path, PATH_MAX) <= 0) { - jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id()); + // In the warning message, let the user know. + if (check_only) { + buf.print("the core path couldn't be determined. It commonly defaults to "); + } + buf.print("core.%d%s", current_process_id(), check_only ? "" : " (may not exist)"); #ifdef LINUX } else if (core_path[0] == '"') { // redirect to user process - jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path); + if (check_only) { + buf.print("core dumps may be further processed by the following: "); + } else { + buf.print("Determined by the following: "); + } + buf.print("%s", core_path); #endif } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) { - jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path); + if (check_only) { + buf.print("the rlimit couldn't be determined. If resource limits permit, the core dump will be located at "); + } + buf.print("%s%s", core_path, check_only ? "" : " (may not exist)"); } else { switch(rlim.rlim_cur) { case RLIM_INFINITY: - jio_snprintf(buffer, bufferSize, "%s", core_path); + buf.print("%s", core_path); warn = false; break; case 0: - jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again"); + buf.print("%s dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again", check_only ? "core" : "Core"); success = false; break; default: - jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K); + if (check_only) { + buf.print("core dumps are constrained "); + } else { + buf.print( "%s ", core_path); + } + buf.print( "(max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", uint64_t(rlim.rlim_cur) / K); break; } } + const char* result = buf.freeze(); if (!check_only) { - VMError::record_coredump_status(buffer, success); + VMError::record_coredump_status(result, success); } else if (warn) { - warning("CreateCoredumpOnCrash specified, but %s", buffer); + warning("CreateCoredumpOnCrash specified, but %s", result); } } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java index 0be39d22ebe..26d1f726feb 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,8 +72,8 @@ public class TestCrashOnOutOfMemoryError { # # JRE version: OpenJDK Runtime Environment (9.0) (build 1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00) # Java VM: OpenJDK 64-Bit Server VM (1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00, mixed mode, tiered, compressed oops, serial gc, linux-amd64) - # Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %P" (or dumping to - /home/cheleswer/Desktop/core.6212) + # Core dump will be written. Default location: Determined by the following: + "/usr/share/apport/apport %p %s %c %P" (alternatively, falling back to /home/cheleswer/Desktop/core.6212) # # An error report file with more information is saved as: # /home/cheleswer/Desktop/hs_err_pid6212.log From 74354f23dbb0fc852d216c8f1d3e5f80d406cfc6 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 26 Nov 2025 13:25:57 +0000 Subject: [PATCH 06/81] 8372585: TestVerifyLoopOptimizationsHitsMemLimit fails with product builds Reviewed-by: rcastanedalo, thartmann --- .../loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java index fbe69ad0e04..90a8287004f 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java @@ -45,7 +45,8 @@ package compiler.loopopts; * -XX:-TieredCompilation -Xcomp -XX:PerMethodTrapLimit=0 * -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations -XX:-StressDuplicateBackedge * compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit - * @run main/othervm -XX:-StressDuplicateBackedge compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-StressDuplicateBackedge + * compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit */ public class TestVerifyLoopOptimizationsHitsMemLimit { From 85d4f551b1f82f1b43155a4ac3c5026ac580410e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 26 Nov 2025 13:36:58 +0000 Subject: [PATCH 07/81] 8372055: Fragment link tag does not work in package info Reviewed-by: liach --- .../com/sun/tools/javac/api/JavacTrees.java | 18 ++- .../formats/html/taglets/LinkTaglet.java | 5 + .../jdk/javadoc/internal/doclint/Checker.java | 15 +- .../testSeeLinkAnchor/TestSeeLinkAnchor.java | 139 ++++++++++++++++-- 4 files changed, 156 insertions(+), 21 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index f933ef36565..22ee2393a02 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -413,7 +413,18 @@ public class JavacTrees extends DocTrees { } if (ref.qualifierExpression == null) { - tsym = env.enclClass.sym; + // Resolve target for unqualified reference based on declaring element + tsym = switch (path.getLeaf().getKind()) { + case PACKAGE -> env.toplevel.packge; + case MODULE -> env.toplevel.modle; + case COMPILATION_UNIT -> + // Treat unqualified reference in legacy package.html as package reference. + // Unqualified references in doc-files only need to work locally, so null is fine. + path.getCompilationUnit().getSourceFile().isNameCompatible("package", JavaFileObject.Kind.HTML) + ? env.toplevel.packge + : null; + default -> env.enclClass.sym; // Class or class member reference + }; memberName = (Name) ref.memberName; } else { // Check if qualifierExpression is a type or package, using the methods javac provides. @@ -470,8 +481,11 @@ public class JavacTrees extends DocTrees { } } - if (memberName == null) + if (memberName == null) { return tsym; + } else if (tsym == null || tsym.getKind() == ElementKind.PACKAGE || tsym.getKind() == ElementKind.MODULE) { + return null; // Non-null member name in non-class context + } if (tsym.type.isPrimitive()) { return null; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java index 914f70ced47..62b003afd96 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java @@ -50,6 +50,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -159,6 +160,10 @@ public class LinkTaglet extends BaseTaglet { Optional.of(refSignature)); } refFragment = refFragment.substring(1); + if (ref == null && refSignature.startsWith("##")) { + // Unqualified local anchor link in doc-file + return htmlWriter.links.createLink(HtmlId.of(refFragment), labelContent); + } } if (refClass == null) { ModuleElement refModule = ch.getReferencedModule(ref); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index 3669c800a8e..43405c3ebb0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -1004,12 +1004,15 @@ public class Checker extends DocTreePathScanner { @Override @DefinedBy(Api.COMPILER_TREE) public Void visitReference(ReferenceTree tree, Void ignore) { - Element e = env.trees.getElement(getCurrentPath()); - if (e == null) { - reportBadReference(tree); - } else if ((inLink || inSee) - && e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED) { - reportBadReference(tree); + // Exclude same-file anchor links from reference checks + if (!tree.getSignature().startsWith("##")) { + Element e = env.trees.getElement(getCurrentPath()); + if (e == null) { + reportBadReference(tree); + } else if ((inLink || inSee) + && e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED) { + reportBadReference(tree); + } } return super.visitReference(tree, ignore); } diff --git a/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java b/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java index 626e4870401..f59de2e5e70 100644 --- a/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java +++ b/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,11 @@ public class TestSeeLinkAnchor extends JavadocTester { """ Link to heading in package p2""", """ - Plain link to sub heading above""", + Plain link to heading in Class2""", + """ +
  • unqualified link to heading above
  • +
  • qualified link to heading above
  • + """, """
  • See main heading in p2.Class2
  • See heading in p2
  • @@ -89,13 +93,19 @@ public class TestSeeLinkAnchor extends JavadocTester { Plain link to Class1."""); checkOrder("p2/package-summary.html", """ - See sub heading in p2.Class2"""); +
  • See sub heading in p2.Class2
  • +
  • local qualified link
  • +
  • local unqualified link
  • + """); checkOrder("p2/doc-files/file.html", """ Plain link to heading in p1.ClassA.""", """ - See main heading in p2.ClassB"""); +
  • See main heading in p2.ClassB
  • +
  • package link
  • +
  • local anchor
  • + """); } @Test @@ -112,12 +122,57 @@ public class TestSeeLinkAnchor extends JavadocTester { checkOrder("m1/module-summary.html", """ See main heading in Class2"""); + checkOrder("m1/com/m1/package-summary.html", + """ +
    Link to local anchor. + """, + """ + package-anchor
    + """, + """ + + """); checkOrder("m1/com/m1/Class1.html", """ sub heading in Class2.""", """ -
  • See main heading in Class2
  • -
  • See heading in module m1
  • +

    More links: +

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

      Class1 Main

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

      Class1 Sub

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

      Package p2

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

      Package p2 HTML File

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

      More links: + *

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

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

      Package com.m2

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

      Module m2 HTML File

      + +

      Module m2 HTML File

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

    test()

    ", "

    testNoPreviewInSig()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    What the JDBC 4.3 API Includes

    - * The JDBC 4.3 API includes both + *

    What the JDBC 4.5 API Includes

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

    Versions

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

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

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

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

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

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

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

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

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

    Custom Mapping of UDTs

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

    Package Specification

    * * * *

    Related Documentation

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

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

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

    The {@code link} parameter locates the directory entry to create. @@ -1007,8 +1011,8 @@ public final class Files { * if the implementation does not support adding an existing file * to a directory * @throws FileAlreadyExistsException - * if the entry could not otherwise be created because a file of - * that name already exists (optional specific exception) + * if {@code link} locates an existing file + * (optional specific exception) * @throws IOException * if an I/O error occurs */ @@ -2711,7 +2715,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) * @@ -2754,7 +2758,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) * @@ -3161,7 +3165,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) */ @@ -3222,7 +3226,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) */ From 6cb1c8f9cfcb797af788ca8fb490f388cc68f525 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Mon, 1 Dec 2025 17:29:15 +0000 Subject: [PATCH 63/81] 8371864: GaloisCounterMode.implGCMCrypt0 AVX512/AVX2 intrinsics stubs cause AES-GCM encryption failure for certain payload sizes Co-authored-by: Thomas Holenstein Co-authored-by: Lukas Zobernig Reviewed-by: shade, sviswanathan --- .../cpu/x86/stubGenerator_x86_64_aes.cpp | 7 +- .../Cipher/AES/TestGCMSplitBound.java | 145 ++++++++++++++++++ 2 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index f0726ded7e5..1e728ffa279 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -3524,10 +3524,10 @@ void StubGenerator::aesgcm_avx512(Register in, Register len, Register ct, Regist false, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32); ghash16_avx512(false, true, false, false, true, in, pos, avx512_subkeyHtbl, AAD_HASHx, SHUF_MASK, stack_offset, 16 * 16, 0, HashKey_16); + __ addl(pos, 16 * 16); __ bind(MESG_BELOW_32_BLKS); __ subl(len, 16 * 16); - __ addl(pos, 16 * 16); gcm_enc_dec_last_avx512(len, in, pos, AAD_HASHx, SHUF_MASK, avx512_subkeyHtbl, ghashin_offset, HashKey_16, true, true); __ bind(GHASH_DONE); @@ -4016,13 +4016,15 @@ void StubGenerator::aesgcm_avx2(Register in, Register len, Register ct, Register const Register rounds = r10; const XMMRegister ctr_blockx = xmm9; const XMMRegister aad_hashx = xmm8; - Label encrypt_done, encrypt_by_8_new, encrypt_by_8; + Label encrypt_done, encrypt_by_8_new, encrypt_by_8, exit; //This routine should be called only for message sizes of 128 bytes or more. //Macro flow: //process 8 16 byte blocks in initial_num_blocks. //process 8 16 byte blocks at a time until all are done 'encrypt_by_8_new followed by ghash_last_8' __ xorl(pos, pos); + __ cmpl(len, 128); + __ jcc(Assembler::less, exit); //Generate 8 constants for htbl generateHtbl_8_block_avx2(subkeyHtbl); @@ -4090,6 +4092,7 @@ void StubGenerator::aesgcm_avx2(Register in, Register len, Register ct, Register __ vpxor(xmm0, xmm0, xmm0, Assembler::AVX_128bit); __ vpxor(xmm13, xmm13, xmm13, Assembler::AVX_128bit); + __ bind(exit); } #undef __ diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java new file mode 100644 index 00000000000..133e68b344f --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2025, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8371864 + * @run main/othervm/timeout=600 TestGCMSplitBound + * @requires (os.simpleArch == "x64" & (vm.cpu.features ~= ".*avx2.*" | + * vm.cpu.features ~= ".*avx512.*")) + * @summary Test GaloisCounterMode.implGCMCrypt0 AVX512/AVX2 intrinsics. + */ + +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.time.Duration; +import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class TestGCMSplitBound { + + static final SecureRandom SECURE_RANDOM = newDefaultSecureRandom(); + + private static SecureRandom newDefaultSecureRandom() { + SecureRandom retval = new SecureRandom(); + retval.nextLong(); // force seeding + return retval; + } + + private static byte[] randBytes(int size) { + byte[] rand = new byte[size]; + SECURE_RANDOM.nextBytes(rand); + return rand; + } + + private static final int IV_SIZE_IN_BYTES = 12; + private static final int TAG_SIZE_IN_BYTES = 16; + + private Cipher getCipher(final byte[] key, final byte[] aad, + final byte[] nonce, int mode) + throws Exception { + SecretKey keySpec = new SecretKeySpec(key, "AES"); + AlgorithmParameterSpec params = + new GCMParameterSpec(8 * TAG_SIZE_IN_BYTES, nonce, 0, nonce.length); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(mode, keySpec, params); + if (aad != null && aad.length != 0) { + cipher.updateAAD(aad); + } + return cipher; + } + + private byte[] gcmEncrypt(final byte[] key, final byte[] plaintext, + final byte[] aad) + throws Exception { + byte[] nonce = randBytes(IV_SIZE_IN_BYTES); + Cipher cipher = getCipher(key, aad, nonce, Cipher.ENCRYPT_MODE); + int outputSize = cipher.getOutputSize(plaintext.length); + int len = IV_SIZE_IN_BYTES + outputSize; + byte[] output = new byte[len]; + System.arraycopy(nonce, 0, output, 0, IV_SIZE_IN_BYTES); + cipher.doFinal(plaintext, 0, plaintext.length, output, + IV_SIZE_IN_BYTES); + return output; + } + + private byte[] gcmDecrypt(final byte[] key, final byte[] ciphertext, + final byte[] aad) + throws Exception { + byte[] nonce = new byte[IV_SIZE_IN_BYTES]; + System.arraycopy(ciphertext, 0, nonce, 0, IV_SIZE_IN_BYTES); + Cipher cipher = getCipher(key, aad, nonce, Cipher.DECRYPT_MODE); + return cipher.doFinal(ciphertext, IV_SIZE_IN_BYTES, + ciphertext.length - IV_SIZE_IN_BYTES); + } + + // x86-64 parallel intrinsic data size + private static final int PARALLEL_LEN = 512; + // max data size for x86-64 intrinsic + private static final int SPLIT_LEN = 1048576; // 1MB + + private void encryptAndDecrypt(byte[] key, byte[] aad, byte[] message, + int messageSize) + throws Exception { + byte[] ciphertext = gcmEncrypt(key, message, aad); + byte[] decrypted = gcmDecrypt(key, ciphertext, aad); + if (ciphertext == null) { + throw new RuntimeException("ciphertext is null"); + } + if (Arrays.compare(decrypted, 0, messageSize, + message, 0, messageSize) != 0) { + throw new RuntimeException( + "Decrypted message is different from the original message"); + } + } + + private void run() throws Exception { + byte[] aad = randBytes(20); + byte[] key = randBytes(16); + // Force JIT. + for (int i = 0; i < 100000; i++) { + byte[] message = randBytes(PARALLEL_LEN); + encryptAndDecrypt(key, aad, message, PARALLEL_LEN); + } + for (int messageSize = SPLIT_LEN - 300; messageSize <= SPLIT_LEN + 300; + messageSize++) { + byte[] message = randBytes(messageSize); + try { + encryptAndDecrypt(key, aad, message, messageSize); + } catch (Exception e) { + throw new RuntimeException("Failed for messageSize " + + Integer.toHexString(messageSize), e); + } + } + } + + public static void main(String[] args) throws Exception { + TestGCMSplitBound test = new TestGCMSplitBound(); + for (int i = 0; i < 3; i++) { + test.run(); + } + } +} From 45c0600d3abfa4bcd0338840523c0df69283afe2 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 1 Dec 2025 18:17:00 +0000 Subject: [PATCH 64/81] 8372609: Bug4944439 does not enforce locale correctly Reviewed-by: liach, jpai --- .../text/Format/NumberFormat/Bug4944439.java | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/test/jdk/java/text/Format/NumberFormat/Bug4944439.java b/test/jdk/java/text/Format/NumberFormat/Bug4944439.java index 561052e9a95..a13a36733e2 100644 --- a/test/jdk/java/text/Format/NumberFormat/Bug4944439.java +++ b/test/jdk/java/text/Format/NumberFormat/Bug4944439.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,22 +23,19 @@ /* * @test - * @bug 4944439 + * @bug 4944439 8372609 * @summary Confirm that numbers where all digits after the decimal separator are 0 * and which are between Long.MIN_VALUE and Long.MAX_VALUE are returned * as Long(not double). * @run junit Bug4944439 */ -import java.text.DecimalFormat; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Locale; import java.util.stream.Stream; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -47,21 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertInstanceOf; public class Bug4944439 { - // Save JVM default locale - private static final Locale savedLocale = Locale.getDefault(); - private static final DecimalFormat df = new DecimalFormat(); - - // Set JVM default locale to US for testing - @BeforeAll - static void initAll() { - Locale.setDefault(Locale.US); - } - - // Restore JVM default locale - @AfterAll - static void tearDownAll() { - Locale.setDefault(savedLocale); - } + private static final NumberFormat df = NumberFormat.getInstance(Locale.US); // Check return type and value returned by DecimalFormat.parse() for longs @ParameterizedTest From 79e99bb0778608733a677821a0bb35041e9fb939 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Mon, 1 Dec 2025 18:30:38 +0000 Subject: [PATCH 65/81] 8372566: Genshen: crash at ShenandoahScanRemembered::process_clusters after JDK-8371667 Reviewed-by: wkemper, kdnilsen, ysr --- src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 22a59b5ac18..5c4d10ca8a5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1015,7 +1015,7 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // Record the plab configuration for this result and register the object. if (result != nullptr && req.is_old()) { old_generation()->configure_plab_for_current_thread(req); - if (req.type() == ShenandoahAllocRequest::_alloc_shared_gc) { + if (!req.is_lab_alloc()) { // Register the newly allocated object while we're holding the global lock since there's no synchronization // built in to the implementation of register_object(). There are potential races when multiple independent // threads are allocating objects, some of which might span the same card region. For example, consider From 84ffe87260753973835ea6b88443e28bcaf0122f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 2 Dec 2025 08:38:22 +0000 Subject: [PATCH 66/81] 8342175: MemoryEaterMT fails intermittently with ExceptionInInitializerError Reviewed-by: lmesnik, aboldtch --- test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java index 6b33783306f..15bbc9eb964 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java @@ -48,6 +48,9 @@ public class GC extends nsk.share.test.Tests { public GCTestRunner(Test test, String[] args) { super(test, args); + // GC tests often run at the brink of OOME, make sure + // LocalRandom is loaded, initialized, and has enough memory. + LocalRandom.init(); } private GCParams getGCParams(String[] args) { From 7278d2e8e5835f090672f7625d391a1b4c1a6626 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Tue, 2 Dec 2025 09:39:29 +0000 Subject: [PATCH 67/81] 8372258: Improve TypeVariable support Reviewed-by: liach --- .../java/lang/reflect/TypeVariable.java | 4 +- .../reflectiveObjects/TypeVariableImpl.java | 16 +++-- ...otectInnerStateOfTypeVariableImplTest.java | 70 +++++++++++++++++++ 3 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java diff --git a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java index 01746e34385..85e99fd3f92 100644 --- a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java +++ b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,7 +72,7 @@ public interface TypeVariable extends Type, Annota Type[] getBounds(); /** - * Returns the {@code GenericDeclaration} object representing the + * Returns a {@code GenericDeclaration} object representing the * generic declaration declared for this type variable. * * @return the generic declaration declared for this type variable. diff --git a/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java b/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java index 75750d38f2f..560e9a4f7c9 100644 --- a/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java +++ b/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ import java.lang.reflect.TypeVariable; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; + +import jdk.internal.reflect.ReflectionFactory; import sun.reflect.annotation.AnnotationSupport; import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.annotation.AnnotationType; @@ -125,18 +127,24 @@ public class TypeVariableImpl } /** - * Returns the {@code GenericDeclaration} object representing the + * Returns a {@code GenericDeclaration} object representing the * generic declaration that declared this type variable. * - * @return the generic declaration that declared this type variable. + * @return a generic declaration that declared this type variable. * * @since 1.5 */ + @SuppressWarnings("unchecked") public D getGenericDeclaration() { assert genericDeclaration instanceof Class || genericDeclaration instanceof Method || genericDeclaration instanceof Constructor : "Unexpected kind of GenericDeclaration"; - return genericDeclaration; + // If the `genericDeclaration` instance is mutable, we need to make a copy. + return switch (genericDeclaration) { + case Method method -> (D) ReflectionFactory.getReflectionFactory().copyMethod(method); + case Constructor ctor -> (D) ReflectionFactory.getReflectionFactory().copyConstructor(ctor); + default -> genericDeclaration; + }; } diff --git a/test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java b/test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java new file mode 100644 index 00000000000..05a2a8e84de --- /dev/null +++ b/test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8372258 + * @summary Test if a copy of the internal state is provided + * @run junit ProtectInnerStateOfTypeVariableImplTest + */ + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.TypeVariable; + +import static org.junit.jupiter.api.Assertions.*; + +final class ProtectInnerStateOfTypeVariableImplTest { + + static final class Foo { + public Foo() { + } + + X x() { + return null; + } + } + + @Test + void testMethod() throws NoSuchMethodException { + Method method = Foo.class.getDeclaredMethod("x"); + TypeVariable tv = method.getTypeParameters()[0]; + + Method gd = tv.getGenericDeclaration(); + Method gd2 = tv.getGenericDeclaration(); + assertNotSame(gd, gd2); + } + + @Test + void testConstructor() throws NoSuchMethodException { + Constructor ctor = Foo.class.getConstructor(); + TypeVariable> tv = ctor.getTypeParameters()[0]; + + Constructor gd = tv.getGenericDeclaration(); + Constructor gd2 = tv.getGenericDeclaration(); + assertNotSame(gd, gd2); + } + +} From f636fcadd72eba7aefbf3f89777c14b3e3f19fb8 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 2 Dec 2025 10:58:44 +0000 Subject: [PATCH 68/81] 8372645: ParallelGC: Remove race between allocation and expansion before is_init_completed Reviewed-by: ayang, sjohanss, eosterlund --- .../gc/parallel/parallelScavengeHeap.cpp | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 3a13d0d0535..4d291120e4a 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -307,9 +307,13 @@ HeapWord* ParallelScavengeHeap::mem_allocate_cas_noexpand(size_t size, bool is_t HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { for (uint loop_count = 0; /* empty */; ++loop_count) { - HeapWord* result = mem_allocate_cas_noexpand(size, is_tlab); - if (result != nullptr) { - return result; + HeapWord* result; + { + ConditionalMutexLocker locker(Heap_lock, !is_init_completed()); + result = mem_allocate_cas_noexpand(size, is_tlab); + if (result != nullptr) { + return result; + } } // Read total_collections() under the lock so that multiple @@ -326,10 +330,15 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { } if (!is_init_completed()) { - // Can't do GC; try heap expansion to satisfy the request. - result = expand_heap_and_allocate(size, is_tlab); - if (result != nullptr) { - return result; + // Double checked locking, this ensure that is_init_completed() does not + // transition while expanding the heap. + MonitorLocker ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag); + if (!is_init_completed()) { + // Can't do GC; try heap expansion to satisfy the request. + result = expand_heap_and_allocate(size, is_tlab); + if (result != nullptr) { + return result; + } } } From e27abe8a979880f308c69ea53319565dcd2142b6 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 2 Dec 2025 10:59:04 +0000 Subject: [PATCH 69/81] 8372540: SerialGC: Remove race between allocation and expansion before is_init_completed Reviewed-by: ayang, sjohanss, eosterlund --- src/hotspot/share/gc/serial/serialHeap.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 03ad1282f5f..faef3b89125 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -304,9 +304,12 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { HeapWord* result = nullptr; for (uint try_count = 1; /* break */; try_count++) { - result = mem_allocate_cas_noexpand(size, is_tlab); - if (result != nullptr) { - break; + { + ConditionalMutexLocker locker(Heap_lock, !is_init_completed()); + result = mem_allocate_cas_noexpand(size, is_tlab); + if (result != nullptr) { + break; + } } uint gc_count_before; // Read inside the Heap_lock locked region. { @@ -320,10 +323,15 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { } if (!is_init_completed()) { - // Can't do GC; try heap expansion to satisfy the request. - result = expand_heap_and_allocate(size, is_tlab); - if (result != nullptr) { - return result; + // Double checked locking, this ensure that is_init_completed() does not + // transition while expanding the heap. + MonitorLocker ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag); + if (!is_init_completed()) { + // Can't do GC; try heap expansion to satisfy the request. + result = expand_heap_and_allocate(size, is_tlab); + if (result != nullptr) { + return result; + } } } From 3f046f6dec72392d0693655c0f0ef9189529ce45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Tue, 2 Dec 2025 11:56:22 +0000 Subject: [PATCH 70/81] 8372747: G1: Conservative heap alignment does not account for card table constraint Reviewed-by: mdoerr, stefank, tschatzl, sjohanss --- src/hotspot/share/gc/g1/g1Arguments.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index 5cbafd2ae94..2be0e008c22 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -77,10 +77,11 @@ void G1Arguments::initialize_alignments() { } size_t G1Arguments::conservative_max_heap_alignment() { - if (FLAG_IS_DEFAULT(G1HeapRegionSize)) { - return G1HeapRegion::max_ergonomics_size(); - } - return G1HeapRegion::max_region_size(); + const size_t region_size = FLAG_IS_DEFAULT(G1HeapRegionSize) + ? G1HeapRegion::max_ergonomics_size() + : G1HeapRegion::max_region_size(); + + return calculate_heap_alignment(region_size); } void G1Arguments::initialize_verification_types() { From fd7283be47489d3297aac6ecf6658ee9500b2891 Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Tue, 2 Dec 2025 12:05:31 +0000 Subject: [PATCH 71/81] 8360046: Scalability issue when submitting virtual threads with almost empty tasks Reviewed-by: vklang --- .../classes/java/lang/VirtualThread.java | 18 +- .../java/util/concurrent/ForkJoinPool.java | 632 +++++++++--------- .../util/concurrent/forkjoin/Starvation.java | 20 +- 3 files changed, 341 insertions(+), 329 deletions(-) diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 6064b46d50a..51543f835c1 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -315,6 +315,18 @@ final class VirtualThread extends BaseVirtualThread { } } + /** + * Submits the given task to the given executor. If the scheduler is a + * ForkJoinPool then the task is first adapted to a ForkJoinTask. + */ + private void submit(Executor executor, Runnable task) { + if (executor instanceof ForkJoinPool pool) { + pool.submit(ForkJoinTask.adapt(task)); + } else { + executor.execute(task); + } + } + /** * Submits the runContinuation task to the scheduler. For the default scheduler, * and calling it on a worker thread, the task will be pushed to the local queue, @@ -335,12 +347,12 @@ final class VirtualThread extends BaseVirtualThread { if (currentThread().isVirtual()) { Continuation.pin(); try { - scheduler.execute(runContinuation); + submit(scheduler, runContinuation); } finally { Continuation.unpin(); } } else { - scheduler.execute(runContinuation); + submit(scheduler, runContinuation); } done = true; } catch (RejectedExecutionException ree) { @@ -1536,4 +1548,4 @@ final class VirtualThread extends BaseVirtualThread { unblocker.setDaemon(true); unblocker.start(); } -} \ No newline at end of file +} diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 1f2c8d2ffa6..f289186e0ad 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -560,89 +560,70 @@ public class ForkJoinPool extends AbstractExecutorService * access (which is usually needed anyway). * * Signalling. Signals (in signalWork) cause new or reactivated - * workers to scan for tasks. Method signalWork and its callers - * try to approximate the unattainable goal of having the right - * number of workers activated for the tasks at hand, but must err - * on the side of too many workers vs too few to avoid stalls: + * workers to scan for tasks. SignalWork is invoked in two cases: + * (1) When a task is pushed onto an empty queue, and (2) When a + * worker takes a top-level task from a queue that has additional + * tasks. Together, these suffice in O(log(#threads)) steps to + * fully activate with at least enough workers, and ideally no + * more than required. This ideal is unobtainable: Callers do not + * know whether another worker will finish its current task and + * poll for others without need of a signal (which is otherwise an + * advantage of work-stealing vs other schemes), and also must + * conservatively estimate the triggering conditions of emptiness + * or non-emptiness; all of which usually cause more activations + * than necessary (see below). (Method signalWork is also used as + * failsafe in case of Thread failures in deregisterWorker, to + * activate or create a new worker to replace them). * - * * If computations are purely tree structured, it suffices for - * every worker to activate another when it pushes a task into - * an empty queue, resulting in O(log(#threads)) steps to full - * activation. Emptiness must be conservatively approximated, - * which may result in unnecessary signals. Also, to reduce - * resource usages in some cases, at the expense of slower - * startup in others, activation of an idle thread is preferred - * over creating a new one, here and elsewhere. - * - * * At the other extreme, if "flat" tasks (those that do not in - * turn generate others) come in serially from only a single - * producer, each worker taking a task from a queue should - * propagate a signal if there are more tasks in that - * queue. This is equivalent to, but generally faster than, - * arranging the stealer take multiple tasks, re-pushing one or - * more on its own queue, and signalling (because its queue is - * empty), also resulting in logarithmic full activation - * time. If tasks do not not engage in unbounded loops based on - * the actions of other workers with unknown dependencies loop, - * this form of proagation can be limited to one signal per - * activation (phase change). We distinguish the cases by - * further signalling only if the task is an InterruptibleTask - * (see below), which are the only supported forms of task that - * may do so. - * - * * Because we don't know about usage patterns (or most commonly, - * mixtures), we use both approaches, which present even more - * opportunities to over-signal. (Failure to distinguish these - * cases in terms of submission methods was arguably an early - * design mistake.) Note that in either of these contexts, - * signals may be (and often are) unnecessary because active - * workers continue scanning after running tasks without the - * need to be signalled (which is one reason work stealing is - * often faster than alternatives), so additional workers - * aren't needed. - * - * * For rapidly branching tasks that require full pool resources, - * oversignalling is OK, because signalWork will soon have no - * more workers to create or reactivate. But for others (mainly - * externally submitted tasks), overprovisioning may cause very - * noticeable slowdowns due to contention and resource - * wastage. We reduce impact by deactivating workers when - * queues don't have accessible tasks, but reactivating and - * rescanning if other tasks remain. - * - * * Despite these, signal contention and overhead effects still - * occur during ramp-up and ramp-down of small computations. + * Top-Level scheduling + * ==================== * * Scanning. Method runWorker performs top-level scanning for (and * execution of) tasks by polling a pseudo-random permutation of * the array (by starting at a given index, and using a constant * cyclically exhaustive stride.) It uses the same basic polling * method as WorkQueue.poll(), but restarts with a different - * permutation on each invocation. The pseudorandom generator - * need not have high-quality statistical properties in the long + * permutation on each rescan. The pseudorandom generator need + * not have high-quality statistical properties in the long * term. We use Marsaglia XorShifts, seeded with the Weyl sequence - * from ThreadLocalRandom probes, which are cheap and - * suffice. Each queue's polling attempts to avoid becoming stuck - * when other scanners/pollers stall. Scans do not otherwise - * explicitly take into account core affinities, loads, cache - * localities, etc, However, they do exploit temporal locality - * (which usually approximates these) by preferring to re-poll - * from the same queue after a successful poll before trying - * others, which also reduces bookkeeping, cache traffic, and - * scanning overhead. But it also reduces fairness, which is - * partially counteracted by giving up on detected interference - * (which also reduces contention when too many workers try to - * take small tasks from the same queue). + * from ThreadLocalRandom probes, which are cheap and suffice. * * Deactivation. When no tasks are found by a worker in runWorker, - * it tries to deactivate()), giving up (and rescanning) on "ctl" - * contention. To avoid missed signals during deactivation, the - * method rescans and reactivates if there may have been a missed - * signal during deactivation. To reduce false-alarm reactivations - * while doing so, we scan multiple times (analogously to method - * quiescent()) before trying to reactivate. Because idle workers - * are often not yet blocked (parked), we use a WorkQueue field to - * advertise that a waiter actually needs unparking upon signal. + * it invokes deactivate, that first deactivates (to an IDLE + * phase). Avoiding missed signals during deactivation requires a + * (conservative) rescan, reactivating if there may be tasks to + * poll. Because idle workers are often not yet blocked (parked), + * we use a WorkQueue field to advertise that a waiter actually + * needs unparking upon signal. + * + * When tasks are constructed as (recursive) DAGs, top-level + * scanning is usually infrequent, and doesn't encounter most + * of the following problems addressed by runWorker and awaitWork: + * + * Locality. Polls are organized into "runs", continuing until + * empty or contended, while also minimizing interference by + * postponing bookeeping to ends of runs. This may reduce + * fairness. + * + * Contention. When many workers try to poll few queues, they + * often collide, generating CAS failures and disrupting locality + * of workers already running their tasks. This also leads to + * stalls when tasks cannot be taken because other workers have + * not finished poll operations, which is detected by reading + * ahead in queue arrays. In both cases, workers restart scans in a + * way that approximates randomized backoff. + * + * Oversignalling. When many short top-level tasks are present in + * a small number of queues, the above signalling strategy may + * activate many more workers than needed, worsening locality and + * contention problems, while also generating more global + * contention (field ctl is CASed on every activation and + * deactivation). We filter out (both in runWorker and + * signalWork) attempted signals that are surely not needed + * because the signalled tasks are already taken. + * + * Shutdown and Quiescence + * ======================= * * Quiescence. Workers scan looking for work, giving up when they * don't find any, without being sure that none are available. @@ -892,9 +873,7 @@ public class ForkJoinPool extends AbstractExecutorService * shutdown, runners are interrupted so they can cancel. Since * external joining callers never run these tasks, they must await * cancellation by others, which can occur along several different - * paths. The inability to rely on caller-runs may also require - * extra signalling (resulting in scanning and contention) so is - * done only conditionally in methods push and runworker. + * paths. * * Across these APIs, rules for reporting exceptions for tasks * with results accessed via join() differ from those via get(), @@ -961,9 +940,13 @@ public class ForkJoinPool extends AbstractExecutorService * less-contended applications. To help arrange this, some * non-reference fields are declared as "long" even when ints or * shorts would suffice. For class WorkQueue, an - * embedded @Contended region segregates fields most heavily - * updated by owners from those most commonly read by stealers or - * other management. + * embedded @Contended isolates the very busy top index, along + * with status and bookkeeping fields written (mostly) by owners, + * that otherwise interfere with reading array and base + * fields. There are other variables commonly contributing to + * false-sharing-related performance issues (including fields of + * class Thread), but we can't do much about this except try to + * minimize access. * * Initial sizing and resizing of WorkQueue arrays is an even more * delicate tradeoff because the best strategy systematically @@ -972,13 +955,11 @@ public class ForkJoinPool extends AbstractExecutorService * direct false-sharing and indirect cases due to GC bookkeeping * (cardmarks etc), and reduce the number of resizes, which are * not especially fast because they require atomic transfers. - * Currently, arrays for workers are initialized to be just large - * enough to avoid resizing in most tree-structured tasks, but - * larger for external queues where both false-sharing problems - * and the need for resizing are more common. (Maintenance note: - * any changes in fields, queues, or their uses, or JVM layout - * policies, must be accompanied by re-evaluation of these - * placement and sizing decisions.) + * Currently, arrays are initialized to be just large enough to + * avoid resizing in most tree-structured tasks, but grow rapidly + * until large. (Maintenance note: any changes in fields, queues, + * or their uses, or JVM layout policies, must be accompanied by + * re-evaluation of these placement and sizing decisions.) * * Style notes * =========== @@ -1061,17 +1042,11 @@ public class ForkJoinPool extends AbstractExecutorService static final int DEFAULT_COMMON_MAX_SPARES = 256; /** - * Initial capacity of work-stealing queue array for workers. + * Initial capacity of work-stealing queue array. * Must be a power of two, at least 2. See above. */ static final int INITIAL_QUEUE_CAPACITY = 1 << 6; - /** - * Initial capacity of work-stealing queue array for external queues. - * Must be a power of two, at least 2. See above. - */ - static final int INITIAL_EXTERNAL_QUEUE_CAPACITY = 1 << 9; - // conversions among short, int, long static final int SMASK = 0xffff; // (unsigned) short bits static final long LMASK = 0xffffffffL; // lower 32 bits of long @@ -1211,11 +1186,11 @@ public class ForkJoinPool extends AbstractExecutorService @jdk.internal.vm.annotation.Contended("w") int stackPred; // pool stack (ctl) predecessor link @jdk.internal.vm.annotation.Contended("w") + volatile int parking; // nonzero if parked in awaitWork + @jdk.internal.vm.annotation.Contended("w") volatile int source; // source queue id (or DROPPED) @jdk.internal.vm.annotation.Contended("w") int nsteals; // number of steals from other queues - @jdk.internal.vm.annotation.Contended("w") - volatile int parking; // nonzero if parked in awaitWork // Support for atomic operations private static final Unsafe U; @@ -1248,11 +1223,11 @@ public class ForkJoinPool extends AbstractExecutorService */ WorkQueue(ForkJoinWorkerThread owner, int id, int cfg, boolean clearThreadLocals) { - array = new ForkJoinTask[owner == null ? - INITIAL_EXTERNAL_QUEUE_CAPACITY : - INITIAL_QUEUE_CAPACITY]; - this.owner = owner; this.config = (clearThreadLocals) ? cfg | CLEAR_TLS : cfg; + if ((this.owner = owner) == null) { + array = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; + phase = id | IDLE; + } } /** @@ -1279,27 +1254,27 @@ public class ForkJoinPool extends AbstractExecutorService * @throws RejectedExecutionException if array could not be resized */ final void push(ForkJoinTask task, ForkJoinPool pool, boolean internal) { - int s = top, b = base, m, cap, room; ForkJoinTask[] a; - if ((a = array) != null && (cap = a.length) > 0 && // else disabled - task != null) { - int pk = task.noUserHelp() + 1; // prev slot offset - if ((room = (m = cap - 1) - (s - b)) >= 0) { + int s = top, b = base, m, cap, room; ForkJoinTask[] a, na; + if ((a = array) != null && (cap = a.length) > 0) { // else disabled + int k = (m = cap - 1) & s; + if ((room = m - (s - b)) >= 0) { top = s + 1; - long pos = slotOffset(m & s); + long pos = slotOffset(k); if (!internal) U.putReference(a, pos, task); // inside lock else U.getAndSetReference(a, pos, task); // fully fenced - if (room == 0) // resize - growArray(a, cap, s); + if (room == 0 && (na = growArray(a, cap, s)) != null) + k = ((a = na).length - 1) & s; // resize } if (!internal) unlockPhase(); if (room < 0) throw new RejectedExecutionException("Queue capacity exceeded"); - if ((room == 0 || a[m & (s - pk)] == null) && - pool != null) - pool.signalWork(); // may have appeared empty + if (pool != null && + (room == 0 || + U.getReferenceAcquire(a, slotOffset(m & (s - 1))) == null)) + pool.signalWork(a, k); // may have appeared empty } } @@ -1308,11 +1283,12 @@ public class ForkJoinPool extends AbstractExecutorService * @param a old array * @param cap old array capacity * @param s current top + * @return new array, or null on failure */ - private void growArray(ForkJoinTask[] a, int cap, int s) { - int newCap = cap << 1; + private ForkJoinTask[] growArray(ForkJoinTask[] a, int cap, int s) { + int newCap = (cap >= 1 << 16) ? cap << 1 : cap << 2; + ForkJoinTask[] newArray = null; if (a != null && a.length == cap && cap > 0 && newCap > 0) { - ForkJoinTask[] newArray = null; try { newArray = new ForkJoinTask[newCap]; } catch (OutOfMemoryError ex) { @@ -1329,34 +1305,45 @@ public class ForkJoinPool extends AbstractExecutorService updateArray(newArray); // fully fenced } } + return newArray; } /** - * Takes next task, if one exists, in order specified by mode, - * so acts as either local-pop or local-poll. Called only by owner. - * @param fifo nonzero if FIFO mode + * Takes next task, if one exists, in lifo order. */ - private ForkJoinTask nextLocalTask(int fifo) { + private ForkJoinTask localPop() { ForkJoinTask t = null; - ForkJoinTask[] a = array; - int b = base, p = top, cap; - if (p - b > 0 && a != null && (cap = a.length) > 0) { - for (int m = cap - 1, s, nb;;) { - if (fifo == 0 || (nb = b + 1) == p) { - if ((t = (ForkJoinTask)U.getAndSetReference( - a, slotOffset(m & (s = p - 1)), null)) != null) - updateTop(s); // else lost race for only task - break; + int s = top - 1, cap; long k; ForkJoinTask[] a; + if ((a = array) != null && (cap = a.length) > 0 && + U.getReference(a, k = slotOffset((cap - 1) & s)) != null && + (t = (ForkJoinTask)U.getAndSetReference(a, k, null)) != null) + updateTop(s); + return t; + } + + /** + * Takes next task, if one exists, in fifo order. + */ + private ForkJoinTask localPoll() { + ForkJoinTask t = null; + int p = top, cap; ForkJoinTask[] a; + if ((a = array) != null && (cap = a.length) > 0) { + for (int b = base; p - b > 0; ) { + int nb = b + 1; + long k = slotOffset((cap - 1) & b); + if (U.getReference(a, k) == null) { + if (nb == p) + break; // else base is lagging + while (b == (b = U.getIntAcquire(this, BASE))) + Thread.onSpinWait(); // spin to reduce memory traffic } - if ((t = (ForkJoinTask)U.getAndSetReference( - a, slotOffset(m & b), null)) != null) { + else if ((t = (ForkJoinTask) + U.getAndSetReference(a, k, null)) != null) { updateBase(nb); break; } - while (b == (b = U.getIntAcquire(this, BASE))) - Thread.onSpinWait(); // spin to reduce memory traffic - if (p - b <= 0) - break; + else + b = base; } } return t; @@ -1364,10 +1351,9 @@ public class ForkJoinPool extends AbstractExecutorService /** * Takes next task, if one exists, using configured mode. - * (Always internal, never called for Common pool.) */ final ForkJoinTask nextLocalTask() { - return nextLocalTask(config & FIFO); + return (config & FIFO) == 0 ? localPop() : localPoll(); } /** @@ -1443,12 +1429,12 @@ public class ForkJoinPool extends AbstractExecutorService // specialized execution methods /** - * Runs the given task, as well as remaining local tasks. + * Runs the given task, as well as remaining local tasks */ final void topLevelExec(ForkJoinTask task, int fifo) { while (task != null) { task.doExec(); - task = nextLocalTask(fifo); + task = (fifo != 0) ? localPoll() : localPop(); } } @@ -1578,7 +1564,7 @@ public class ForkJoinPool extends AbstractExecutorService * Cancels all local tasks. Called only by owner. */ final void cancelTasks() { - for (ForkJoinTask t; (t = nextLocalTask(0)) != null; ) { + for (ForkJoinTask t; (t = localPop()) != null; ) { try { t.cancel(false); } catch (Throwable ignore) { @@ -1780,7 +1766,8 @@ public class ForkJoinPool extends AbstractExecutorService * @param w caller's WorkQueue */ final void registerWorker(WorkQueue w) { - if (w != null && (runState & STOP) == 0L) { + if (w != null) { + w.array = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; ThreadLocalRandom.localInit(); int seed = w.stackPred = ThreadLocalRandom.getProbe(); int phaseSeq = seed & ~((IDLE << 1) - 1); // initial phase tag @@ -1858,17 +1845,18 @@ public class ForkJoinPool extends AbstractExecutorService } if ((tryTerminate(false, false) & STOP) == 0L && phase != 0 && w != null && w.source != DROPPED) { - signalWork(); // possibly replace w.cancelTasks(); // clean queue + signalWork(null, 0); // possibly replace } if (ex != null) ForkJoinTask.rethrow(ex); } /** - * Releases an idle worker, or creates one if not enough exist. + * Releases an idle worker, or creates one if not enough exist, + * giving up if array a is nonnull and task at a[k] already taken. */ - final void signalWork() { + final void signalWork(ForkJoinTask[] a, int k) { int pc = parallelism; for (long c = ctl;;) { WorkQueue[] qs = queues; @@ -1884,13 +1872,15 @@ public class ForkJoinPool extends AbstractExecutorService if (sp == 0) { if ((short)(c >>> TC_SHIFT) >= pc) break; - nc = ((c + TC_UNIT) & TC_MASK); + nc = ((c + TC_UNIT) & TC_MASK) | ac; } else if ((v = w) == null) break; else - nc = (v.stackPred & LMASK) | (c & TC_MASK); - if (c == (c = compareAndExchangeCtl(c, nc | ac))) { + nc = (v.stackPred & LMASK) | (c & TC_MASK) | ac; + if (a != null && k < a.length && k >= 0 && a[k] == null) + break; + if (c == (c = ctl) && c == (c = compareAndExchangeCtl(c, nc))) { if (v == null) createWorker(); else { @@ -1973,178 +1963,196 @@ public class ForkJoinPool extends AbstractExecutorService * @param w caller's WorkQueue (may be null on failed initialization) */ final void runWorker(WorkQueue w) { - if (w != null) { - int phase = w.phase, r = w.stackPred; // seed from registerWorker - int fifo = w.config & FIFO, nsteals = 0, src = -1; - for (;;) { - WorkQueue[] qs; + if (w != null && w.phase != 0) { // else unregistered + WorkQueue[] qs; + int r = w.stackPred; // seed from registerWorker + int fifo = (int)config & FIFO, rescans = 0, inactive = 0, taken = 0, n; + while ((runState & STOP) == 0L && (qs = queues) != null && + (n = qs.length) > 0) { + int i = r, step = (r >>> 16) | 1; r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift - if ((runState & STOP) != 0L || (qs = queues) == null) - break; - int n = qs.length, i = r, step = (r >>> 16) | 1; - boolean rescan = false; - scan: for (int l = n; l > 0; --l, i += step) { // scan queues - int j, cap; WorkQueue q; ForkJoinTask[] a; - if ((q = qs[j = i & (n - 1)]) != null && - (a = q.array) != null && (cap = a.length) > 0) { - for (int m = cap - 1, pb = -1, b = q.base;;) { - ForkJoinTask t; long k; + scan: for (int j = n; j != 0; --j, i += step) { + WorkQueue q; int qid; + if ((q = qs[qid = i & (n - 1)]) != null) { + ForkJoinTask[] a; int cap; // poll queue + while ((a = q.array) != null && (cap = a.length) > 0) { + int b, nb, nk; long bp; ForkJoinTask t; t = (ForkJoinTask)U.getReferenceAcquire( - a, k = slotOffset(m & b)); - if (b != (b = q.base) || t == null || - !U.compareAndSetReference(a, k, t, null)) { - if (a[b & m] == null) { - if (rescan) // end of run - break scan; - if (a[(b + 1) & m] == null && - a[(b + 2) & m] == null) { - break; // probably empty + a, bp = slotOffset((cap - 1) & (b = q.base))); + long np = slotOffset(nk = (nb = b + 1) & (cap - 1)); + if (q.base == b) { // else inconsistent + if (t == null) { + if (q.array == a) { // else resized + if (rescans > 0) // ran or stalled + break scan; + if (U.getReference(a, np) == null && + (rescans >= 0 || + (U.getReferenceAcquire(a, bp) == null && + q.top == q.base))) + break; + rescans = 1; // may be stalled } - if (pb == (pb = b)) { // track progress - rescan = true; // stalled; reorder scan + } + else if (inactive != 0) { + if ((inactive = tryReactivate(w)) != 0) { + rescans = 1; // can't take yet break scan; } } - } - else { - boolean propagate; - int nb = q.base = b + 1, prevSrc = src; - w.nsteals = ++nsteals; - w.source = src = j; // volatile - rescan = true; - int nh = t.noUserHelp(); - if (propagate = - (prevSrc != src || nh != 0) && a[nb & m] != null) - signalWork(); - w.topLevelExec(t, fifo); - if ((b = q.base) != nb && !propagate) - break scan; // reduce interference + else if (U.compareAndSetReference(a, bp, t, null)) { + q.base = nb; + Object nt = U.getReferenceAcquire(a, np); + w.source = qid; + rescans = 1; + ++taken; + if (nt != null && // confirm a[nk] + U.getReferenceAcquire(a, np) == nt) + signalWork(a, nk); // propagate + w.topLevelExec(t, fifo); + } } } } } - if (!rescan) { - if (((phase = deactivate(w, phase)) & IDLE) != 0) - break; - src = -1; // re-enable propagation + if (rescans >= 0) + --rescans; + else if (inactive == 0) { + if ((inactive = deactivate(w, taken)) != 0) + taken = 0; } + else if (awaitWork(w) == 0) + inactive = rescans = 0; + else + break; } } } /** - * Deactivates and if necessary awaits signal or termination. + * Tries to deactivate worker, keeping active on contention * - * @param w the worker - * @param phase current phase - * @return current phase, with IDLE set if worker should exit + * @param w the work queue + * @param taken number of stolen tasks since last deactivation + * @return nonzero if inactive */ - private int deactivate(WorkQueue w, int phase) { - if (w == null) // currently impossible - return IDLE; - int p = phase | IDLE, activePhase = phase + (IDLE << 1); - long pc = ctl, qc = (activePhase & LMASK) | ((pc - RC_UNIT) & UMASK); - int sp = w.stackPred = (int)pc; // set ctl stack link - w.phase = p; - if (!compareAndSetCtl(pc, qc)) // try to enqueue - return w.phase = phase; // back out on possible signal - int ac = (short)(qc >>> RC_SHIFT), n; long e; WorkQueue[] qs; - if (((e = runState) & STOP) != 0L || - ((e & SHUTDOWN) != 0L && ac == 0 && quiescent() > 0) || - (qs = queues) == null || (n = qs.length) <= 0) - return IDLE; // terminating - - for (int prechecks = Math.min(ac, 2), // reactivation threshold - k = Math.max(n + (n << 1), SPIN_WAITS << 1);;) { - WorkQueue q; int cap; ForkJoinTask[] a; long c; - if (w.phase == activePhase) - return activePhase; - if (--k < 0) - return awaitWork(w, p); // block, drop, or exit - if ((q = qs[k & (n - 1)]) == null) - Thread.onSpinWait(); - else if ((a = q.array) != null && (cap = a.length) > 0 && - a[q.base & (cap - 1)] != null && --prechecks < 0 && - (int)(c = ctl) == activePhase && - compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) - return w.phase = activePhase; // reactivate + private int deactivate(WorkQueue w, int taken) { + int inactive = 0, phase; + if (w != null && (inactive = (phase = w.phase) & IDLE) == 0) { + long sp = (phase + (IDLE << 1)) & LMASK, pc, c; + w.phase = phase | IDLE; + w.stackPred = (int)(pc = ctl); // set ctl stack link + if (!compareAndSetCtl( // try to enqueue + pc, c = ((pc - RC_UNIT) & UMASK) | sp)) + w.phase = phase; // back out on contention + else { + if (taken != 0) { + w.nsteals += taken; + if ((w.config & CLEAR_TLS) != 0 && + (Thread.currentThread() instanceof ForkJoinWorkerThread f)) + f.resetThreadLocals(); // (instanceof check always true) + } + if (((c & RC_MASK) == 0L && quiescent() > 0) || taken == 0) + inactive = w.phase & IDLE; // check quiescent termination + else { // spin for approx 1 scan cost + int tc = (short)(c >>> TC_SHIFT); + int spins = Math.max((tc << 1) + tc, SPIN_WAITS); + while ((inactive = w.phase & IDLE) != 0 && --spins != 0) + Thread.onSpinWait(); + } + } } + return inactive; + } + + /** + * Reactivates worker w if it is currently top of ctl stack + * + * @param w the work queue + * @return 0 if now active + */ + private int tryReactivate(WorkQueue w) { + int inactive = 0; + if (w != null) { // always true; hoist checks + int sp = w.stackPred, phase, activePhase; long c; + if ((inactive = (phase = w.phase) & IDLE) != 0 && + (int)(c = ctl) == (activePhase = phase + IDLE) && + compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) { + w.phase = activePhase; + inactive = 0; + } + } + return inactive; } /** * Awaits signal or termination. * * @param w the work queue - * @param p current phase (known to be idle) - * @return current phase, with IDLE set if worker should exit + * @return 0 if now active */ - private int awaitWork(WorkQueue w, int p) { - if (w != null) { - ForkJoinWorkerThread t; long deadline; - if ((w.config & CLEAR_TLS) != 0 && (t = w.owner) != null) - t.resetThreadLocals(); // clear before reactivate - if ((ctl & RC_MASK) > 0L) - deadline = 0L; - else if ((deadline = - (((w.source != INVALID_ID) ? keepAlive : TIMEOUT_SLOP)) + - System.currentTimeMillis()) == 0L) - deadline = 1L; // avoid zero - int activePhase = p + IDLE; - if ((p = w.phase) != activePhase && (runState & STOP) == 0L) { + private int awaitWork(WorkQueue w) { + int inactive = 0, phase; + if (w != null) { // always true; hoist checks + long waitTime = (w.source == INVALID_ID) ? 0L : keepAlive; + if ((inactive = (phase = w.phase) & IDLE) != 0) { LockSupport.setCurrentBlocker(this); - w.parking = 1; // enable unpark - while ((p = w.phase) != activePhase) { - boolean trimmable = false; int trim; - Thread.interrupted(); // clear status + int activePhase = phase + IDLE; + for (long deadline = 0L;;) { + Thread.interrupted(); // clear status if ((runState & STOP) != 0L) break; - if (deadline != 0L) { - if ((trim = tryTrim(w, p, deadline)) > 0) - break; - else if (trim < 0) - deadline = 0L; - else - trimmable = true; + boolean trimmable = false; // use timed wait if trimmable + long d = 0L, c; + if (((c = ctl) & RC_MASK) == 0L && (int)c == activePhase) { + long now = System.currentTimeMillis(); + if (deadline == 0L) + deadline = waitTime + now; + if (deadline - now <= TIMEOUT_SLOP) { + if (tryTrim(w, c, activePhase)) + break; + continue; // lost race to trim + } + d = deadline; + trimmable = true; } - U.park(trimmable, deadline); + w.parking = 1; // enable unpark and recheck + if ((inactive = w.phase & IDLE) != 0) + U.park(trimmable, d); + w.parking = 0; // close unpark window + if (inactive == 0 || (inactive = w.phase & IDLE) == 0) + break; } - w.parking = 0; LockSupport.setCurrentBlocker(null); } } - return p; + return inactive; } /** * Tries to remove and deregister worker after timeout, and release - * another to do the same. - * @return > 0: trimmed, < 0 : not trimmable, else 0 + * another to do the same unless new tasks are found. */ - private int tryTrim(WorkQueue w, int phase, long deadline) { - long c, nc; int stat, activePhase, vp, i; WorkQueue[] vs; WorkQueue v; - if ((activePhase = phase + IDLE) != (int)(c = ctl) || w == null) - stat = -1; // no longer ctl top - else if (deadline - System.currentTimeMillis() >= TIMEOUT_SLOP) - stat = 0; // spurious wakeup - else if (!compareAndSetCtl( - c, nc = ((w.stackPred & LMASK) | (RC_MASK & c) | - (TC_MASK & (c - TC_UNIT))))) - stat = -1; // lost race to signaller - else { - stat = 1; - w.source = DROPPED; - w.phase = activePhase; - if ((vp = (int)nc) != 0 && (vs = queues) != null && - vs.length > (i = vp & SMASK) && (v = vs[i]) != null && - compareAndSetCtl( // try to wake up next waiter - nc, ((UMASK & (nc + RC_UNIT)) | - (nc & TC_MASK) | (v.stackPred & LMASK)))) { - v.source = INVALID_ID; // enable cascaded timeouts - v.phase = vp; - U.unpark(v.owner); + private boolean tryTrim(WorkQueue w, long c, int activePhase) { + if (w != null) { + int vp, i; WorkQueue[] vs; WorkQueue v; + long nc = ((w.stackPred & LMASK) | + ((RC_MASK & c) | (TC_MASK & (c - TC_UNIT)))); + if (compareAndSetCtl(c, nc)) { + w.source = DROPPED; + w.phase = activePhase; + if ((vp = (int)nc) != 0 && (vs = queues) != null && + vs.length > (i = vp & SMASK) && (v = vs[i]) != null && + compareAndSetCtl( // try to wake up next waiter + nc, ((v.stackPred & LMASK) | + ((UMASK & (nc + RC_UNIT)) | (nc & TC_MASK))))) { + v.source = INVALID_ID; // enable cascaded timeouts + v.phase = vp; + U.unpark(v.owner); + } + return true; } } - return stat; + return false; } /** @@ -2561,52 +2569,35 @@ public class ForkJoinPool extends AbstractExecutorService /** * Finds and locks a WorkQueue for an external submitter, or - * throws RejectedExecutionException if shutdown or terminating. - * @param r current ThreadLocalRandom.getProbe() value + * throws RejectedExecutionException if shutdown * @param rejectOnShutdown true if RejectedExecutionException - * should be thrown when shutdown (else only if terminating) + * should be thrown when shutdown */ - private WorkQueue submissionQueue(int r, boolean rejectOnShutdown) { - int reuse; // nonzero if prefer create - if ((reuse = r) == 0) { - ThreadLocalRandom.localInit(); // initialize caller's probe + final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) { + int r; + if ((r = ThreadLocalRandom.getProbe()) == 0) { + ThreadLocalRandom.localInit(); // initialize caller's probe r = ThreadLocalRandom.getProbe(); } - for (int probes = 0; ; ++probes) { - int n, i, id; WorkQueue[] qs; WorkQueue q; - if ((qs = queues) == null) - break; - if ((n = qs.length) <= 0) + for (;;) { + WorkQueue q; WorkQueue[] qs; int n, id, i; + if ((qs = queues) == null || (n = qs.length) <= 0) break; if ((q = qs[i = (id = r & EXTERNAL_ID_MASK) & (n - 1)]) == null) { - WorkQueue w = new WorkQueue(null, id, 0, false); - w.phase = id; - boolean reject = ((lockRunState() & SHUTDOWN) != 0 && - rejectOnShutdown); - if (!reject && queues == qs && qs[i] == null) - q = qs[i] = w; // else lost race to install + WorkQueue newq = new WorkQueue(null, id, 0, false); + lockRunState(); + if (qs[i] == null && queues == qs) + q = qs[i] = newq; // else lost race to install unlockRunState(); - if (q != null) - return q; - if (reject) + } + if (q != null && q.tryLockPhase()) { + if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) { + q.unlockPhase(); // check while q lock held break; - reuse = 0; - } - if (reuse == 0 || !q.tryLockPhase()) { // move index - if (reuse == 0) { - if (probes >= n >> 1) - reuse = r; // stop prefering free slot } - else if (q != null) - reuse = 0; // probe on collision - r = ThreadLocalRandom.advanceProbe(r); - } - else if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) { - q.unlockPhase(); // check while q lock held - break; - } - else return q; + } + r = ThreadLocalRandom.advanceProbe(r); // move } throw new RejectedExecutionException(); } @@ -2620,24 +2611,12 @@ public class ForkJoinPool extends AbstractExecutorService } else { // find and lock queue internal = false; - q = submissionQueue(ThreadLocalRandom.getProbe(), true); + q = externalSubmissionQueue(true); } q.push(task, signalIfEmpty ? this : null, internal); return task; } - /** - * Returns queue for an external submission, bypassing call to - * submissionQueue if already established and unlocked. - */ - final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) { - WorkQueue[] qs; WorkQueue q; int n; - int r = ThreadLocalRandom.getProbe(); - return (((qs = queues) != null && (n = qs.length) > 0 && - (q = qs[r & EXTERNAL_ID_MASK & (n - 1)]) != null && r != 0 && - q.tryLockPhase()) ? q : submissionQueue(r, rejectOnShutdown)); - } - /** * Returns queue for an external thread, if one exists that has * possibly ever submitted to the given pool (nonzero probe), or @@ -3310,11 +3289,14 @@ public class ForkJoinPool extends AbstractExecutorService * @since 19 */ public int setParallelism(int size) { + int prevSize; if (size < 1 || size > MAX_CAP) throw new IllegalArgumentException(); if ((config & PRESET_SIZE) != 0) throw new UnsupportedOperationException("Cannot override System property"); - return getAndSetParallelism(size); + if ((prevSize = getAndSetParallelism(size)) < size) + signalWork(null, 0); // trigger worker activation + return prevSize; } /** diff --git a/test/jdk/java/util/concurrent/forkjoin/Starvation.java b/test/jdk/java/util/concurrent/forkjoin/Starvation.java index 8397e852ffa..d864fa0ba33 100644 --- a/test/jdk/java/util/concurrent/forkjoin/Starvation.java +++ b/test/jdk/java/util/concurrent/forkjoin/Starvation.java @@ -28,6 +28,7 @@ */ import java.util.concurrent.Callable; import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; import java.util.concurrent.atomic.AtomicInteger; public class Starvation { @@ -42,7 +43,7 @@ public class Starvation { while (count.get() == c) Thread.onSpinWait(); return null; }}; - public static void main(String[] args) throws Exception { + static void testSubmitExternalCallable() throws Exception { try (var pool = new ForkJoinPool(2)) { for (int i = 0; i < 100_000; i++) { var future1 = pool.submit(new AwaitCount(i)); @@ -53,4 +54,21 @@ public class Starvation { } } } + + static void testSubmitAdaptedCallable() throws Exception { + try (var pool = new ForkJoinPool(2)) { + for (int i = 0; i < 100_000; i++) { + var future1 = pool.submit(new AwaitCount(i)); + var future2 = pool.submit(ForkJoinTask.adapt(noop)); + future2.get(); + count.set(i + 1); + future1.get(); + } + } + } + + public static void main(String[] args) throws Exception { + testSubmitExternalCallable(); + testSubmitAdaptedCallable(); + } } From 13e062e7a36cf9880416a4e867de13778c6bed2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Tue, 2 Dec 2025 12:13:03 +0000 Subject: [PATCH 72/81] 8366578: Remove the field tagSize in various QuicPacketEncoder.OutgoingQuicPacket subclasses Reviewed-by: jpai, dfuchs --- .../internal/net/http/quic/packets/QuicPacketEncoder.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java index 890c1a63a35..db519dc7557 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java @@ -577,7 +577,6 @@ public class QuicPacketEncoder { final byte[] encodedPacketNumber; final List frames; final int payloadSize; - private int tagSize; OutgoingHandshakePacket(QuicConnectionId sourceId, QuicConnectionId destinationId, @@ -590,7 +589,6 @@ public class QuicPacketEncoder { this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); this.payloadSize = frames.stream().mapToInt(QuicFrame::size).reduce(0, Math::addExact); - this.tagSize = tagSize; this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize); this.size = computeSize(length); } @@ -676,7 +674,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; OutgoingZeroRttPacket(QuicConnectionId sourceId, @@ -689,7 +686,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size) .reduce(0, Math::addExact); this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize); @@ -778,7 +774,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; OutgoingOneRttPacket(QuicConnectionId destinationId, @@ -789,7 +784,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size) .reduce(0, Math::addExact); this.size = computeSize(payloadSize, encodedPacketNumber.length, tagSize); @@ -853,7 +847,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; private record InitialPacketVariableComponents(int length, byte[] token, QuicConnectionId sourceId, @@ -873,7 +866,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream() .mapToInt(QuicFrame::size) .reduce(0, Math::addExact); From 5cba2c8461005f2f7bcafdce622126a113f4bbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Tue, 2 Dec 2025 12:13:21 +0000 Subject: [PATCH 73/81] 8368093: Remove Stream::createPseudoHeaders Reviewed-by: dfuchs, jpai, vyazici --- .../classes/jdk/internal/net/http/Stream.java | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 4b59a777de2..9a7ccd8f3a1 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -31,7 +31,6 @@ import java.io.UncheckedIOException; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.net.ProtocolException; -import java.net.URI; import java.net.http.HttpResponse.BodyHandler; import java.net.http.HttpResponse.ResponseInfo; import java.nio.ByteBuffer; @@ -973,36 +972,6 @@ class Stream extends ExchangeImpl { return headers; } - private static HttpHeaders createPseudoHeaders(HttpRequest request) { - HttpHeadersBuilder hdrs = new HttpHeadersBuilder(); - String method = request.method(); - hdrs.setHeader(":method", method); - URI uri = request.uri(); - hdrs.setHeader(":scheme", uri.getScheme()); - String host = uri.getHost(); - int port = uri.getPort(); - assert host != null; - if (port != -1) { - hdrs.setHeader(":authority", host + ":" + port); - } else { - hdrs.setHeader(":authority", host); - } - String query = uri.getRawQuery(); - String path = uri.getRawPath(); - if (path == null || path.isEmpty()) { - if (method.equalsIgnoreCase("OPTIONS")) { - path = "*"; - } else { - path = "/"; - } - } - if (query != null) { - path += "?" + query; - } - hdrs.setHeader(":path", Utils.encode(path)); - return hdrs.build(); - } - HttpHeaders getRequestPseudoHeaders() { return requestPseudoHeaders; } From 07856fce34ba14a83fc1ac0faffe3b5ba883e0b5 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 2 Dec 2025 12:17:40 +0000 Subject: [PATCH 74/81] 8372787: ModuleReader should throw IOException consistently when using --patch-module and ModuleReader is closed Reviewed-by: alanb --- .../jdk/internal/module/ModulePatcher.java | 20 ++- .../patched/PatchedModuleReaderTest.java | 132 ++++++++++++++++++ .../java.base/java/lang/PatchedFoo.java | 26 ++++ 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java create mode 100644 test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java diff --git a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java index d24cc77600c..eb3f25ceca7 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java +++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -225,6 +225,7 @@ public final class ModulePatcher { private final ModuleReference mref; private final URL delegateCodeSourceURL; private volatile ModuleReader delegate; + private volatile boolean closed; /** * Creates the ModuleReader to reads resources in a patched module. @@ -291,6 +292,15 @@ public final class ModulePatcher { return r; } + /** + * Throws an IOException if the ModuleReader is closed. + */ + private void ensureOpen() throws IOException { + if (closed) { + throw new IOException("ModuleReader is closed"); + } + } + /** * Finds a resources in the patch locations. Returns null if not found * or the name is "module-info.class" as that cannot be overridden. @@ -310,7 +320,7 @@ public final class ModulePatcher { * Finds a resource of the given name in the patched module. */ public Resource findResource(String name) throws IOException { - + assert !closed : "module reader is closed"; // patch locations Resource r = findResourceInPatch(name); if (r != null) @@ -354,6 +364,7 @@ public final class ModulePatcher { @Override public Optional find(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { URI uri = URI.create(r.getURL().toString()); @@ -365,6 +376,7 @@ public final class ModulePatcher { @Override public Optional open(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { return Optional.of(r.getInputStream()); @@ -375,6 +387,7 @@ public final class ModulePatcher { @Override public Optional read(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { ByteBuffer bb = r.getByteBuffer(); @@ -398,6 +411,7 @@ public final class ModulePatcher { @Override public Stream list() throws IOException { + ensureOpen(); Stream s = delegate().list(); for (ResourceFinder finder : finders) { s = Stream.concat(s, finder.list()); @@ -407,6 +421,10 @@ public final class ModulePatcher { @Override public void close() throws IOException { + if (closed) { + return; + } + closed = true; closeAll(finders); delegate().close(); } diff --git a/test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java b/test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java new file mode 100644 index 00000000000..80f4e324627 --- /dev/null +++ b/test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.util.Optional; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test + * @bug 8372787 + * @summary Test the behaviour of ModuleReader when using --patch-module + * @comment patch the java.base module with a test specific resource + * @compile/module=java.base java/lang/PatchedFoo.java + * @run junit/othervm ${test.main.class} + */ +class PatchedModuleReaderTest { + + private static ModuleReference patchedModuleRef; + + @BeforeAll + static void beforeAll() { + patchedModuleRef = ModuleFinder.ofSystem() + .find("java.base") + .orElseThrow(); + } + + /* + * Verifies that the resource that was patched into a module + * is found by the ModuleReader. + */ + @Test + void testResourceFound() throws Exception { + try (ModuleReader reader = patchedModuleRef.open()) { + String resourceName = "java/lang/PatchedFoo.class"; + Optional res = reader.find(resourceName); + assertTrue(res.isPresent(), resourceName + " is missing in " + + patchedModuleRef.descriptor().name() + " module"); + URI uri = res.get(); + assertEquals("file", uri.getScheme(), + "unexpected scheme in resource URI " + uri); + assertTrue(uri.getPath().endsWith(resourceName), + "unexpected path component " + uri.getPath() + + " in resource URI " + uri); + + } + } + + /* + * Verifies the ModuleReader against a resource which isn't + * expected to be part of the patched module. + */ + @Test + void testResourceNotFound() throws Exception { + try (ModuleReader reader = patchedModuleRef.open()) { + String nonExistentResource = "foo/bar/NonExistent.class"; + Optional res = reader.find(nonExistentResource); + assertTrue(res.isEmpty(), "unexpected resource " + nonExistentResource + + " in " + patchedModuleRef.descriptor().name() + " module"); + } + } + + /* + * This test opens a ModuleReader for a patched module, accumulates + * the Stream of resources from that ModuleReader and then closes that + * ModuleReader. It then verifies that the closed ModuleReader + * throws the specified IOException whenever it is used for subsequent + * operations on the Stream of resources. + */ + @Test + void testIOExceptionAfterClose() throws Exception { + ModuleReader reader; + Stream resources; + try (var _ = reader = patchedModuleRef.open()) { + // hold on to the available resources, to test them after the + // ModuleReader is closed + resources = reader.list(); + } // close the ModuleReader + + // verify IOException is thrown by the closed ModuleReader + + assertThrows(IOException.class, () -> reader.list(), + "ModuleReader.list()"); + + resources.forEach(rn -> { + assertThrows(IOException.class, () -> reader.read(rn), + "ModuleReader.read(String)"); + assertThrows(IOException.class, () -> reader.open(rn), + "ModuleReader.open(String)"); + assertThrows(IOException.class, () -> reader.find(rn), + "ModuleReader.find(String)"); + }); + + // repeat the test for a non-existent resource + String nonExistentResource = "foo/bar/NonExistent.class"; + assertThrows(IOException.class, () -> reader.read(nonExistentResource), + "ModuleReader.read(String)"); + assertThrows(IOException.class, () -> reader.open(nonExistentResource), + "ModuleReader.open(String)"); + assertThrows(IOException.class, () -> reader.find(nonExistentResource), + "ModuleReader.find(String)"); + } +} diff --git a/test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java b/test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java new file mode 100644 index 00000000000..814757134d6 --- /dev/null +++ b/test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.lang; + +public class PatchedFoo { +} From d3083ac05453c9dd303038f90ddab50d52124e51 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Tue, 2 Dec 2025 12:19:48 +0000 Subject: [PATCH 75/81] 8371194: serviceability/sa/TestJhsdbJstackMixedWithXComp.java failing Co-authored-by: Patricio Chilano Mateo Reviewed-by: cjplummer, pchilanomate --- .../debugger/bsd/BsdDebuggerLocal.java | 48 ++++--- .../sun/jvm/hotspot/debugger/cdbg/CFrame.java | 11 +- .../debugger/linux/LinuxCDebugger.java | 14 +- .../linux/aarch64/LinuxAARCH64CFrame.java | 39 +++++- .../linux/amd64/LinuxAMD64CFrame.java | 67 ++++++--- .../linux/ppc64/LinuxPPC64CFrame.java | 10 +- .../linux/riscv64/LinuxRISCV64CFrame.java | 26 +++- .../hotspot/runtime/aarch64/AARCH64Frame.java | 10 +- .../jvm/hotspot/runtime/amd64/AMD64Frame.java | 4 +- .../classes/sun/jvm/hotspot/tools/PStack.java | 131 ++++++++---------- test/hotspot/jtreg/ProblemList.txt | 1 - .../sa/TestJhsdbJstackMixedWithXComp.java | 31 ++++- 12 files changed, 256 insertions(+), 136 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java index 10f6881d010..efbb613994d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,9 @@ package sun.jvm.hotspot.debugger.bsd; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.stream.IntStream; import sun.jvm.hotspot.debugger.Address; import sun.jvm.hotspot.debugger.DebuggerBase; @@ -75,10 +77,11 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { // CDebugger support private BsdCDebugger cdbg; - // threadList and loadObjectList are filled by attach0 method - private List threadList; + // loadObjectList is filled by attach0 method private List loadObjectList; + private List javaThreadList; + // called by native method lookupByAddress0 private ClosestSymbol createClosestSymbol(String name, long offset) { return new ClosestSymbol(name, offset); @@ -241,10 +244,21 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { } } + private void fillJavaThreadList() { + // TODO: thread list on macOS is now supported for corefile only. + if (!isCore && isDarwin) { + javaThreadList = Collections.emptyList(); + } else { + Threads threads = VM.getVM().getThreads(); + javaThreadList = IntStream.range(0, threads.getNumberOfThreads()) + .mapToObj(threads::getJavaThreadAt) + .toList(); + } + } + /** From the Debugger interface via JVMDebugger */ public synchronized void attach(int processID) throws DebuggerException { checkAttached(); - threadList = new ArrayList<>(); loadObjectList = new ArrayList<>(); class AttachTask implements WorkerThreadTask { int pid; @@ -264,7 +278,6 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** From the Debugger interface via JVMDebugger */ public synchronized void attach(String execName, String coreName) { checkAttached(); - threadList = new ArrayList<>(); loadObjectList = new ArrayList<>(); attach0(execName, coreName); attached = true; @@ -278,7 +291,7 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { return false; } - threadList = null; + javaThreadList = null; loadObjectList = null; if (isCore) { @@ -492,7 +505,12 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** From the BsdCDebugger interface */ public List getThreadList() { requireAttach(); - return threadList; + if (javaThreadList == null) { + fillJavaThreadList(); + } + return javaThreadList.stream() + .map(JavaThread::getThreadProxy) + .toList(); } /** From the BsdCDebugger interface */ @@ -561,21 +579,19 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** this functions used for core file reading and called from native attach0, it returns an array of long integers as [thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for - all java threads recorded in Threads. Also adds the ThreadProxy to threadList */ + all java threads recorded in Threads. */ public long[] getJavaThreadsInfo() { requireAttach(); - Threads threads = VM.getVM().getThreads(); - int len = threads.getNumberOfThreads(); - long[] result = new long[len * 3]; // triple + if (javaThreadList == null) { + fillJavaThreadList(); + } + long[] result = new long[javaThreadList.size() * 3]; // triple long beg, end; int i = 0; - for (int k = 0; k < threads.getNumberOfThreads(); k++) { - JavaThread t = threads.getJavaThreadAt(k); + for (var t : javaThreadList) { end = t.getStackBaseValue(); beg = end - t.getStackSize(); - BsdThread bsdt = (BsdThread)t.getThreadProxy(); - long uid = bsdt.getUniqueThreadId(); - if (threadList != null) threadList.add(bsdt); + long uid = ((BsdThread)t.getThreadProxy()).getUniqueThreadId(); result[i] = uid; result[i + 1] = beg; result[i + 2] = end; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java index 47f41fe1383..bc366ef02b5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.jvm.hotspot.debugger.cdbg; import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.utilities.*; /** Models a "C" programming language frame on the stack -- really just an arbitrary frame with hooks to access C and C++ debug @@ -37,7 +39,7 @@ public interface CFrame { public CFrame sender(ThreadProxy th); /** Find sender frame with given FP and PC */ - public default CFrame sender(ThreadProxy th, Address fp, Address pc) { + public default CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { return sender(th); } @@ -70,4 +72,9 @@ public interface CFrame { /** Visit all local variables in this frame if debug information is available. Automatically descends into compound types and arrays. */ public void iterateLocals(ObjectVisitor v); + + /** Get Frame instance assosiated with this CFrame. */ + public default Frame toFrame() { + throw new UnsupportedPlatformException(); + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java index 894e31949b2..e3543503216 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -81,9 +81,11 @@ class LinuxCDebugger implements CDebugger { String cpu = dbg.getCPU(); if (cpu.equals("amd64")) { AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(AMD64ThreadContext.RSP); + if (sp == null) return null; Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP); if (pc == null) return null; - return LinuxAMD64CFrame.getTopFrame(dbg, pc, context); + return LinuxAMD64CFrame.getTopFrame(dbg, sp, pc, context); } else if (cpu.equals("ppc64")) { PPC64ThreadContext context = (PPC64ThreadContext) thread.getContext(); Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP); @@ -93,18 +95,22 @@ class LinuxCDebugger implements CDebugger { return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize()); } else if (cpu.equals("aarch64")) { AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP); + if (sp == null) return null; Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP); if (fp == null) return null; Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC); if (pc == null) return null; - return new LinuxAARCH64CFrame(dbg, fp, pc); + return new LinuxAARCH64CFrame(dbg, sp, fp, pc); } else if (cpu.equals("riscv64")) { RISCV64ThreadContext context = (RISCV64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(RISCV64ThreadContext.SP); + if (sp == null) return null; Address fp = context.getRegisterAsAddress(RISCV64ThreadContext.FP); if (fp == null) return null; Address pc = context.getRegisterAsAddress(RISCV64ThreadContext.PC); if (pc == null) return null; - return new LinuxRISCV64CFrame(dbg, fp, pc); + return new LinuxRISCV64CFrame(dbg, sp, fp, pc); } else { // Runtime exception thrown by LinuxThreadContextFactory if unknown cpu ThreadContext context = thread.getContext(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java index 93edb43eb82..5f76e6308e9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,10 +30,14 @@ import sun.jvm.hotspot.debugger.aarch64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.aarch64.*; public final class LinuxAARCH64CFrame extends BasicCFrame { - public LinuxAARCH64CFrame(LinuxDebugger dbg, Address fp, Address pc) { + public LinuxAARCH64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) { super(dbg.getCDebugger()); + this.sp = sp; this.fp = fp; this.pc = pc; this.dbg = dbg; @@ -55,11 +59,11 @@ public final class LinuxAARCH64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy thread) { - return sender(thread, null, null); + return sender(thread, null, null, null); } @Override - public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) { + public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) { // Check fp // Skip if both nextFP and nextPC are given - do not need to load from fp. if (nextFP == null && nextPC == null) { @@ -86,7 +90,32 @@ public final class LinuxAARCH64CFrame extends BasicCFrame { if (nextPC == null) { return null; } - return new LinuxAARCH64CFrame(dbg, nextFP, nextPC); + + if (nextSP == null) { + CodeCache cc = VM.getVM().getCodeCache(); + CodeBlob currentBlob = cc.findBlobUnsafe(pc()); + + // This case is different from HotSpot. See JDK-8371194 for details. + if (currentBlob != null && (currentBlob.isContinuationStub() || currentBlob.isNativeMethod())) { + // Use FP since it should always be valid for these cases. + // TODO: These should be walked as Frames not CFrames. + nextSP = fp.addOffsetTo(2 * ADDRESS_SIZE); + } else { + CodeBlob codeBlob = cc.findBlobUnsafe(nextPC); + boolean useCodeBlob = codeBlob != null && codeBlob.getFrameSize() > 0; + nextSP = useCodeBlob ? nextFP.addOffsetTo((2 * ADDRESS_SIZE) - codeBlob.getFrameSize()) : nextFP; + } + } + if (nextSP == null) { + return null; + } + + return new LinuxAARCH64CFrame(dbg, nextSP, nextFP, nextPC); + } + + @Override + public Frame toFrame() { + return new AARCH64Frame(sp, fp, pc); } // package/class internals only diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 9fa0fc20e99..612203634f3 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -29,10 +29,12 @@ import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.amd64.*; public final class LinuxAMD64CFrame extends BasicCFrame { - public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rip, ThreadContext context) { + public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rsp, Address rip, ThreadContext context) { Address libptr = dbg.findLibPtrByAddress(rip); Address cfa = context.getRegisterAsAddress(AMD64ThreadContext.RBP); DwarfParser dwarf = null; @@ -45,7 +47,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // DWARF processing should succeed when the frame is native // but it might fail if Common Information Entry (CIE) has language // personality routine and/or Language Specific Data Area (LSDA). - return new LinuxAMD64CFrame(dbg, cfa, rip, dwarf, true); + return new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf, true); } cfa = context.getRegisterAsAddress(dwarf.getCFARegister()) @@ -53,19 +55,20 @@ public final class LinuxAMD64CFrame extends BasicCFrame { } return (cfa == null) ? null - : new LinuxAMD64CFrame(dbg, cfa, rip, dwarf); + : new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf) { - this(dbg, cfa, rip, dwarf, false); + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf) { + this(dbg, rsp, cfa, rip, dwarf, false); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) { - this(dbg, cfa, rip, dwarf, finalFrame, false); + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) { + this(dbg, rsp, cfa, rip, dwarf, finalFrame, false); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) { + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) { super(dbg.getCDebugger()); + this.rsp = rsp; this.cfa = cfa; this.rip = rip; this.dbg = dbg; @@ -107,7 +110,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame { (!isNative || (isNative && nextCFA.greaterThan(cfa))); } - private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP) { + private Address getNextRSP() { + // next RSP should be previous slot of return address. + var bp = dwarf == null ? cfa.addOffsetTo(ADDRESS_SIZE) // top of BP points callser BP + : cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA()); + return bp.addOffsetTo(ADDRESS_SIZE); + } + + private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP, Address senderPC) { Address nextCFA; boolean isNative = false; @@ -115,13 +125,17 @@ public final class LinuxAMD64CFrame extends BasicCFrame { senderFP = cfa.getAddressAt(0); // RBP by default } - if (nextDwarf == null) { // Next frame is Java + if (VM.getVM().getCodeCache().contains(senderPC)) { // Next frame is Java nextCFA = (dwarf == null) ? senderFP // Current frame is Java : cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA()); // Current frame is Native } else { // Next frame is Native - if (dwarf == null) { // Current frame is Java + if (VM.getVM().getCodeCache().contains(pc())) { // Current frame is Java nextCFA = senderFP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()); } else { // Current frame is Native + if (nextDwarf == null) { // maybe runtime entrypoint (_start()) + throw new DebuggerException("nextDwarf is null even though native call"); + } + isNative = true; int nextCFAReg = nextDwarf.getCFARegister(); if (nextCFAReg == AMD64ThreadContext.RBP) { @@ -130,10 +144,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame { Address nextRBP = rbp.getAddressAt(0); nextCFA = nextRBP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()); } else if (nextCFAReg == AMD64ThreadContext.RSP) { - // next RSP should be previous slot of return address. - Address nextRSP = cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA()) - .addOffsetTo(ADDRESS_SIZE); - nextCFA = nextRSP.addOffsetTo(nextDwarf.getCFAOffset()); + nextCFA = getNextRSP().addOffsetTo(nextDwarf.getCFAOffset()); } else { throw new DebuggerException("Unsupported CFA register: " + nextCFAReg); } @@ -153,17 +164,22 @@ public final class LinuxAMD64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy th) { - return sender(th, null, null); + return sender(th, null, null, null); } @Override - public CFrame sender(ThreadProxy th, Address fp, Address pc) { + public CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { if (finalFrame) { return null; } ThreadContext context = th.getContext(); + Address nextRSP = sp != null ? sp : getNextRSP(); + if (nextRSP == null) { + return null; + } + Address nextPC = pc != null ? pc : getNextPC(dwarf != null); if (nextPC == null) { return null; @@ -183,13 +199,16 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // DWARF processing should succeed when the frame is native // but it might fail if Common Information Entry (CIE) has language // personality routine and/or Language Specific Data Area (LSDA). - return new LinuxAMD64CFrame(dbg, null, nextPC, nextDwarf, true); + return null; } } - Address nextCFA = getNextCFA(nextDwarf, context, fp); - return nextCFA == null ? null - : new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf, false, fallback); + try { + Address nextCFA = getNextCFA(nextDwarf, context, fp, nextPC); + return new LinuxAMD64CFrame(dbg, nextRSP, nextCFA, nextPC, nextDwarf, false, fallback); + } catch (DebuggerException _) { + return null; + } } private DwarfParser createDwarfParser(Address pc) throws DebuggerException { @@ -210,8 +229,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame { return nextDwarf; } + @Override + public Frame toFrame() { + return new AMD64Frame(rsp, cfa, rip); + } + // package/class internals only private static final int ADDRESS_SIZE = 8; + private Address rsp; private Address rip; private Address cfa; private LinuxDebugger dbg; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java index 424766fb1b4..c3724f14c2a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ import sun.jvm.hotspot.debugger.ppc64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.ppc64.*; public final class LinuxPPC64CFrame extends BasicCFrame { // package/class internals only @@ -71,6 +73,12 @@ public final class LinuxPPC64CFrame extends BasicCFrame { return new LinuxPPC64CFrame(dbg, nextSP, nextPC, address_size); } + @Override + public Frame toFrame() { + // 2nd arg (raw_fp) would be derived from sp in c'tor of PPC64Frame. + return new PPC64Frame(sp, null, pc); + } + public static int PPC64_STACK_BIAS = 0; private static int address_size; private Address pc; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java index 76f45891c47..65563be59ec 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -31,13 +31,17 @@ import sun.jvm.hotspot.debugger.riscv64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.riscv64.*; public final class LinuxRISCV64CFrame extends BasicCFrame { private static final int C_FRAME_LINK_OFFSET = -2; private static final int C_FRAME_RETURN_ADDR_OFFSET = -1; + private static final int C_FRAME_SENDER_SP_OFFSET = 0; - public LinuxRISCV64CFrame(LinuxDebugger dbg, Address fp, Address pc) { + public LinuxRISCV64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) { super(dbg.getCDebugger()); + this.sp = sp; this.fp = fp; this.pc = pc; this.dbg = dbg; @@ -59,11 +63,11 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy thread) { - return sender(thread, null, null); + return sender(thread, null, null, null); } @Override - public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) { + public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) { // Check fp // Skip if both nextFP and nextPC are given - do not need to load from fp. if (nextFP == null && nextPC == null) { @@ -77,6 +81,13 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { } } + if (nextSP == null) { + nextSP = fp.getAddressAt(C_FRAME_SENDER_SP_OFFSET * ADDRESS_SIZE); + } + if (nextSP == null) { + return null; + } + if (nextFP == null) { nextFP = fp.getAddressAt(C_FRAME_LINK_OFFSET * ADDRESS_SIZE); } @@ -91,7 +102,12 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { return null; } - return new LinuxRISCV64CFrame(dbg, nextFP, nextPC); + return new LinuxRISCV64CFrame(dbg, nextSP, nextFP, nextPC); + } + + @Override + public Frame toFrame() { + return new RISCV64Frame(sp, fp, pc); } // package/class internals only diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java index 5ae4cb703b3..7233d508cbc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java @@ -272,9 +272,7 @@ public class AARCH64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } @@ -389,7 +387,11 @@ public class AARCH64Frame extends Frame { if (Assert.ASSERTS_ENABLED) { Assert.that(cb.getFrameSize() > 0, "must have non-zero frame size"); } - Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize()); + + // TODO: senderSP should consider not only PreserveFramePointer but also _sp_is_trusted. + Address senderSP = !VM.getVM().getCommandLineBooleanFlag("PreserveFramePointer") + ? getUnextendedSP().addOffsetTo(cb.getFrameSize()) + : getSenderSP(); // The return_address is always the word on the stack Address senderPC = stripPAC(senderSP.getAddressAt(-1 * VM.getVM().getAddressSize())); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java index 360f62a253d..fa9d50160e1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java @@ -272,9 +272,7 @@ public class AMD64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java index 9865fbbe0f2..29d2954efdc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java @@ -70,7 +70,6 @@ public class PStack extends Tool { if (cdbg != null) { ConcurrentLocksPrinter concLocksPrinter = null; // compute and cache java Vframes. - initJFrameCache(); if (concurrentLocks) { concLocksPrinter = new ConcurrentLocksPrinter(out); } @@ -96,6 +95,7 @@ public class PStack extends Tool { return; } final boolean cdbgCanDemangle = cdbg.canDemangle(); + Map proxyToThread = createProxyToThread();; String fillerForAddress = " ".repeat(2 + 2 * (int) VM.getVM().getAddressSize()) + "\t"; for (Iterator itr = l.iterator() ; itr.hasNext();) { ThreadProxy th = itr.next(); @@ -109,6 +109,7 @@ public class PStack extends Tool { jthread.printThreadInfoOn(out); } while (f != null) { + Address senderSP = null; Address senderFP = null; Address senderPC = null; ClosestSymbol sym = f.closestSymbolToPC(); @@ -131,7 +132,7 @@ public class PStack extends Tool { // check interpreter frame Interpreter interp = VM.getVM().getInterpreter(); if (interp.contains(pc)) { - nameInfo = getJavaNames(th, f.localVariableBase()); + nameInfo = getJavaNames(jthread, f); // print codelet name if we can't determine method if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) { out.print(" "); @@ -156,7 +157,7 @@ public class PStack extends Tool { } out.println(" (Native method)"); } else { - nameInfo = getJavaNames(th, f.localVariableBase()); + nameInfo = getJavaNames(jthread, f); // just print compiled code, if can't determine method if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) { out.println(""); @@ -164,6 +165,12 @@ public class PStack extends Tool { } } else { out.println("<" + cb.getName() + ">"); + if (cb.getFrameSize() > 0) { + Frame senderFrame = f.toFrame().sender(jthread.newRegisterMap(true)); + senderSP = senderFrame.getSP(); + senderFP = senderFrame.getFP(); + senderPC = senderFrame.getPC(); + } } } else { printUnknown(out); @@ -180,11 +187,12 @@ public class PStack extends Tool { out.println(nameInfo.names()[i]); } } + senderSP = nameInfo.senderSP(); senderFP = nameInfo.senderFP(); senderPC = nameInfo.senderPC(); } } - f = f.sender(th, senderFP, senderPC); + f = f.sender(th, senderSP, senderFP, senderPC); } } catch (Exception exp) { exp.printStackTrace(); @@ -212,95 +220,74 @@ public class PStack extends Tool { } // -- Internals only below this point - private Map jframeCache; - private Map proxyToThread; private PrintStream out; private boolean verbose; private boolean concurrentLocks; - private void initJFrameCache() { - // cache frames for subsequent reference - jframeCache = new HashMap<>(); - proxyToThread = new HashMap<>(); + private Map createProxyToThread() { + Map proxyToThread = new HashMap<>(); Threads threads = VM.getVM().getThreads(); for (int i = 0; i < threads.getNumberOfThreads(); i++) { - JavaThread cur = threads.getJavaThreadAt(i); - List tmp = new ArrayList<>(10); - try { - for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { - tmp.add(vf); - } - } catch (Exception exp) { - // may be we may get frames for other threads, continue - // after printing stack trace. - exp.printStackTrace(); - } - JavaVFrame[] jvframes = tmp.toArray(new JavaVFrame[0]); - jframeCache.put(cur.getThreadProxy(), jvframes); - proxyToThread.put(cur.getThreadProxy(), cur); + JavaThread jthread = threads.getJavaThreadAt(i); + proxyToThread.put(jthread.getThreadProxy(), jthread); } + return proxyToThread; } private void printUnknown(PrintStream out) { out.println("\t????????"); } - private static record JavaNameInfo(String[] names, Address senderFP, Address senderPC) {}; - - private JavaNameInfo getJavaNames(ThreadProxy th, Address fp) { - if (fp == null) { - return null; - } - JavaVFrame[] jvframes = jframeCache.get(th); - if (jvframes == null) return null; // not a java thread + private static record JavaNameInfo(String[] names, Address senderSP, Address senderFP, Address senderPC) {}; + private JavaNameInfo getJavaNames(JavaThread jthread, CFrame f) { List names = new ArrayList<>(10); - JavaVFrame bottomJVFrame = null; - for (int fCount = 0; fCount < jvframes.length; fCount++) { - JavaVFrame vf = jvframes[fCount]; - Frame f = vf.getFrame(); - if (fp.equals(f.getFP())) { - bottomJVFrame = vf; - StringBuilder sb = new StringBuilder(); - Method method = vf.getMethod(); - // a special char to identify java frames in output - sb.append("* "); - sb.append(method.externalNameAndSignature()); - sb.append(" bci:").append(vf.getBCI()); - int lineNumber = method.getLineNumberFromBCI(vf.getBCI()); - if (lineNumber != -1) { - sb.append(" line:").append(lineNumber); - } - - if (verbose) { - sb.append(" Method*:").append(method.getAddress()); - } - - if (vf.isCompiledFrame()) { - sb.append(" (Compiled frame"); - if (vf.isDeoptimized()) { - sb.append(" [deoptimized]"); - } - } else if (vf.isInterpretedFrame()) { - sb.append(" (Interpreted frame"); - } - if (vf.mayBeImpreciseDbg()) { - sb.append("; information may be imprecise"); - } - sb.append(")"); - names.add(sb.toString()); - } - } - + Address senderSP = null; Address senderFP = null; Address senderPC = null; - if (bottomJVFrame != null) { - Frame senderFrame = bottomJVFrame.getFrame().sender((RegisterMap)bottomJVFrame.getRegisterMap().clone()); + VFrame vf = VFrame.newVFrame(f.toFrame(), jthread.newRegisterMap(true), jthread, true, true); + while (vf != null && vf.isJavaFrame()) { + StringBuilder sb = new StringBuilder(); + Method method = ((JavaVFrame)vf).getMethod(); + // a special char to identify java frames in output + sb.append("* "); + sb.append(method.externalNameAndSignature()); + sb.append(" bci:").append(((JavaVFrame)vf).getBCI()); + int lineNumber = method.getLineNumberFromBCI(((JavaVFrame)vf).getBCI()); + if (lineNumber != -1) { + sb.append(" line:").append(lineNumber); + } + + if (verbose) { + sb.append(" Method*:").append(method.getAddress()); + } + + if (vf.isCompiledFrame()) { + sb.append(" (Compiled frame"); + if (vf.isDeoptimized()) { + sb.append(" [deoptimized]"); + } + } else if (vf.isInterpretedFrame()) { + sb.append(" (Interpreted frame"); + } + if (vf.mayBeImpreciseDbg()) { + sb.append("; information may be imprecise"); + } + sb.append(")"); + names.add(sb.toString()); + + // Keep registers in sender Frame + Frame senderFrame = vf.getFrame() + .sender((RegisterMap)vf.getRegisterMap().clone()); + senderSP = senderFrame.getSP(); senderFP = senderFrame.getFP(); senderPC = senderFrame.getPC(); + + // Get sender VFrame for next stack walking + vf = vf.sender(true); } - return new JavaNameInfo(names.toArray(new String[0]), senderFP, senderPC); + return new JavaNameInfo(names.toArray(new String[0]), senderSP, senderFP, senderPC); } public void setVerbose(boolean verbose) { diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 423bcdecaa8..a51e8aef5ee 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -143,7 +143,6 @@ serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64 serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64 serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64 -serviceability/sa/TestJhsdbJstackMixedWithXComp.java 8371194 linux-x64 serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java index 043a198331e..a26fc4532df 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java @@ -23,6 +23,7 @@ */ import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import jdk.test.lib.JDKToolLauncher; @@ -32,7 +33,7 @@ import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; /** - * @test + * @test id=xcomp * @bug 8370176 * @requires vm.hasSA * @requires os.family == "linux" @@ -40,6 +41,28 @@ import jdk.test.lib.process.OutputAnalyzer; * @library /test/lib * @run driver TestJhsdbJstackMixedWithXComp */ + +/** + * @test id=xcomp-preserve-frame-pointer + * @bug 8370176 + * @requires vm.hasSA + * @requires os.family == "linux" + * @requires os.arch == "amd64" + * @library /test/lib + * @run driver TestJhsdbJstackMixedWithXComp -XX:+PreserveFramePointer + */ + +/** + * @test id=xcomp-disable-tiered-compilation + * @bug 8370176 + * @requires vm.hasSA + * @requires os.family == "linux" + * @requires os.arch == "amd64" + * @library /test/lib + * @run driver TestJhsdbJstackMixedWithXComp -XX:-TieredCompilation + */ + + public class TestJhsdbJstackMixedWithXComp { private static void runJstack(LingeredApp app) throws Exception { @@ -89,8 +112,12 @@ public class TestJhsdbJstackMixedWithXComp { LingeredApp app = null; try { + List jvmOpts = new ArrayList<>(); + jvmOpts.add("-Xcomp"); + jvmOpts.addAll(Arrays.asList(args)); + app = new LingeredAppWithVirtualThread(); - LingeredApp.startApp(app, "-Xcomp"); + LingeredApp.startApp(app, jvmOpts.toArray(new String[0])); System.out.println("Started LingeredApp with pid " + app.getPid()); runJstack(app); System.out.println("Test Completed"); From 6abf7b6f226adb580718a314dc218d87289c80ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Tue, 2 Dec 2025 12:38:16 +0000 Subject: [PATCH 76/81] 8371986: Remove the default value of InitialRAMPercentage Reviewed-by: shade, aboldtch --- src/hotspot/share/gc/shared/gc_globals.hpp | 2 +- src/hotspot/share/runtime/flags/jvmFlag.cpp | 2 +- src/java.base/share/man/java.md | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index e86a8744847..d08e95378f7 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -291,7 +291,7 @@ "size on systems with small physical memory size") \ range(0.0, 100.0) \ \ - product(double, InitialRAMPercentage, 0.2, \ + product(double, InitialRAMPercentage, 0.0, \ "Percentage of real memory used for initial heap size") \ range(0.0, 100.0) \ \ diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 487528c49bd..51517fa49db 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -162,7 +162,7 @@ void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) co // uintx ThresholdTolerance = 10 {product} {default} // size_t TLABSize = 0 {product} {default} // uintx SurvivorRatio = 8 {product} {default} - // double InitialRAMPercentage = 1.562500 {product} {default} + // double InitialRAMPercentage = 0.000000 {product} {default} // ccstr CompileCommandFile = MyFile.cmd {product} {command line} // ccstrlist CompileOnly = Method1 // CompileOnly += Method2 {product} {command line} diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 462baa5a4a0..8517e161e3f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2455,8 +2455,7 @@ Java HotSpot VM. `-XX:InitialRAMPercentage=`*percent* : Sets the initial amount of memory that the JVM will use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount - determined as described in the `-XX:MaxRAM` option. The default value is - 0.2 percent. + determined as described in the `-XX:MaxRAM` option. The following example shows how to set the percentage of the initial amount of memory used for the Java heap: From eecba58c6817dbac129c545604d6286dfdcf951f Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Dec 2025 13:05:46 +0000 Subject: [PATCH 77/81] 8371587: Final mapping lost in ProcSmapsParser::parse_next Reviewed-by: jsjolen, fandreuzzi --- src/hotspot/os/linux/procMapsParser.cpp | 27 +++-- src/hotspot/os/linux/procMapsParser.hpp | 3 +- .../runtime/test_procMapsParser_linux.cpp | 109 ++++++++++++++++++ 3 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp diff --git a/src/hotspot/os/linux/procMapsParser.cpp b/src/hotspot/os/linux/procMapsParser.cpp index 47c5c6cc594..0663cae61f3 100644 --- a/src/hotspot/os/linux/procMapsParser.cpp +++ b/src/hotspot/os/linux/procMapsParser.cpp @@ -50,7 +50,14 @@ ProcSmapsParser::~ProcSmapsParser() { bool ProcSmapsParser::read_line() { _line[0] = '\0'; - return ::fgets(_line, _linelen, _f) != nullptr; + + if (::fgets(_line, _linelen, _f) == nullptr) { + // On error or EOF, ensure deterministic empty buffer + _line[0] = '\0'; + return false; + } else { + return true; + } } bool ProcSmapsParser::is_header_line() { @@ -101,8 +108,6 @@ void ProcSmapsParser::scan_additional_line(ProcSmapsInfo& out) { } } -// Starts or continues parsing. Returns true on success, -// false on EOF or on error. bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) { // Information about a single mapping reaches across several lines. @@ -117,15 +122,13 @@ bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) { assert(is_header_line(), "Not a header line: \"%s\".", _line); scan_header_line(out); - // Now read until we encounter the next header line or EOF or an error. - bool ok = false, stop = false; - do { - ok = read_line(); - stop = !ok || is_header_line(); - if (!stop) { - scan_additional_line(out); + while (true) { + bool ok = read_line(); + if (!ok || is_header_line()) { + break; // EOF or next header } - } while (!stop); + scan_additional_line(out); + } - return ok; + return true; // always return true if a mapping was parsed } diff --git a/src/hotspot/os/linux/procMapsParser.hpp b/src/hotspot/os/linux/procMapsParser.hpp index 06035333b2f..037af91358f 100644 --- a/src/hotspot/os/linux/procMapsParser.hpp +++ b/src/hotspot/os/linux/procMapsParser.hpp @@ -84,8 +84,7 @@ public: ProcSmapsParser(FILE* f); ~ProcSmapsParser(); - // Starts or continues parsing. Returns true on success, - // false on EOF or on error. + // Starts or continues parsing. Returns true iff a mapping was parsed. bool parse_next(ProcSmapsInfo& out); }; diff --git a/test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp b/test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp new file mode 100644 index 00000000000..0177acda49f --- /dev/null +++ b/test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifdef LINUX + +#include "procMapsParser.hpp" +#include "unittest.hpp" + +#include + +TEST(ProcSmapsParserTest, ParseMappings) { + const char* smaps_content = + "7f5a00000000-7f5a00001000 r--p 00000000 00:00 0 [anon]\n" + "Size: 4 kB\n" + "KernelPageSize: 4 kB\n" + "MMUPageSize: 4 kB\n" + "Rss: 0 kB\n" + "Pss: 0 kB\n" + "Shared_Clean: 0 kB\n" + "Shared_Dirty: 0 kB\n" + "Private_Clean: 0 kB\n" + "Private_Dirty: 0 kB\n" + "Referenced: 0 kB\n" + "Anonymous: 0 kB\n" + "LazyFree: 0 kB\n" + "AnonHugePages: 0 kB\n" + "ShmemPmdMapped: 0 kB\n" + "FilePmdMapped: 0 kB\n" + "Shared_Hugetlb: 0 kB\n" + "Private_Hugetlb: 0 kB\n" + "Swap: 0 kB\n" + "SwapPss: 0 kB\n" + "Locked: 0 kB\n" + "THPeligible: 0\n" + "VmFlags: rd mr mw me ac \n" + "7f5a00001000-7f5a00002000 rw-p 00000000 00:00 0 [anon]\n" + "Size: 4 kB\n" + "KernelPageSize: 4 kB\n" + "MMUPageSize: 4 kB\n" + "Rss: 4 kB\n" + "Pss: 4 kB\n" + "Shared_Clean: 0 kB\n" + "Shared_Dirty: 0 kB\n" + "Private_Clean: 0 kB\n" + "Private_Dirty: 4 kB\n" + "Referenced: 4 kB\n" + "Anonymous: 4 kB\n" + "LazyFree: 0 kB\n" + "AnonHugePages: 0 kB\n" + "ShmemPmdMapped: 0 kB\n" + "FilePmdMapped: 0 kB\n" + "Shared_Hugetlb: 0 kB\n" + "Private_Hugetlb: 0 kB\n" + "Swap: 0 kB\n" + "SwapPss: 0 kB\n" + "Locked: 0 kB\n" + "THPeligible: 0\n" + "VmFlags: rd wr mr mw me ac \n"; + + FILE* f = fmemopen((void*)smaps_content, strlen(smaps_content), "r"); + ASSERT_TRUE(f != nullptr); + + ProcSmapsParser parser(f); + ProcSmapsInfo info; + + // First mapping + ASSERT_TRUE(parser.parse_next(info)); + EXPECT_EQ((uintptr_t)info.from, 0x7f5a00000000ULL); + EXPECT_EQ((uintptr_t)info.to, 0x7f5a00001000ULL); + EXPECT_STREQ(info.prot, "r--p"); + EXPECT_TRUE(info.rd); + EXPECT_FALSE(info.wr); + + // Second mapping + ASSERT_TRUE(parser.parse_next(info)); + EXPECT_EQ((uintptr_t)info.from, 0x7f5a00001000ULL); + EXPECT_EQ((uintptr_t)info.to, 0x7f5a00002000ULL); + EXPECT_STREQ(info.prot, "rw-p"); + EXPECT_TRUE(info.rd); + EXPECT_TRUE(info.wr); + + // End of file + ASSERT_FALSE(parser.parse_next(info)); + + fclose(f); +} + +#endif // LINUX From 6c01d3b08862447983b96daaf34a4c62daf54101 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 2 Dec 2025 13:10:37 +0000 Subject: [PATCH 78/81] 8372451: C2 SuperWord: "endless loop" assert. Need to implement proper worklist mechanism Reviewed-by: mhaessig, chagedorn --- src/hotspot/share/opto/vtransform.cpp | 115 ++++++++++++------ src/hotspot/share/opto/vtransform.hpp | 51 ++++++-- .../superword/TestLongReductionChain.java | 85 +++++++++++++ 3 files changed, 207 insertions(+), 44 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index b437d2e6eac..93aefe0d505 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -40,38 +40,76 @@ void VTransformGraph::add_vtnode(VTransformNode* vtnode) { } \ ) -// This is similar to IGVN optimization. But we are a bit lazy, and don't care about -// notification / worklist, since the list of nodes is rather small, and we don't -// expect optimizations that trickle over the whole graph. -void VTransformGraph::optimize(VTransform& vtransform) { - TRACE_OPTIMIZE( tty->print_cr("\nVTransformGraph::optimize"); ) - - bool progress = true; - DEBUG_ONLY(int pass_count = 0;) - while (progress) { - progress = false; - assert(++pass_count < 10, "ensure we do not have endless loops"); - for (int i = 0; i < _vtnodes.length(); i++) { - VTransformNode* vtn = _vtnodes.at(i); - if (!vtn->is_alive()) { continue; } - progress |= vtn->optimize(_vloop_analyzer, vtransform); - - // Nodes that have no use any more are dead. - if (vtn->out_strong_edges() == 0 && - // There are some exceptions: - // 1. Memory phi uses are not modeled, so they appear to have no use here, but must be kept alive. - // 2. Similarly, some stores may not have their memory uses modeled, but need to be kept alive. - // 3. Outer node with strong inputs: is a use after the loop that we must keep alive. - !(vtn->isa_PhiScalar() != nullptr || - vtn->is_load_or_store_in_loop() || - (vtn->isa_Outer() != nullptr && vtn->has_strong_in_edge()))) { - vtn->mark_dead(); - progress = true; - } - } +void VTransformOptimize::worklist_push(VTransformNode* vtn) { + if (!_worklist_set.test_set(vtn->_idx)) { + _worklist.push(vtn); } } +VTransformNode* VTransformOptimize::worklist_pop() { + VTransformNode* vtn = _worklist.pop(); + _worklist_set.remove(vtn->_idx); + return vtn; +} + +void VTransform::optimize() { + NOT_PRODUCT( if (vloop().is_trace_optimization()) { tty->print_cr("\nVTransform::optimize"); } ) + ResourceMark rm; + VTransformOptimize vtoptimize(_vloop_analyzer, *this); + vtoptimize.optimize(); +} + +void VTransformOptimize::optimize() { + // Initialize: push all nodes to worklist. + for (int i = 0; i < _vtransform.graph().vtnodes().length(); i++) { + VTransformNode* vtn = _vtransform.graph().vtnodes().at(i); + worklist_push(vtn); + } + + // We don't want to iterate too many times. We set some arbitrary limit, + // just to catch infinite loops. + DEBUG_ONLY( int allowed_steps = 100 * _worklist.length(); ) + + // Optimize iteratively. + while (_worklist.is_nonempty()) { + VTransformNode* vtn = worklist_pop(); + optimize_step(vtn); + assert(--allowed_steps > 0, "no endless loop"); + } + + DEBUG_ONLY( verify(); ) +} + +#ifdef ASSERT +void VTransformOptimize::verify() { + for (int i = 0; i < _vtransform.graph().vtnodes().length(); i++) { + VTransformNode* vtn = _vtransform.graph().vtnodes().at(i); + assert(!optimize_step(vtn), "Missed optimization during VTransform::optimize for %s", vtn->name()); + assert(_worklist.is_empty(), "vtnode on worklist despite no progress for %s", vtn->name()); + } +} +#endif + +// Return true if (and only if) we made progress. +bool VTransformOptimize::optimize_step(VTransformNode* vtn) { + if (!vtn->is_alive()) { return false; } + bool progress = vtn->optimize(*this); + + // Nodes that have no use any more are dead. + if (vtn->out_strong_edges() == 0 && + // There are some exceptions: + // 1. Memory phi uses are not modeled, so they appear to have no use here, but must be kept alive. + // 2. Similarly, some stores may not have their memory uses modeled, but need to be kept alive. + // 3. Outer node with strong inputs: is a use after the loop that we must keep alive. + !(vtn->isa_PhiScalar() != nullptr || + vtn->is_load_or_store_in_loop() || + (vtn->isa_Outer() != nullptr && vtn->has_strong_in_edge()))) { + vtn->mark_dead(*this); + return true; + } + return progress; +} + // Compute a linearization of the graph. We do this with a reverse-post-order of a DFS. // This only works if the graph is a directed acyclic graph (DAG). The C2 graph, and // the VLoopDependencyGraph are both DAGs, but after introduction of vectors/packs, the @@ -1141,8 +1179,8 @@ VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& appl return VTransformApplyResult::make_vector(vn); } -bool VTransformReductionVectorNode::optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { - return optimize_move_non_strict_order_reductions_out_of_loop(vloop_analyzer, vtransform); +bool VTransformReductionVectorNode::optimize(VTransformOptimize& vtoptimize) { + return optimize_move_non_strict_order_reductions_out_of_loop(vtoptimize); } int VTransformReductionVectorNode::vector_reduction_opcode() const { @@ -1213,7 +1251,7 @@ bool VTransformReductionVectorNode::requires_strict_order() const { // become profitable, since the expensive reduction node is moved // outside the loop, and instead cheaper element-wise vector accumulations // are performed inside the loop. -bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop_preconditions(VTransform& vtransform) { +bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop_preconditions(const VTransform& vtransform) { // We have a phi with a single use. VTransformPhiScalarNode* phi = in_req(1)->isa_PhiScalar(); if (phi == nullptr) { @@ -1260,13 +1298,13 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou current_red->element_basic_type() != bt || current_red->vector_length() != vlen) { TRACE_OPTIMIZE( - tty->print(" Cannot move out of loop, other reduction node does not match:"); + tty->print(" Cannot move out of loop, other reduction node does not match: "); print(); tty->print(" other: "); if (current_red != nullptr) { current_red->print(); } else { - tty->print("nullptr"); + tty->print_cr("nullptr"); } ) return false; // not compatible @@ -1314,7 +1352,8 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou return true; // success } -bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { +bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop(VTransformOptimize& vtoptimize) { + VTransform& vtransform = vtoptimize.vtransform(); if (!optimize_move_non_strict_order_reductions_out_of_loop_preconditions(vtransform)) { return false; } @@ -1328,7 +1367,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou const uint vlen = vector_length(); const BasicType bt = element_basic_type(); const int vopc = VectorNode::opcode(sopc, bt); - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + PhaseIdealLoop* phase = vtoptimize.vloop_analyzer().vloop().phase(); // Create a vector of identity values. Node* identity = ReductionNode::make_identity_con_scalar(phase->igvn(), sopc, bt); @@ -1341,6 +1380,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou // Look at old scalar phi. VTransformPhiScalarNode* phi_scalar = in_req(1)->isa_PhiScalar(); PhiNode* old_phi = phi_scalar->node(); + vtoptimize.worklist_push(phi_scalar); VTransformNode* init = phi_scalar->in_req(1); TRACE_OPTIMIZE( @@ -1354,6 +1394,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou phi_vector->init_req(0, phi_scalar->in_req(0)); phi_vector->init_req(1, vtn_identity_vector); // Note: backedge comes later + vtoptimize.worklist_push(phi_vector); // Traverse down the chain of reductions, and replace them with vector_accumulators. VTransformReductionVectorNode* first_red = this; @@ -1365,6 +1406,8 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou VTransformVectorNode* vector_accumulator = new (vtransform.arena()) VTransformElementWiseVectorNode(vtransform, 3, current_red->properties(), vopc); vector_accumulator->init_req(1, current_vector_accumulator); vector_accumulator->init_req(2, vector_input); + vtoptimize.worklist_push(current_red); + vtoptimize.worklist_push(vector_accumulator); TRACE_OPTIMIZE( tty->print(" replace "); current_red->print(); diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index a3e4977494e..b60c71945e1 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -24,6 +24,7 @@ #ifndef SHARE_OPTO_VTRANSFORM_HPP #define SHARE_OPTO_VTRANSFORM_HPP +#include "libadt/vectset.hpp" #include "opto/node.hpp" #include "opto/vectorization.hpp" #include "opto/vectornode.hpp" @@ -192,7 +193,6 @@ public: const GrowableArray& vtnodes() const { return _vtnodes; } const GrowableArray& get_schedule() const { return _schedule; } - void optimize(VTransform& vtransform); bool schedule(); bool has_store_to_load_forwarding_failure(const VLoopAnalyzer& vloop_analyzer) const; float cost_for_vector_loop() const; @@ -257,7 +257,7 @@ public: DEBUG_ONLY( bool has_graph() const { return !_graph.is_empty(); } ) VTransformGraph& graph() { return _graph; } - void optimize() { return _graph.optimize(*this); } + void optimize(); bool schedule() { return _graph.schedule(); } bool is_profitable() const; float cost_for_vector_loop() const { return _graph.cost_for_vector_loop(); } @@ -291,6 +291,36 @@ private: void apply_vectorization() const; }; +// We keep track of the worklist during optimizations. +// The concept is somewhat parallel to IGVN: we keep on +// optimizing vtnodes on the worklist, which may in turn +// add more nodes to the list. We keep on optimizing until +// no more nodes are on the worklist. +class VTransformOptimize : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + VTransform& _vtransform; + + GrowableArray _worklist; + VectorSet _worklist_set; + +public: + VTransformOptimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) : + _vloop_analyzer(vloop_analyzer), + _vtransform(vtransform) {} + + const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; } + VTransform& vtransform() { return _vtransform; } + + void worklist_push(VTransformNode* vtn); + void optimize(); + +private: + VTransformNode* worklist_pop(); + bool optimize_step(VTransformNode* vtn); + DEBUG_ONLY( void verify(); ) +}; + // Keeps track of the state during "VTransform::apply" // -> keep track of the already transformed nodes and the memory state. class VTransformApplyState : public StackObj { @@ -531,10 +561,15 @@ public: bool is_alive() const { return _is_alive; } - void mark_dead() { + void mark_dead(VTransformOptimize& vtoptimize) { _is_alive = false; - // Remove all inputs + // Remove all inputs, and put inputs on worklist in + // case they are also dead. for (uint i = 0; i < req(); i++) { + VTransformNode* in = in_req(i); + if (in != nullptr) { + vtoptimize.worklist_push(in); + } set_req(i, nullptr); } } @@ -558,7 +593,7 @@ public: virtual const VPointer& vpointer() const { ShouldNotReachHere(); } virtual bool is_loop_head_phi() const { return false; } - virtual bool optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { return false; } + virtual bool optimize(VTransformOptimize& vtoptimize) { return false; } virtual float cost(const VLoopAnalyzer& vloop_analyzer) const = 0; @@ -868,7 +903,7 @@ public: VTransformReductionVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : VTransformVectorNode(vtransform, 3, properties) {} virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; } - virtual bool optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) override; + virtual bool optimize(VTransformOptimize& vtoptimize) override; virtual float cost(const VLoopAnalyzer& vloop_analyzer) const override; virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) @@ -876,8 +911,8 @@ public: private: int vector_reduction_opcode() const; bool requires_strict_order() const; - bool optimize_move_non_strict_order_reductions_out_of_loop_preconditions(VTransform& vtransform); - bool optimize_move_non_strict_order_reductions_out_of_loop(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform); + bool optimize_move_non_strict_order_reductions_out_of_loop_preconditions(const VTransform& vtransform); + bool optimize_move_non_strict_order_reductions_out_of_loop(VTransformOptimize& vtoptimize); }; class VTransformPhiVectorNode : public VTransformVectorNode { diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java new file mode 100644 index 00000000000..37dd964048f --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.superword; + +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @bug 8372451 + * @summary Test long reduction chain. Triggered bug with long chain of dead ReductionVector + * vtnodes after optimize_move_non_strict_order_reductions_out_of_loop. + * @library /test/lib / + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=1000 -XX:MaxVectorSize=8 -Xbatch + * -XX:CompileCommand=compileonly,${test.main.class}::test + * ${test.main.class} + * @run main ${test.main.class} + */ + +public class TestLongReductionChain { + static int RANGE = 1024*8; + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + int[] aI = generateI(); + int[] bI = generateI(); + int gold = test(aI, bI); + + for (int i = 0; i < 1000; i++) { + int result = test(aI, bI); + if (result != gold) { + throw new RuntimeException("wrong value"); + } + } + } + + static int[] generateI() { + int[] a = new int[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = RANDOM.nextInt(); + } + return a; + } + + // Test creates a very long reduction chain, especially with -XX:LoopUnrollLimit=1000. + // Limiting the reduction vectors to 2 elements gets us a very long chain -XX:MaxVectorSize=8. + // During VTransform::optimize this means a long chain of nodes needs to be found as dead. + // Before the fix, this took too many rounds, and we hit an assert. + static int test(int[] a, int[] b) { + int s = 0; + for (int i = 0; i < RANGE; i+=8) { + s += a[i+0] * b[i+0]; + s += a[i+1] * b[i+1]; + s += a[i+2] * b[i+2]; + s += a[i+3] * b[i+3]; + + s += a[i+4] & b[i+4]; + s += a[i+5] & b[i+5]; + s += a[i+6] & b[i+6]; + s += a[i+7] & b[i+7]; + } + return s; + } +} From c97d53a9529d9148aacd85a3b31d694f04df0758 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Tue, 2 Dec 2025 13:32:22 +0000 Subject: [PATCH 79/81] 8371470: Java Launcher does not fail when running compact java-file with private no-arg constructor Reviewed-by: jpai --- .../tools/javac/launcher/SourceLauncher.java | 6 ++++ .../tools/javac/resources/launcher.properties | 6 ++++ .../javac/launcher/SourceLauncherTest.java | 35 +++++++++++++------ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java index 4d679403ee7..af7d79d4195 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java @@ -226,6 +226,8 @@ public final class SourceLauncher { Object instance = null; + // Similar to sun.launcher.LauncherHelper#checkAndLoadMain, including + // checks performed in LauncherHelper#validateMainMethod if (!isStatic) { if (Modifier.isAbstract(mainClass.getModifiers())) { throw new Fault(Errors.CantInstantiate(mainClassName)); @@ -238,6 +240,10 @@ public final class SourceLauncher { throw new Fault(Errors.CantFindConstructor(mainClassName)); } + if (Modifier.isPrivate(constructor.getModifiers())) { + throw new Fault(Errors.CantUsePrivateConstructor(mainClassName)); + } + try { constructor.setAccessible(true); instance = constructor.newInstance(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties index 122e5dca80d..36d50afad0f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties @@ -124,6 +124,12 @@ launcher.err.cant.access.main.method=\ launcher.err.cant.find.constructor=\ can''t find no argument constructor in class: {0} +# 0: string +launcher.err.cant.use.private.constructor=\ + no non-private zero argument constructor found in class {0}\n\ + remove private from existing constructor or define as:\n\ +\ public {0}() + # 0: string launcher.err.cant.access.constructor=\ can''t access no argument constructor in class: {0} diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 6b147d32d00..37d50674855 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -798,6 +798,22 @@ public class SourceLauncherTest extends TestRunner { } } + @Test + public void testPrivateConstructor(Path base) throws IOException { + tb.writeJavaFiles(base, + """ + class PrivateConstructor { + private PrivateConstructor() {} + void main() {} + } + """); + testError(base.resolve("PrivateConstructor.java"), "", + """ + error: no non-private zero argument constructor found in class PrivateConstructor + remove private from existing constructor or define as: + public PrivateConstructor()"""); + } + @Test public void testAbstractClassInstanceMain(Path base) throws IOException { tb.writeJavaFiles(base, @@ -904,14 +920,6 @@ public class SourceLauncherTest extends TestRunner { } } - void checkContains(String name, String found, String expect) { - expect = expect.replace("\n", tb.lineSeparator); - out.println(name + ": " + found); - if (!found.contains(expect)) { - error("Expected output not found: " + expect); - } - } - void checkEqual(String name, List found, List expect) { out.println(name + ": " + found); tb.checkEqual(expect, found); @@ -939,7 +947,6 @@ public class SourceLauncherTest extends TestRunner { } void checkFault(String name, Throwable found, String expect) { - expect = expect.replace("\n", tb.lineSeparator); out.println(name + ": " + found); if (found == null) { error("No exception thrown; expected Fault"); @@ -947,8 +954,14 @@ public class SourceLauncherTest extends TestRunner { if (!(found instanceof Fault)) { error("Unexpected exception; expected Fault"); } - if (!(found.getMessage().equals(expect))) { - error("Unexpected detail message; expected: " + expect); + String actual = found.getMessage(); + List actualLines = actual.lines().toList(); + List expectLines = expect.lines().toList(); + if (!(actualLines.equals(expectLines))) { + error("Unexpected detail message; expected: \n" + + expect.indent(2) + + "\nactual:\n" + + actual.indent(2)); } } } From 6f2169ff6996e0629ce80455959a21947fd5de2c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 2 Dec 2025 13:55:45 +0000 Subject: [PATCH 80/81] 8372755: Remove local suppression of VS C4146 warnings Reviewed-by: ayang --- src/hotspot/os/windows/sharedRuntimeRem.cpp | 4 +--- src/hotspot/share/runtime/atomicAccess.hpp | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/hotspot/os/windows/sharedRuntimeRem.cpp b/src/hotspot/os/windows/sharedRuntimeRem.cpp index aae93f701ec..fbcf68a5940 100644 --- a/src/hotspot/os/windows/sharedRuntimeRem.cpp +++ b/src/hotspot/os/windows/sharedRuntimeRem.cpp @@ -50,11 +50,9 @@ double SharedRuntime::fmod_winx64(double x, double y) hx ^= sx; /* |x| */ hy &= 0x7fffffff; /* |y| */ -#pragma warning( disable : 4146 ) /* purge off exception values */ if ((hy | ly) == 0 || (hx >= 0x7ff00000) || /* y=0,or x not finite */ - ((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */ -#pragma warning( default : 4146 ) + ((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */ return (x*y) / (x*y); if (hx <= hy) { if ((hx::value || std::is_integral::value); using I = std::conditional_t::value, ptrdiff_t, D>; // Assumes two's complement integer representation. - #pragma warning(suppress: 4146) AtomicAccess::add(dest, I(-1), order); } @@ -652,7 +651,6 @@ inline D AtomicAccess::sub(D volatile* dest, I sub_value, atomic_memory_order or STATIC_ASSERT(sizeof(I) <= sizeof(AddendType)); AddendType addend = sub_value; // Assumes two's complement integer representation. - #pragma warning(suppress: 4146) // In case AddendType is not signed. return AtomicAccess::add(dest, -addend, order); } From a62296d8a0858d63a930e91168254a9927f06783 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 2 Dec 2025 14:00:21 +0000 Subject: [PATCH 81/81] 8371464: C2: assert(no_dead_loop) failed: dead loop detected Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/cfgnode.cpp | 13 +-- src/hotspot/share/opto/cfgnode.hpp | 2 +- .../compiler/c2/TestDeadLoopAtMergeMem.java | 83 +++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 0293f42d791..0598f10b880 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -326,7 +326,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) { // First, cut the simple case of fallthrough region when NONE of // region's phis references itself directly or through a data node. - if (is_possible_unsafe_loop(phase)) { + if (is_possible_unsafe_loop()) { // If we have a possible unsafe loop, check if the region node is actually unreachable from root. if (is_unreachable_from_root(phase)) { _is_unreachable_region = true; @@ -336,7 +336,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) { return false; } -bool RegionNode::is_possible_unsafe_loop(const PhaseGVN* phase) const { +bool RegionNode::is_possible_unsafe_loop() const { uint max = outcnt(); uint i; for (i = 0; i < max; i++) { @@ -634,8 +634,8 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { } } else if (can_reshape && cnt == 1) { // Is it dead loop? - // If it is LoopNopde it had 2 (+1 itself) inputs and - // one of them was cut. The loop is dead if it was EntryContol. + // If it is LoopNode it had 2 (+1 itself) inputs and + // one of them was cut. The loop is dead if it was EntryControl. // Loop node may have only one input because entry path // is removed in PhaseIdealLoop::Dominators(). assert(!this->is_Loop() || cnt_orig <= 3, "Loop node should have 3 or less inputs"); @@ -1392,7 +1392,7 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) { } assert(is_diamond_phi() > 0, "sanity"); assert(req() == 3, "same as region"); - const Node* region = in(0); + RegionNode* region = in(0)->as_Region(); for (uint i = 1; i < 3; i++) { Node* phi_input = in(i); if (phi_input != nullptr && phi_input->is_MergeMem() && region->in(i)->outcnt() == 1) { @@ -1400,8 +1400,9 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) { MergeMemNode* merge_mem = phi_input->as_MergeMem(); uint j = 3 - i; Node* other_phi_input = in(j); - if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory()) { + if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory() && !is_data_loop(region, phi_input, igvn)) { // merge_mem is a successor memory to other_phi_input, and is not pinned inside the diamond, so push it out. + // Only proceed if the transformation doesn't create a data loop // This will allow the diamond to collapse completely if there are no other phis left. igvn->replace_node(this, merge_mem); return true; diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 78ad085e03d..bc0b38e2f97 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -84,7 +84,7 @@ private: bool _is_unreachable_region; LoopStatus _loop_status; - bool is_possible_unsafe_loop(const PhaseGVN* phase) const; + bool is_possible_unsafe_loop() const; bool is_unreachable_from_root(const PhaseGVN* phase) const; public: // Node layout (parallels PhiNode): diff --git a/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java b/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java new file mode 100644 index 00000000000..5c4dcc76a76 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 IBM Corporation. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8371464 + * @summary C2: assert(no_dead_loop) failed: dead loop detected + * @run main/othervm -Xcomp -XX:CompileOnly=TestDeadLoopAtMergeMem::test TestDeadLoopAtMergeMem + * @run main TestDeadLoopAtMergeMem + */ + +public class TestDeadLoopAtMergeMem { + static final int N = 400; + static long instanceCount; + boolean bFld; + float fArrFld[]; + static int iArrFld[] = new int[N]; + long vMeth_check_sum; + + public static void main(String[] strArr) { + TestDeadLoopAtMergeMem r = new TestDeadLoopAtMergeMem(); + for (int i = 0; i < 1000; i++) { + r.test((short) 0, instanceCount); + } + } + + void test(short s, long l) { + int i11 = 6, i12, i13 = 6, i14 = 2; + byte byArr2[] = new byte[N]; + init(byArr2, (byte) 4); + helper(66.118169, i11); + for (i12 = 3; i12 < 23; i12++) { + if (bFld) { + instanceCount = 5; + } else if (bFld) { + fArrFld[i12] = s; + do { + try { + i11 = i13 / i12 % i12; + } catch (ArithmeticException a_e) { + } + } while (i14 < 8); + } + } + for (int i15 : iArrFld) { + try { + i11 = 1 / i15; + } catch (ArithmeticException a_e) { + } + } + vMeth_check_sum += i11; + } + + void helper(double d, int i) { + int i1[] = new int[N]; + } + + public static void init(byte[] a, byte seed) { + for (int j = 0; j < a.length; j++) { + a[j] = (byte) ((j % 2 == 0) ? seed + j : seed - j); + } + } +}