From 9fb3d591f52ad5cbd1e885f698248e9ed33cecce Mon Sep 17 00:00:00 2001
From: Roland Westrelin
Date: Thu, 1 Oct 2026 06:38:01 +0000
Subject: [PATCH 01/98] 8385993: C2: Incorrect escape analysis in reduce
allocation merges causes NPE
Reviewed-by: cslucas, qamai
---
src/hotspot/share/opto/escape.cpp | 125 +++++++++--
src/hotspot/share/opto/escape.hpp | 3 +
.../TestReduceAllocationClonedCast.java | 204 ++++++++++++++++++
3 files changed, 310 insertions(+), 22 deletions(-)
create mode 100644 test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationClonedCast.java
diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp
index 858bb657802..776aba1ff1c 100644
--- a/src/hotspot/share/opto/escape.cpp
+++ b/src/hotspot/share/opto/escape.cpp
@@ -1127,6 +1127,24 @@ void ConnectionGraph::updates_after_load_split(Node* data_phi, Node* previous_lo
}
Node* base = get_addp_base(new_addp);
+ if (base->Opcode() == Op_CastPP) {
+ Node* previous_base = get_addp_base(previous_addp);
+ if (previous_base->Opcode() == Op_CastPP && (base->_idx >= nodes_size() || ptnode_adr(base->_idx) == nullptr)) {
+ assert(previous_base != base, "Should have been pushed through Phi");
+ // add the CastPP to the connection graph
+ _nodes.at_grow(base->_idx, nullptr);
+ PointsToNode* curr_castpp_ptn = ptnode_adr(previous_base->_idx);
+ add_local_var(base, curr_castpp_ptn->escape_state());
+ add_edge(ptnode_adr(base->_idx), ptnode_adr(base->in(1)->_idx));
+ JavaObjectNode* java_object = unique_java_object(base->in(1));
+ if (java_object != nullptr) {
+ add_edge(ptnode_adr(base->_idx), java_object);
+ }
+ base = base->in(1);
+ assert(previous_base->in(1)->as_Phi()->in(i) == base, "an input to the cast was cloned");
+ }
+ }
+
// The base might not be something that we can create an unique
// type for. If that's the case we are done with that input.
PointsToNode* jobj_ptn = unique_java_object(base);
@@ -4330,7 +4348,22 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base) {
// for the instance type. Note: C++ will not remove it since the call
// has side effect.
int alias_idx = _compile->get_alias_index(tinst);
- igvn->set_type(addp, tinst);
+ if (igvn->type(addp)->isa_oopptr()) {
+ igvn->set_type(addp, tinst);
+ } else {
+ // Captured stores should remain raw memory stores
+#ifdef ASSERT
+ InitializeNode* init = base->in(0)->in(0)->as_Initialize();
+ bool found = false;
+ for (uint i = InitializeNode::RawStores; i < init->req(); i++) {
+ Node* st = init->in(i);
+ if (st->is_Store() && st->in(MemNode::Address) == addp) {
+ found = true;
+ }
+ }
+ assert(found, "expected AddP from captured store");
+#endif
+ }
// record the allocation in the node map
set_map(addp, get_map(base->_idx));
// Set addp's Base and Address to 'base'.
@@ -4796,6 +4829,74 @@ Node* ConnectionGraph::find_inst_mem(Node* orig_mem, int alias_idx, Unique_Node_
return result;
}
+#ifdef ASSERT
+void ConnectionGraph::verify_ram_after_reduce_phi(const Unique_Node_List &reducible_merges, const Unique_Node_List& reduced_merges) {
+ if (VerifyReduceAllocationMerges) {
+ {
+ // Checks that nodes added by reduce_phi() were properly added to the connection graph
+ ResourceMark rm;
+ Unique_Node_List wq;
+ wq.push(_compile->root());
+ for (uint i = 0; i < wq.size(); ++i) {
+ Node* n = wq.at(i);
+ Node* base = nullptr;
+ switch (n->Opcode()) {
+ case Op_CastPP:
+ base = n->in(1);
+ while (base->Opcode() == Op_CastPP) {
+ base = base->in(1);
+ }
+ if (base->is_AddP()) {
+ // LibraryCallKit::inline_unsafe_flat_access() inserts a CastPP with an AddP input
+ base = get_addp_base(base);
+ }
+ break;
+ case Op_AddP:
+ base = get_addp_base(n);
+ break;
+ case Op_LoadP:
+ case Op_LoadN: {
+ Node* adr = n->in(MemNode::Address);
+ if (adr->is_AddP()) {
+ base = get_addp_base(adr);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ assert(base == nullptr || unique_java_object(base) == nullptr || !unique_java_object(base)->scalar_replaceable() ||
+ (n->_idx < nodes_size() && ptnode_adr(n->_idx) != nullptr), "missing node");
+ for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) {
+ Node* u = n->fast_out(j);
+ wq.push(u);
+ }
+ }
+ }
+
+ for (uint i = 0; i < reducible_merges.size(); i++) {
+ Node* phi = reducible_merges.at(i);
+
+ if (!reduced_merges.member(phi)) {
+ phi->dump(2);
+ phi->dump(-2);
+ assert(false, "This reducible merge wasn't reduced.");
+ }
+
+ // At this point reducible Phis shouldn't have AddP users anymore; only SafePoints or Casts.
+ for (DUIterator_Fast jmax, j = phi->fast_outs(jmax); j < jmax; j++) {
+ Node* use = phi->fast_out(j);
+ if (!use->is_SafePoint() && !use->is_CastPP()) {
+ phi->dump(2);
+ phi->dump(-2);
+ assert(false, "Unexpected user of reducible Phi -> %d:%s:%d", use->_idx, use->Name(), use->outcnt());
+ }
+ }
+ }
+ }
+}
+#endif
+
Node* ConnectionGraph::find_inst_mem_assert_no_new_node(Node* orig_mem, int alias_idx, Unique_Node_List& orig_phis) {
uint orig_uniq = _compile->unique();
Node* result = find_inst_mem(orig_mem, alias_idx, orig_phis);
@@ -5222,27 +5323,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist,
}
#ifdef ASSERT
- if (VerifyReduceAllocationMerges) {
- for (uint i = 0; i < reducible_merges.size(); i++) {
- Node* phi = reducible_merges.at(i);
-
- if (!reduced_merges.member(phi)) {
- phi->dump(2);
- phi->dump(-2);
- assert(false, "This reducible merge wasn't reduced.");
- }
-
- // At this point reducible Phis shouldn't have AddP users anymore; only SafePoints or Casts.
- for (DUIterator_Fast jmax, j = phi->fast_outs(jmax); j < jmax; j++) {
- Node* use = phi->fast_out(j);
- if (!use->is_SafePoint() && !use->is_CastPP()) {
- phi->dump(2);
- phi->dump(-2);
- assert(false, "Unexpected user of reducible Phi -> %d:%s:%d", use->_idx, use->Name(), use->outcnt());
- }
- }
- }
- }
+ verify_ram_after_reduce_phi(reducible_merges, reduced_merges);
#endif
// Go over all ArrayCopy nodes and if one of the inputs has a unique
diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp
index 44f2d6aaa69..aedfaa2810d 100644
--- a/src/hotspot/share/opto/escape.hpp
+++ b/src/hotspot/share/opto/escape.hpp
@@ -628,6 +628,9 @@ class ConnectionGraph: public ArenaObj {
bool reduce_phi_on_safepoints(PhiNode* ophi);
bool reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, Node* selector, Unique_Node_List& safepoints);
void reduce_phi(PhiNode* ophi, GrowableArray &alloc_worklist);
+#ifdef ASSERT
+ void verify_ram_after_reduce_phi(const Unique_Node_List &reducible_merges, const Unique_Node_List& reduced_merges);
+#endif
void set_not_scalar_replaceable(PointsToNode* ptn NOT_PRODUCT(COMMA const char* reason)) const {
#ifndef PRODUCT
diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationClonedCast.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationClonedCast.java
new file mode 100644
index 00000000000..8f7b711eab4
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationClonedCast.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * @test
+ * @bug 8385993
+ * @summary C2: Incorrect escape analysis in reduce allocation merges causes NPE
+ * @library /test/lib
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-UseDeepIGVNRevisit -XX:+UnlockDiagnosticVMOptions
+ * -XX:+StressIGVN -XX:StressSeed=30740779 -XX:CompileCommand=compileonly,${test.main.class}::* ${test.main.class}
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-UseDeepIGVNRevisit -XX:+UnlockDiagnosticVMOptions
+ * -XX:+StressIGVN -XX:StressSeed=42701780 -XX:CompileCommand=compileonly,${test.main.class}::* ${test.main.class}
+ * @run main ${test.main.class}
+ */
+
+package compiler.escapeAnalysis;
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+import java.io.IOException;
+
+public class TestReduceAllocationClonedCast {
+ public static void main(String[] args) throws IOException {
+ for (int i = 0; i < 8_000; i++) {
+ test1();
+ test2();
+ test3(true, true);
+ test3(false, false);
+ test3(false, true);
+ test4(true, true);
+ test4(false, false);
+ test4(false, true);
+ }
+ System.out.println("DONE");
+ }
+
+ static int test1() {
+ int val = 0;
+ A1 a = getA1(Integer.valueOf(14));
+ if (a != null) {
+ val += a.getA1();
+ }
+ return val;
+ }
+
+ static int test2() {
+ int val = 0;
+ A2 a = getA2(Integer.valueOf(14));
+ if (a != null) {
+ val += a.getA1();
+ }
+ return val;
+ }
+
+ static A1 getA1(Object obj) {
+ java.util.Random rnd = new java.util.Random();
+ int rndInt= rnd.nextInt(100);
+ if (rndInt < 15) {
+ return null;
+ }
+
+ A1 retA = new A1(rndInt);
+ if (obj != null) {
+ B1 b = new B1(retA);
+ retA = b.getAFromB(obj);
+ }
+
+ return retA;
+ }
+
+ static A2 getA2(Object obj) {
+ java.util.Random rnd = new java.util.Random();
+ int rndInt= rnd.nextInt(100);
+ if (rndInt < 15) {
+ return null;
+ }
+
+ A2 retA = new A2(rndInt, rnd.nextInt(100), rnd.nextInt(100));
+ if (obj != null) {
+ B2 b = new B2(retA);
+ retA = b.getAFromB(obj);
+ }
+
+ return retA;
+ }
+
+ static A fieldA = new A(42);
+ static int field;
+
+ static int test3(boolean flag, boolean flag2) {
+ A a = null;
+ if (flag) {
+ a = new A(42);
+ } else {
+ a = fieldA;
+ if (flag2) {
+ if (a == null) {
+ throw new RuntimeException("not taken");
+ }
+ }
+ field = 42;
+ }
+ return a.field;
+ }
+
+ static int test4(boolean flag, boolean flag2) {
+ A a = null;
+ if (flag) {
+ a = new A(42);
+ } else {
+ a = fieldA;
+ if (flag2) {
+ if (a == null) {
+ throw new RuntimeException("not taken");
+ }
+ }
+ }
+ return a.field;
+ }
+
+ static class A {
+ int field;
+
+ A(int v) {
+ field = v;
+ }
+
+ }
+
+
+ static class A1 {
+ final Integer a1;
+
+ A1(int a1) {
+ this.a1 = a1;
+ }
+
+ int getA1() {
+ return a1.intValue();
+ }
+
+ }
+
+ static class A2 {
+ final Integer a1;
+ final int a2;
+ final long a3;
+
+ A2(int a1, int a2, long a3) {
+ this.a1 = a1;
+ this.a2 = a2;
+ this.a3 = a3;
+ }
+
+ int getA1() {
+ return a1.intValue();
+ }
+
+ }
+
+ static class B1 {
+ final A1 a;
+ B1(A1 a) {
+ this.a = a;
+ }
+
+ A1 getAFromB(Object obj) {
+ return a;
+ }
+ }
+
+ static class B2 {
+ final A2 a;
+ B2(A2 a) {
+ this.a = a;
+ }
+
+ A2 getAFromB(Object obj) {
+ return a;
+ }
+ }
+}
From 10a0e008c05a89ebd35d992ecab0f69b2c0d7f1f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?=
Date: Thu, 1 Oct 2026 06:48:51 +0000
Subject: [PATCH 02/98] 8392337: [Valhalla] C2: incorrect escape analysis for
mismatching scalarization of value argument and return
Reviewed-by: qamai, roland, thartmann
---
src/hotspot/share/opto/escape.cpp | 39 ++-
src/hotspot/share/opto/escape.hpp | 7 +-
.../valuetypes/TestReturnValueArgument.java | 280 ++++++++++++++++++
3 files changed, 312 insertions(+), 14 deletions(-)
create mode 100644 test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnValueArgument.java
diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp
index 776aba1ff1c..2796f7c908c 100644
--- a/src/hotspot/share/opto/escape.cpp
+++ b/src/hotspot/share/opto/escape.cpp
@@ -1647,10 +1647,11 @@ void ConnectionGraph::add_proj(Node* n, Unique_Node_List* delayed_worklist) {
} else if (n->as_Proj()->_con >= TypeFunc::Parms && n->in(0)->is_Call() && n->bottom_type()->isa_ptr()) {
CallNode* call = n->in(0)->as_Call();
assert(call->tf()->returns_value_type_as_fields(), "");
- if (n->as_Proj()->_con == TypeFunc::Parms || !returns_an_argument(call)) {
+ if (n->as_Proj()->_con == TypeFunc::Parms || !returns_an_argument(call) || has_incompatible_argument_return(call)) {
// either:
// - not an argument returned
// - the returned buffer for a returned scalarized argument
+ // - incompatible returned argument
add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), delayed_worklist);
} else {
add_local_var(n, PointsToNode::NoEscape);
@@ -2284,16 +2285,26 @@ class DomainIterator : public StackObj {
}
};
-// Determine whether any arguments are returned.
-bool ConnectionGraph::returns_an_argument(CallNode* call) {
+bool ConnectionGraph::returns_an_argument(const CallNode* call) {
ciMethod* meth = call->as_CallJava()->method();
+ assert(meth != nullptr, "call must have an associated method pointer");
BCEscapeAnalyzer* call_analyzer = meth->get_bcea();
- if (call_analyzer == nullptr) {
- return false;
+ const TypeTuple* d = call->tf()->domain_sig();
+ for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
+ const Type* t = d->field_at(i);
+ if (t->isa_ptr() != nullptr &&
+ call_analyzer->is_arg_returned(i - TypeFunc::Parms)) {
+ return true;
+ }
}
+ return false;
+}
+bool ConnectionGraph::has_incompatible_argument_return(const CallNode* call) {
+ ciMethod* meth = call->as_CallJava()->method();
+ assert(meth != nullptr, "call must have an associated method pointer");
+ BCEscapeAnalyzer* call_analyzer = meth->get_bcea();
const TypeTuple* d = call->tf()->domain_sig();
- bool ret_arg = false;
int arg_num = 0;
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
const Type* t = d->field_at(i);
@@ -2301,19 +2312,18 @@ bool ConnectionGraph::returns_an_argument(CallNode* call) {
call_analyzer->is_arg_returned(i - TypeFunc::Parms)) {
const bool scalarized_arg = meth->is_scalarized_arg(arg_num);
if (scalarized_arg && !compatible_return(call->as_CallJava(), i)) {
- return false;
+ return true;
}
if (call->tf()->returns_value_type_as_fields() != scalarized_arg) {
- return false;
+ return true;
}
- ret_arg = true;
}
if (t != Type::HALF) {
arg_num++;
}
}
assert(arg_num == meth->signature()->count() + (meth->is_static() ? 0 : 1), "inconsistent argument count");
- return ret_arg;
+ return false;
}
void ConnectionGraph::add_call_node(CallNode* call) {
@@ -2430,7 +2440,9 @@ void ConnectionGraph::add_call_node(CallNode* call) {
// For scalarized argument/return: process_call_arguments() adds an edge between a call projection for a field
// and the argument input to the call for that field. An edge is added between the projection for the returned
// buffer and the call.
- if (returns_an_argument(call) && !call->tf()->returns_value_type_as_fields()) {
+ // For incompatible argument/return (only one of them is scalarized, or their types do not match): the call is
+ // conservatively assumed to make all its oop arguments escape globally and return an unknown object.
+ if (returns_an_argument(call) && !has_incompatible_argument_return(call) && !call->tf()->returns_value_type_as_fields()) {
// returns non scalarized argument
add_local_var(call, PointsToNode::ArgEscape);
} else {
@@ -2639,8 +2651,9 @@ void ConnectionGraph::process_call_arguments(CallNode *call) {
break; // Boxing methods do not modify any oops.
}
BCEscapeAnalyzer* call_analyzer = (meth !=nullptr) ? meth->get_bcea() : nullptr;
- // fall-through if not a Java method or no analyzer information
- if (call_analyzer != nullptr) {
+ // Fall-through if not a Java method, no analyzer information, or
+ // incompatible argument returns.
+ if (call_analyzer != nullptr && !has_incompatible_argument_return(call)) {
PointsToNode* call_ptn = ptnode_adr(call->_idx);
bool ret_arg = returns_an_argument(call);
for (DomainIterator di(call->as_CallJava()); di.has_next(); di.next()) {
diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp
index aedfaa2810d..dfa21836ec5 100644
--- a/src/hotspot/share/opto/escape.hpp
+++ b/src/hotspot/share/opto/escape.hpp
@@ -372,7 +372,12 @@ class ConnectionGraph: public ArenaObj {
// Compute the escape state for arguments to a call.
void process_call_arguments(CallNode *call);
- bool returns_an_argument(CallNode* call);
+ // Whether a call returns one of its arguments, according to BCEA.
+ bool returns_an_argument(const CallNode* call);
+
+ // Whether a call's returned argument cannot be connected due to scalarization
+ // or type mismatches.
+ bool has_incompatible_argument_return(const CallNode* call);
// Add PointsToNode node corresponding to a call
void add_call_node(CallNode* call);
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnValueArgument.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnValueArgument.java
new file mode 100644
index 00000000000..5e9c7a0c86b
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnValueArgument.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package compiler.valhalla.valuetypes;
+
+import compiler.lib.ir_framework.*;
+
+/**
+ * @test
+ * @bug 8392337
+ * @summary Test that C2 propagates escape state correctly for returned
+ * arguments in non-inlined calls for different scalarization choices.
+ * @library /test/lib /
+ * @enablePreview
+ * @run driver ${test.main.class}
+ */
+
+class TestReturnValueArgument {
+
+ public static void main(String[] args) {
+ TestFramework framework = new TestFramework();
+ Scenario[] scenarios = new Scenario[2*2];
+ int scenarioIndex = 0;
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ scenarios[scenarioIndex] =
+ new Scenario(scenarioIndex,
+ "--enable-preview",
+ "-XX:" + (i == 0 ? "-" : "+") + "ValueTypePassFieldsAsArgs",
+ "-XX:" + (j == 0 ? "-" : "+") + "ValueTypeReturnedAsFields");
+ scenarioIndex++;
+ }
+ }
+ framework.addScenarios(scenarios);
+ framework.start();
+ }
+
+ static class IdentityObject {
+ int val;
+ }
+
+ static value class ValueHolder {
+ IdentityObject obj;
+ ValueHolder(IdentityObject obj) {
+ this.obj = obj;
+ }
+ }
+
+ static IdentityObject globalObj = null;
+ static ValueHolder globalHolder = null;
+ static Object globalPlainObj = null;
+
+ @ForceInline
+ static ValueHolder createValueHolderWithSynchronizedFieldWrite() {
+ IdentityObject obj = new IdentityObject();
+ ValueHolder holder = new ValueHolder(obj);
+ synchronized (obj) {
+ obj.val = 42;
+ }
+ return holder;
+ }
+
+ @ForceInline
+ static ValueHolder createValueHolder() {
+ IdentityObject obj = new IdentityObject();
+ ValueHolder holder = new ValueHolder(obj);
+ return holder;
+ }
+
+ @DontInline
+ static ValueHolder returnArgument(ValueHolder holder) {
+ return holder;
+ }
+
+ @DontInline
+ static Object returnAsObject(ValueHolder holder) {
+ return holder;
+ }
+
+ @DontInline
+ static ValueHolder returnOneArgument(boolean first, ValueHolder holder1, ValueHolder holder2) {
+ if (first) {
+ return holder1;
+ }
+ return holder2;
+ }
+
+ @DontInline
+ static ValueHolder returnMiddleArgument(ValueHolder holder1, ValueHolder holder2, ValueHolder holder3) {
+ return holder2;
+ }
+
+ @DontInline
+ static ValueHolder returnArgumentAfterTwoSlots(long unused, ValueHolder holder) {
+ return holder;
+ }
+
+ static class BaseReturner {
+ native ValueHolder returnArgument(ValueHolder holder);
+ }
+
+ static final class Returner extends BaseReturner {
+ @DontInline
+ @Override
+ ValueHolder returnArgument(ValueHolder holder) {
+ return holder;
+ }
+ }
+
+ @DontInline
+ static ValueHolder escapeAndReturnArgument(ValueHolder holder) {
+ globalHolder = holder;
+ return holder;
+ }
+
+ @DontInline
+ static ValueHolder escapeFieldAndReturnArgument(ValueHolder holder) {
+ globalObj = holder.obj;
+ return holder;
+ }
+
+ // Return holder passed as argument. Because the IdentityObject held by it
+ // is then stored globally, its synchronization should not be removed.
+ // Depending on the values of the ValueTypePassFieldsAsArgs and
+ // ValueTypeReturnedAsFields flags, the holder is scalarized as argument
+ // and/or return of the returnArgument() call.
+ @Test
+ @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"})
+ static void testReturnHolderAndEscapeIdentityObject() {
+ ValueHolder holder = createValueHolderWithSynchronizedFieldWrite();
+ ValueHolder returnedHolder = returnArgument(holder);
+ globalObj = returnedHolder.obj;
+ }
+
+ // Variant of the above test where the holder is passed as an argument after
+ // another argument taking two slots. The same outcome is expected.
+ @Test
+ @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"})
+ static void testReturnHolderAfterTwoSlotsAndEscapeIdentityObject() {
+ ValueHolder holder = createValueHolderWithSynchronizedFieldWrite();
+ ValueHolder returnedHolder = returnArgumentAfterTwoSlots(42L, holder);
+ globalObj = returnedHolder.obj;
+ }
+
+ // Variant of the above test where one of two passed holders is returned.
+ // The same outcome is expected for each of the IdentityObject instances.
+ @Test
+ @Arguments(values = {Argument.BOOLEAN_TOGGLE_FIRST_TRUE})
+ @IR(counts = {IRNode.FAST_LOCK, "> 1", IRNode.FAST_UNLOCK, "> 1"})
+ static void testReturnOneOfTwoHoldersAndEscapeIdentityObjects(boolean first) {
+ ValueHolder holder1 = createValueHolderWithSynchronizedFieldWrite();
+ ValueHolder holder2 = createValueHolderWithSynchronizedFieldWrite();
+ ValueHolder returnedHolder = returnOneArgument(first, holder1, holder2);
+ globalObj = returnedHolder.obj;
+ }
+
+ // Variant of the above test where three holders are passed and always one
+ // of them is returned. Synchronization of the IdentityObject held by the
+ // returned holder should be retained.
+ @Test
+ @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"})
+ static void testReturnMiddleHolderAndEscapeIdentityObject() {
+ ValueHolder holder1 = createValueHolder();
+ ValueHolder holder2 = createValueHolderWithSynchronizedFieldWrite();
+ ValueHolder holder3 = createValueHolder();
+ ValueHolder returnedHolder = returnMiddleArgument(holder1, holder2, holder3);
+ globalObj = returnedHolder.obj;
+ }
+
+ // Variant of the above test where the passed and returned holder escapes
+ // within the call. The same outcome is expected.
+ @Test
+ @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"})
+ static void testReturnEscapedHolder() {
+ ValueHolder holder = createValueHolderWithSynchronizedFieldWrite();
+ escapeAndReturnArgument(holder);
+ }
+
+ // Variant of the above test where the IdentityObject referred to by the
+ // passed and returned holder escapes within the call. The same outcome is
+ // expected.
+ @Test
+ @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"})
+ static void testReturnHolderWithEscapedField() {
+ ValueHolder holder = createValueHolderWithSynchronizedFieldWrite();
+ escapeFieldAndReturnArgument(holder);
+ }
+
+ // Return holder as an Object, which naturally inhibits scalarization of the
+ // returned value. Because the holder is then stored globally, the
+ // IdentityObject it points to escapes, and its synchronization should not
+ // be removed. Depending on the value of the ValueTypePassFieldsAsArgs flag,
+ // the holder is scalarized as argument of the returnAsObject() call.
+ @Test
+ @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"})
+ static void testReturnHolderAsObjectAndEscapeHolder() {
+ ValueHolder holder = createValueHolderWithSynchronizedFieldWrite();
+ Object holderAsObject = returnAsObject(holder);
+ globalPlainObj = holderAsObject;
+ }
+
+ // Return holder via a non-static override of a native method, which
+ // naturally inhibits scalarization of the holder as argument, but allows it
+ // to be scalarized on return. Because the IdentityObject held by it is then
+ // stored globally, its synchronization should not be removed.
+ @Test
+ @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"})
+ static void testReturnHolderViaNativeSuperclassAndEscapeIdentityObject() {
+ ValueHolder holder = createValueHolderWithSynchronizedFieldWrite();
+ ValueHolder returnedHolder = new Returner().returnArgument(holder);
+ globalObj = returnedHolder.obj;
+ }
+
+ // Return holder passed as argument, do not force a global escape. In the
+ // cases when the holder is passed and returned in the same form (both
+ // scalarized or both buffered), we expect C2 to exploit the bytecode escape
+ // analyzer's ability to detect the argument as "local" and "returned" and
+ // optimize away the lock and unlock operations implementing the
+ // synchronized block.
+ // Currently C2 does not exploit bytecode escape analyzer information for
+ // returned arguments with mismatched buffer/scalar representations.
+ @Test
+ @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"},
+ failOn = {IRNode.FAST_LOCK, IRNode.FAST_UNLOCK})
+ @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"},
+ failOn = {IRNode.FAST_LOCK, IRNode.FAST_UNLOCK})
+ static void testReturnHolderWithoutEscape() {
+ ValueHolder holder = createValueHolderWithSynchronizedFieldWrite();
+ returnArgument(holder);
+ }
+
+ // Variant of the above test where the holder is passed as an argument after
+ // another argument taking two slots. The same outcome is expected.
+ @Test
+ @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"},
+ failOn = {IRNode.FAST_LOCK, IRNode.FAST_UNLOCK})
+ @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"},
+ failOn = {IRNode.FAST_LOCK, IRNode.FAST_UNLOCK})
+ static void testReturnHolderAfterTwoSlotsWithoutEscape() {
+ ValueHolder holder = createValueHolderWithSynchronizedFieldWrite();
+ returnArgumentAfterTwoSlots(42L, holder);
+ }
+
+ // Variant of the above test where three holders are passed and always one
+ // of them is returned. Similarly to above, we expect C2 to remove all
+ // synchronization, which it does except for the mismatched buffer/scalar
+ // cases.
+ @Test
+ @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"},
+ failOn = {IRNode.FAST_LOCK, IRNode.FAST_UNLOCK})
+ @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"},
+ failOn = {IRNode.FAST_LOCK, IRNode.FAST_UNLOCK})
+ static void testReturnMiddleHolderAndNoEscape() {
+ ValueHolder holder1 = createValueHolderWithSynchronizedFieldWrite();
+ ValueHolder holder2 = createValueHolderWithSynchronizedFieldWrite();
+ ValueHolder holder3 = createValueHolderWithSynchronizedFieldWrite();
+ returnMiddleArgument(holder1, holder2, holder3);
+ }
+
+}
From fd13c2b295a7ecc5c8747b0c93e37c8c8e025589 Mon Sep 17 00:00:00 2001
From: Albert Mingkun Yang
Date: Thu, 1 Oct 2026 10:30:58 +0000
Subject: [PATCH 03/98] 8393257: Parallel: Remove unused
RegionData::set_live_obj_size
Reviewed-by: tschatzl
---
src/hotspot/share/gc/parallel/psParallelCompact.hpp | 7 -------
1 file changed, 7 deletions(-)
diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp
index e9ad68278ba..3eb3691c8c0 100644
--- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp
@@ -153,7 +153,6 @@ class ParallelCompactData
}
inline void set_destination_count(uint count);
- inline void set_live_obj_size(size_t words);
inline void set_completed();
inline bool claim_unsafe();
@@ -290,12 +289,6 @@ ParallelCompactData::RegionData::set_destination_count(uint count)
_dc_and_los.store_relaxed((count << dc_shift) | live_sz);
}
-inline void ParallelCompactData::RegionData::set_live_obj_size(size_t words)
-{
- assert(words <= los_mask, "would overflow");
- _dc_and_los.store_relaxed(destination_count_raw() | (region_sz_t)words);
-}
-
inline void ParallelCompactData::RegionData::decrement_destination_count()
{
assert(dc_and_los() < dc_claimed, "already claimed");
From 2b4e5170d35488409b2e8c4bdaa339a04822d255 Mon Sep 17 00:00:00 2001
From: Yunbo Zhang
Date: Thu, 1 Oct 2026 11:03:17 +0000
Subject: [PATCH 04/98] 8369663: [IR Framework] Exclude IR verification when
using DTest on a @Run method with multiple tests
Reviewed-by: qamai, chagedorn
---
.../lib/ir_framework/test/TestVM.java | 4 +-
.../ir_framework/tests/TestRunTests.java | 38 +++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java
index b7c0a2201a5..a8d6fbcb4e9 100644
--- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java
+++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java
@@ -771,7 +771,9 @@ private void addCustomRunTest(Method m, Run runAnno) {
CustomRunTest customRunTest = new CustomRunTest(m, getAnnotation(m, Warmup.class), runAnno, tests, shouldExcludeTest);
allTests.add(customRunTest);
if (PRINT_VALID_IR_RULES) {
- tests.forEach(test -> irMatchRulePrinter.emitApplicableIRRules(test.getTestMethod(), customRunTest.isSkipped()));
+ // Even though we cannot exclude a @Test method from being run when invoked from a @Run method for multiple
+ // tests, we can disable its IR verification.
+ tests.forEach(test -> irMatchRulePrinter.emitApplicableIRRules(test.getTestMethod(), shouldExcludeTest(test.getTestMethod())));
}
}
diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java
index 39dae4ae3ad..feae6987aef 100644
--- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java
+++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java
@@ -64,6 +64,18 @@ public static void main(String[] args) {
new TestFramework(SkipC2Compilation.class).addFlags("-XX:TieredStopAtLevel=1").start();
new TestFramework(SkipC2Compilation.class).addFlags("-XX:TieredStopAtLevel=2").start();
new TestFramework(SkipC2Compilation.class).addFlags("-XX:TieredStopAtLevel=3").start();
+ new TestFramework(FilteredIRRun.class).addFlags("-DTest=test1").start();
+ new TestFramework(FilteredIRRun.class).addFlags("-DExclude=test2").start();
+ new TestFramework(FilteredIRRun.class).addFlags("-DTest=test1,test2", "-DExclude=test2").start();
+ for (String[] flags : new String[][] { {}, { "-DTest=test2" } }) {
+ try {
+ new TestFramework(FilteredIRRun.class).addFlags(flags).start();
+ Asserts.fail("Expected test2 to fail IR verification");
+ } catch (IRViolationException e) {
+ Asserts.assertTrue(e.getExceptionInfo().contains("ir_framework.tests.FilteredIRRun::test2"),
+ e.getExceptionInfo());
+ }
+ }
}
public int iFld;
@@ -268,6 +280,32 @@ public void run2(RunInfo info) {
}
}
+class FilteredIRRun {
+ int iFld;
+
+ @Test
+ @IR(counts = {IRNode.STORE_I, "1"})
+ public void test1(int x) {
+ iFld = x;
+ }
+
+ @Test
+ @IR(failOn = IRNode.STORE_I)
+ public void test2(int x) {
+ iFld = x;
+ }
+
+ @Run(test = {"test1", "test2"})
+ public void run(RunInfo info) {
+ test1(23);
+ test2(42);
+ if (!info.isWarmUp()) {
+ TestFramework.assertCompiledByC2(info.getTest("test1"));
+ TestFramework.assertCompiledByC2(info.getTest("test2"));
+ }
+ }
+}
+
// Run with TieredStopAt=[1,3]. IR verification is skipped.
class SkipC2Compilation {
From 246f461015a2584f5893b4d66eb1435c5e405a93 Mon Sep 17 00:00:00 2001
From: Roland Westrelin
Date: Thu, 1 Oct 2026 12:16:35 +0000
Subject: [PATCH 05/98] 8392714: PhaseIdealLoop::clone_cmp_loadklass_down fails
with assert(n->is_dead())
Reviewed-by: qamai, mchevalier
---
src/hotspot/share/opto/phaseX.cpp | 65 ++++++++++---------
.../splitif/TestDeadAddPLoadCmpLoadKlass.java | 64 ++++++++++++++++++
2 files changed, 99 insertions(+), 30 deletions(-)
create mode 100644 test/hotspot/jtreg/compiler/splitif/TestDeadAddPLoadCmpLoadKlass.java
diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp
index c0d9908d46e..c3f255ab08e 100644
--- a/src/hotspot/share/opto/phaseX.cpp
+++ b/src/hotspot/share/opto/phaseX.cpp
@@ -2337,42 +2337,47 @@ void PhaseIterGVN::remove_globally_dead_node(Node* dead, NodeOrigin origin) {
}
bool recurse = false;
// Remove from hash table
- _table.hash_delete( dead );
+ _table.hash_delete(dead);
// Smash all inputs to 'dead', isolating him completely
for (uint i = 0; i < dead->req(); i++) {
- Node *in = dead->in(i);
- if (in != nullptr && in != C->top()) { // Points to something?
- int nrep = dead->replace_edge(in, nullptr, this); // Kill edges
- assert((nrep > 0), "sanity");
- if (in->outcnt() == 0) { // Made input go dead?
- stack.push(in, PROCESS_INPUTS); // Recursively remove
- recurse = true;
- } else if (in->outcnt() == 1 && in->has_special_unique_user()) {
- add_users_to_worklist(in);
- } else if (in->outcnt() <= 2 && dead->is_Phi()) {
- if (in->Opcode() == Op_Region) {
- _worklist.push(in);
- } else if (in->is_Store()) {
- DUIterator_Fast imax, i = in->fast_outs(imax);
+ Node* in = dead->in(i);
+ if (in == nullptr) {
+ continue;
+ }
+ int nrep = dead->replace_edge(in, nullptr, this); // Kill edges
+ assert((nrep > 0), "sanity");
+ if (in == C->top()) {
+ continue;
+ }
+ if (in->outcnt() == 0) {
+ // Made input go dead?
+ stack.push(in, PROCESS_INPUTS); // Recursively remove
+ recurse = true;
+ } else if (in->outcnt() == 1 && in->has_special_unique_user()) {
+ add_users_to_worklist(in);
+ } else if (in->outcnt() <= 2 && dead->is_Phi()) {
+ if (in->Opcode() == Op_Region) {
+ _worklist.push(in);
+ } else if (in->is_Store()) {
+ DUIterator_Fast imax, i = in->fast_outs(imax);
+ _worklist.push(in->fast_out(i));
+ i++;
+ if (in->outcnt() == 2) {
_worklist.push(in->fast_out(i));
i++;
- if (in->outcnt() == 2) {
- _worklist.push(in->fast_out(i));
- i++;
- }
- assert(!(i < imax), "sanity");
}
- } else if (in->should_process_when_disconnect_output(dead)) {
- _worklist.push(in);
- }
- if (ReduceFieldZeroing && dead->is_Load() && i == MemNode::Memory &&
- in->is_Proj() && in->in(0) != nullptr && in->in(0)->is_Initialize()) {
- // A Load that directly follows an InitializeNode is
- // going away. The Stores that follow are candidates
- // again to be captured by the InitializeNode.
- add_users_to_worklist_if(_worklist, in, [](Node* n) { return n->is_Store(); });
+ assert(!(i < imax), "sanity");
}
- } // if (in != nullptr && in != C->top())
+ } else if (in->should_process_when_disconnect_output(dead)) {
+ _worklist.push(in);
+ }
+ if (ReduceFieldZeroing && dead->is_Load() && i == MemNode::Memory &&
+ in->is_Proj() && in->in(0) != nullptr && in->in(0)->is_Initialize()) {
+ // A Load that directly follows an InitializeNode is
+ // going away. The Stores that follow are candidates
+ // again to be captured by the InitializeNode.
+ add_users_to_worklist_if(_worklist, in, [](Node* n) { return n->is_Store(); });
+ }
} // for (uint i = 0; i < dead->req(); i++)
if (recurse) {
continue;
diff --git a/test/hotspot/jtreg/compiler/splitif/TestDeadAddPLoadCmpLoadKlass.java b/test/hotspot/jtreg/compiler/splitif/TestDeadAddPLoadCmpLoadKlass.java
new file mode 100644
index 00000000000..c0f9fd98f6f
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/splitif/TestDeadAddPLoadCmpLoadKlass.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8392714
+ * @summary AddPNode killed in PhaseIdealLoop::clone_cmp_loadklass_down() not recognized as dead
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:+StressLoopPeeling
+ * -XX:CompileThresholdScaling=0.01
+ * -XX:CompileOnly=${test.main.class}::test ${test.main.class}
+ * @run main ${test.main.class}
+ */
+
+
+public class TestDeadAddPLoadCmpLoadKlass {
+ Object[] oArray;
+ int[] iArray;
+
+ void test(int limit) {
+ if (limit <= 0) {
+ return;
+ }
+ if (oArray == null) {
+ oArray = new int[1][];
+ iArray = new int[1];
+ }
+ int sum = 0;
+ for (int i = 0; sum < limit; i++) {
+ oArray[i] = new int[i];
+ iArray[i] = ++sum;
+ }
+ }
+
+ public static void main(String[] args) {
+ TestDeadAddPLoadCmpLoadKlass value = new TestDeadAddPLoadCmpLoadKlass();
+ for (int i = 0; i <= 60; i++) {
+ value = new TestDeadAddPLoadCmpLoadKlass();
+ value.test(1);
+ }
+ for (int i = 0; i < 1000; i++) {
+ value.test(1);
+ }
+ }
+}
From 5cbf4b411ac60fbfc3796ad0e17d484ae1feba03 Mon Sep 17 00:00:00 2001
From: Alan Bateman
Date: Thu, 1 Oct 2026 12:30:02 +0000
Subject: [PATCH 06/98] 8392944: (fc) FileChannel scatter/gather ops don't
check alignment when file open for direct I/O
Reviewed-by: vyazici
---
.../share/classes/sun/nio/ch/IOUtil.java | 26 +-
.../directio/GatheringWriteAlignment.java | 146 +++++++++++
.../FileChannel/directio/Misaligned.java | 243 ++++++++++++++++++
3 files changed, 410 insertions(+), 5 deletions(-)
create mode 100644 test/jdk/java/nio/channels/FileChannel/directio/GatheringWriteAlignment.java
create mode 100644 test/jdk/java/nio/channels/FileChannel/directio/Misaligned.java
diff --git a/src/java.base/share/classes/sun/nio/ch/IOUtil.java b/src/java.base/share/classes/sun/nio/ch/IOUtil.java
index df6677ab94d..8bd7b784272 100644
--- a/src/java.base/share/classes/sun/nio/ch/IOUtil.java
+++ b/src/java.base/share/classes/sun/nio/ch/IOUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -190,13 +190,25 @@ static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
int lim = buf.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
- if (directIO)
+
+ if (directIO) {
Util.checkRemainingBufferSizeAligned(rem, alignment);
+ if (buf instanceof DirectBuffer) {
+ Util.checkBufferPositionAligned(buf, pos, alignment);
+ }
+ }
if (rem > 0) {
long headroom = WRITEV_MAX - writevLen;
- if (headroom < rem)
- rem = (int)headroom;
+ if (headroom < rem) {
+ if (directIO) {
+ headroom -= headroom % alignment;
+ if (headroom == 0) {
+ break;
+ }
+ }
+ rem = (int) headroom;
+ }
vec.setBuffer(iov_len, buf, pos, rem);
@@ -404,8 +416,12 @@ static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
- if (directIO)
+ if (directIO) {
Util.checkRemainingBufferSizeAligned(rem, alignment);
+ if (buf instanceof DirectBuffer) {
+ Util.checkBufferPositionAligned(buf, pos, alignment);
+ }
+ }
if (rem > 0) {
vec.setBuffer(iov_len, buf, pos, rem);
diff --git a/test/jdk/java/nio/channels/FileChannel/directio/GatheringWriteAlignment.java b/test/jdk/java/nio/channels/FileChannel/directio/GatheringWriteAlignment.java
new file mode 100644
index 00000000000..bfe86a048da
--- /dev/null
+++ b/test/jdk/java/nio/channels/FileChannel/directio/GatheringWriteAlignment.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8392944
+ * @summary Test alignment of gathering writes with direct I/O near WRITEV_MAX
+ * @requires (os.family == "linux" | os.family == "mac")
+ * @requires vm.bits == 64 & os.maxMemory >= 8G
+ * @modules jdk.unsupported
+ * @run junit/othervm/timeout=480 -Xmx4G -XX:MaxDirectMemorySize=3G ${test.main.class}
+ */
+
+import java.lang.foreign.Arena;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.channels.FileChannel;
+import static java.nio.file.StandardOpenOption.*;
+import static com.sun.nio.file.ExtendedOpenOption.*;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import static org.junit.jupiter.api.Assertions.*;
+
+class GatheringWriteAlignment {
+
+ private static Path file;
+ private static int alignment;
+
+ @BeforeAll
+ static void setup() throws Exception {
+ file = Files.createTempFile(Path.of("."), "test", null);
+ alignment = (int) Files.getFileStore(file).getBlockSize();
+ }
+
+ @AfterAll
+ static void cleanup() throws Exception {
+ Files.delete(file);
+ }
+
+ /**
+ * Tests that a gathering write with direct I/O writes from only the first
+ * buffer when the remaining headroom is smaller than one alignment unit.
+ */
+ @Test
+ void testOnlyFirstBufferFits() throws Exception {
+ try (FileChannel fc = FileChannel.open(file, WRITE, DIRECT);
+ Arena arena = Arena.ofConfined()) {
+
+ // largest aligned length below WRITEV_MAX
+ int firstBufferSize = Integer.MAX_VALUE - (Integer.MAX_VALUE % alignment);
+ ByteBuffer firstBuffer = arena.allocate(firstBufferSize, alignment).asByteBuffer();
+
+ // second buffer can not fit in the remaining headroom
+ ByteBuffer secondBuffer = ByteBuffer.allocate(alignment);
+
+ long written = fc.write(new ByteBuffer[]{firstBuffer, secondBuffer});
+
+ assertTrue(written > 0);
+ assertEquals(written, (long) firstBuffer.position());
+ assertEquals(0, firstBuffer.position() % alignment);
+ assertEquals(0, secondBuffer.position());
+ }
+ }
+
+ /**
+ * Tests that a gathering write with direct I/O limits writes from the second
+ * buffer to alignment units when only part of it fits within the remaining
+ * headroom.
+ */
+ @ParameterizedTest
+ @ValueSource(booleans = { true, false })
+ void testOnlyPartOfSecondBufferFits(boolean direct) throws Exception {
+ try (FileChannel fc = FileChannel.open(file, WRITE, DIRECT);
+ Arena arena = Arena.ofConfined()) {
+
+ // leave 2 * alignment - 1 bytes of headroom
+ int firstBufferSize = Integer.MAX_VALUE - (Integer.MAX_VALUE % alignment) - alignment;
+ ByteBuffer firstBuffer = arena.allocate(firstBufferSize, alignment).asByteBuffer();
+
+ // only one alignment unit of this buffer should fit
+ ByteBuffer secondBuffer = direct
+ ? arena.allocate(2L * alignment, alignment).asByteBuffer()
+ : ByteBuffer.allocate(2 * alignment);
+
+ long written = fc.write(new ByteBuffer[]{firstBuffer, secondBuffer});
+
+ assertTrue(written > 0);
+ assertEquals(0L, written % alignment);
+ assertEquals(written, (long) firstBuffer.position() + secondBuffer.position());
+ assertEquals((int) Math.min(written, firstBufferSize), firstBuffer.position());
+ assertEquals(0, secondBuffer.position() % alignment);
+ assertTrue(secondBuffer.position() <= alignment);
+ }
+ }
+
+ /**
+ * Tests that a gathering write with direct I/O writes from only the first two
+ * buffers when the remaining headroom is smaller than one alignment unit.
+ */
+ @Test
+ void testOnlyFirstTwoBuffersFit() throws Exception {
+ try (FileChannel fc = FileChannel.open(file, WRITE, DIRECT);
+ Arena arena = Arena.ofConfined()) {
+
+ // leave room for one aligned buffer, plus alignment - 1 bytes
+ int firstBufferSize = Integer.MAX_VALUE - (Integer.MAX_VALUE % alignment) - alignment;
+ ByteBuffer firstBuffer = arena.allocate(firstBufferSize, alignment).asByteBuffer();
+ ByteBuffer secondBuffer = ByteBuffer.allocate(alignment);
+ ByteBuffer thirdBuffer = ByteBuffer.allocate(alignment);
+
+ long written = fc.write(new ByteBuffer[]{firstBuffer, secondBuffer, thirdBuffer});
+
+ assertTrue(written > 0);
+ assertEquals(0L, written % alignment);
+ assertEquals(written, (long) firstBuffer.position() + secondBuffer.position());
+ assertEquals((int) Math.min(written, firstBufferSize), firstBuffer.position());
+ assertEquals(0, secondBuffer.position() % alignment);
+ assertEquals(0, thirdBuffer.position());
+ }
+ }
+}
diff --git a/test/jdk/java/nio/channels/FileChannel/directio/Misaligned.java b/test/jdk/java/nio/channels/FileChannel/directio/Misaligned.java
new file mode 100644
index 00000000000..25b55ee93dd
--- /dev/null
+++ b/test/jdk/java/nio/channels/FileChannel/directio/Misaligned.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8392944
+ * @summary Test FileChannel direct I/O with misaligned file position or buffers
+ * @modules jdk.unsupported
+ * @run junit ${test.main.class}
+ */
+
+import java.io.IOException;
+import java.lang.foreign.Arena;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.channels.FileChannel;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import static java.nio.file.StandardOpenOption.*;
+import static com.sun.nio.file.ExtendedOpenOption.*;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
+import static org.junit.jupiter.api.Assertions.*;
+
+class Misaligned {
+
+ private static Path file;
+ private static int alignment;
+
+ @BeforeAll
+ static void setup() throws Exception {
+ file = Files.createTempFile(Path.of("."), "test", null);
+ alignment = (int) Files.getFileStore(file).getBlockSize();
+ Files.write(file, new byte[alignment * 4]);
+ }
+
+ @AfterAll
+ static void cleanup() throws Exception {
+ Files.delete(file);
+ }
+
+ /**
+ * Return a stream of suppliers for each Arena type. A supplier is used to avoid JUnit
+ * closing the Arena and failing (as some Arenas are not closable).
+ */
+ static Stream> arenaSuppliers() {
+ return Stream.of(Arena::global, Arena::ofAuto, Arena::ofConfined, Arena::ofShared);
+ }
+
+ /**
+ * Test exception thrown when file position is misaligned.
+ */
+ private void testMisalignedFilePosition(ByteBuffer bb) throws Exception {
+ // check buffer is not empty and is suitably aligned
+ assertTrue(bb.hasRemaining());
+ assertEquals(0, bb.remaining() % alignment);
+ if (bb.isDirect()) {
+ assertEquals(0, bb.alignmentOffset(bb.position(), alignment));
+ assertEquals(0, bb.alignmentOffset(bb.limit(), alignment));
+ }
+
+ try (FileChannel fc = FileChannel.open(file, READ, WRITE, DIRECT)) {
+ fc.position(1L); // misaligned file position
+ assertThrows(IOException.class, () -> fc.read(bb));
+ assertThrows(IOException.class, () -> fc.write(bb));
+ assertThrows(IOException.class, () -> fc.read(new ByteBuffer[]{bb}));
+ assertThrows(IOException.class, () -> fc.write(new ByteBuffer[]{bb}));
+ assertThrows(IOException.class, () -> fc.read(bb, 1L));
+ assertThrows(IOException.class, () -> fc.write(bb, 1L));
+ }
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = { true, false })
+ void testMisalignedFilePosition(boolean direct) throws Exception {
+ ByteBuffer bb = direct
+ ? ByteBuffer.allocateDirect(3 * alignment - 1).alignedSlice(alignment)
+ : ByteBuffer.allocate(3 * alignment);
+ testMisalignedFilePosition(bb);
+ }
+
+ @ParameterizedTest
+ @MethodSource("arenaSuppliers")
+ void testMisalignedFilePosition(Supplier arenaSupplier) throws Exception {
+ Arena arena = arenaSupplier.get();
+ try {
+ ByteBuffer bb = arena.allocate(3L * alignment, alignment).asByteBuffer();
+ testMisalignedFilePosition(bb);
+ } finally {
+ tryClose(arena);
+ }
+ }
+
+ /**
+ * Test exception thrown when the buffer address is misaligned.
+ */
+ private void testMisalignedAddress(ByteBuffer bb) throws Exception {
+ // check buffer is direct with an aligned base address
+ assertTrue(bb.isDirect());
+ assertEquals(0, bb.alignmentOffset(0, alignment));
+
+ // need sufficient capacity for an aligned region starting at position 1
+ assertTrue(bb.capacity() >= alignment + 1);
+
+ // another aligned buffer to use for scatter/gather ops
+ ByteBuffer alignedBuffer = ByteBuffer.allocateDirect(2 * alignment - 1)
+ .alignedSlice(alignment);
+
+ try (FileChannel fc = FileChannel.open(file, READ, WRITE, DIRECT)) {
+ bb.position(1); // misaligned address
+ bb.limit(alignment + 1);
+
+ assertNotEquals(0, bb.alignmentOffset(bb.position(), alignment));
+ assertEquals(0, bb.remaining() % alignment);
+
+ assertThrows(IOException.class, () -> fc.read(bb));
+ assertThrows(IOException.class, () -> fc.write(bb));
+ assertThrows(IOException.class, () -> fc.read(new ByteBuffer[]{bb}));
+ assertThrows(IOException.class, () -> fc.write(new ByteBuffer[]{bb}));
+ assertThrows(IOException.class, () -> fc.read(new ByteBuffer[]{alignedBuffer, bb}));
+ assertThrows(IOException.class, () -> fc.write(new ByteBuffer[]{alignedBuffer, bb}));
+ assertThrows(IOException.class, () -> fc.read(bb, 0L));
+ assertThrows(IOException.class, () -> fc.write(bb, 0L));
+
+
+ }
+ }
+
+ @Test
+ void testMisalignedAddress() throws Exception {
+ ByteBuffer bb = ByteBuffer.allocateDirect(3 * alignment - 1)
+ .alignedSlice(alignment);
+ testMisalignedAddress(bb);
+ }
+
+ @ParameterizedTest
+ @MethodSource("arenaSuppliers")
+ void testMisalignedAddress(Supplier arenaSupplier) throws Exception {
+ Arena arena = arenaSupplier.get();
+ try {
+ ByteBuffer bb = arena.allocate(3L * alignment, alignment).asByteBuffer();
+ testMisalignedAddress(bb);
+ } finally {
+ tryClose(arena);
+ }
+ }
+
+ /**
+ * Test exception thrown when the remaining length is not a multiple of the alignment.
+ */
+ private void testMisalignedRemaining(ByteBuffer bb) throws Exception {
+ assertEquals(0, bb.position());
+ assertTrue(bb.capacity() >= alignment + 1);
+ if (bb.isDirect()) {
+ assertEquals(0, bb.alignmentOffset(0, alignment));
+ }
+
+ // another aligned buffer to use for scatter/gather ops
+ ByteBuffer alignedBuffer = ByteBuffer.allocateDirect(2 * alignment - 1)
+ .alignedSlice(alignment);
+
+ try (FileChannel fc = FileChannel.open(file, READ, WRITE, DIRECT)) {
+ bb.limit(alignment - 1); // remaining is 1 byte below an alignment
+ assertThrows(IOException.class, () -> fc.read(bb));
+ assertThrows(IOException.class, () -> fc.write(bb));
+ assertThrows(IOException.class, () -> fc.read(new ByteBuffer[]{bb}));
+ assertThrows(IOException.class, () -> fc.write(new ByteBuffer[]{bb}));
+ assertThrows(IOException.class, () -> fc.read(new ByteBuffer[]{alignedBuffer, bb}));
+ assertThrows(IOException.class, () -> fc.write(new ByteBuffer[]{alignedBuffer, bb}));
+ assertThrows(IOException.class, () -> fc.read(bb, 0L));
+ assertThrows(IOException.class, () -> fc.write(bb, 0L));
+
+ bb.limit(alignment + 1); // remaining is 1 byte beyond an alignment
+ assertThrows(IOException.class, () -> fc.read(bb));
+ assertThrows(IOException.class, () -> fc.write(bb));
+ assertThrows(IOException.class, () -> fc.read(new ByteBuffer[]{bb}));
+ assertThrows(IOException.class, () -> fc.write(new ByteBuffer[]{bb}));
+ assertThrows(IOException.class, () -> fc.read(new ByteBuffer[]{alignedBuffer, bb}));
+ assertThrows(IOException.class, () -> fc.write(new ByteBuffer[]{alignedBuffer, bb}));
+ assertThrows(IOException.class, () -> fc.read(bb, 0L));
+ assertThrows(IOException.class, () -> fc.write(bb, 0L));
+ }
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = { true, false })
+ void testMisalignedRemaining(boolean direct) throws Exception {
+ ByteBuffer bb = direct
+ ? ByteBuffer.allocateDirect(3 * alignment - 1).alignedSlice(alignment)
+ : ByteBuffer.allocate(3 * alignment);
+ testMisalignedRemaining(bb);
+ }
+
+ @ParameterizedTest
+ @MethodSource("arenaSuppliers")
+ void testMisalignedRemaining(Supplier arenaSupplier) throws Exception {
+ Arena arena = arenaSupplier.get();
+ try {
+ ByteBuffer bb = arena.allocate(3L * alignment, alignment).asByteBuffer();
+ testMisalignedRemaining(bb);
+ } finally {
+ tryClose(arena);
+ }
+ }
+
+ /**
+ * Attempt to close the given Arena.
+ */
+ private static boolean tryClose(Arena arena) {
+ try {
+ arena.close();
+ return true;
+ } catch (UnsupportedOperationException e) {
+ return false;
+ }
+ }
+}
From d95e3773e228943ee412867134d666cce3663e24 Mon Sep 17 00:00:00 2001
From: Matthew Donovan
Date: Thu, 1 Oct 2026 13:27:32 +0000
Subject: [PATCH 07/98] 8387730: Test
javax/crypto/KDF/KDFDelayedProviderThreadingTest.java timed out
Reviewed-by: weijun
---
.../KDF/KDFDelayedProviderThreadingTest.java | 68 +++++++++++++------
1 file changed, 49 insertions(+), 19 deletions(-)
diff --git a/test/jdk/javax/crypto/KDF/KDFDelayedProviderThreadingTest.java b/test/jdk/javax/crypto/KDF/KDFDelayedProviderThreadingTest.java
index 8d7ad058c39..65c9bbb50aa 100644
--- a/test/jdk/javax/crypto/KDF/KDFDelayedProviderThreadingTest.java
+++ b/test/jdk/javax/crypto/KDF/KDFDelayedProviderThreadingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,10 @@
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+
public class KDFDelayedProviderThreadingTest {
/// This number of iterations is enough to see a case where the threads
/// arrange themselves such that both `deriveData` attempts cause "ERROR",
@@ -54,6 +58,21 @@ public class KDFDelayedProviderThreadingTest {
static final HKDFParameterSpec input
= HKDFParameterSpec.ofExtract().extractOnly();
+ private static final CyclicBarrier START = new CyclicBarrier(3);
+ private static final CyclicBarrier FINISH = new CyclicBarrier(3);
+ private static volatile KDF kdf;
+
+ static void wait(CyclicBarrier cb) {
+ try {
+ cb.await();
+ } catch (InterruptedException exc) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException(exc);
+ } catch (BrokenBarrierException exc) {
+ throw new RuntimeException(exc);
+ }
+ }
+
static String derive(KDF kdf) {
try {
return Arrays.toString(kdf.deriveData(input));
@@ -62,10 +81,37 @@ static String derive(KDF kdf) {
}
}
- public static void main(String[] args) throws Exception {
+ static void main(String[] args) throws Exception {
+
+ var t1 = new Thread(() -> {
+ for (int i = 0 ; i < ITERATIONS ; ++i) {
+ wait(START);
+ out = derive(kdf);
+ wait(FINISH);
+ }
+ }, "KDF-derive");
+
+ var t2 = new Thread(() -> {
+ for (int i = 0 ; i < ITERATIONS ; ++i) {
+ wait(START);
+ kdf.getProviderName();
+ wait(FINISH);
+ }
+ }, "KDF-provider-name");
+ t1.start();
+ t2.start();
+
Security.insertProviderAt(new P(), 1);
for (int i = 0; i < ITERATIONS; i++) {
- test();
+ kdf = KDF.getInstance("HKDF-SHA256");
+ wait(START);
+ wait(FINISH);
+
+ String out2 = derive(kdf);
+ Asserts.assertEquals(out, out2);
+ if (out.length() < 10) { // "error"
+ threadOrderReversalCounter++;
+ }
}
// If the value of threadOrderReversalCounter is consistently zero,
@@ -79,22 +125,6 @@ public static void main(String[] args) throws Exception {
+ " iterations (depends on hardware specs/utilization).");
}
- static void test() throws Exception {
- var k = KDF.getInstance("HKDF-SHA256");
- var t1 = new Thread(() -> out = derive(k));
- var t2 = new Thread(() -> k.getProviderName());
- t1.start();
- t2.start();
- t1.join();
- t2.join();
-
- String out2 = derive(k);
- Asserts.assertEquals(out, out2);
- if (out.length() < 10) { // "error"
- threadOrderReversalCounter++;
- }
- }
-
public static class P extends Provider {
public P() {
super("ME", "1", "ME");
From 46fbea9c4b9b628e43dd8474bde2bd8e984bf857 Mon Sep 17 00:00:00 2001
From: Jatin Bhateja
Date: Thu, 1 Oct 2026 13:44:51 +0000
Subject: [PATCH 08/98] 8393382: [VectorAPI] AbstractMask.intoArray should be
force inlined
Reviewed-by: qamai
---
.../share/classes/jdk/incubator/vector/AbstractMask.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractMask.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractMask.java
index 9fac32da26d..256c0668178 100644
--- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractMask.java
+++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractMask.java
@@ -72,6 +72,7 @@ public final VectorSpecies vectorSpecies() {
}
@Override
+ @ForceInline
public void intoArray(boolean[] bits, int i) {
AbstractSpecies vsp = (AbstractSpecies) vectorSpecies();
int laneCount = vsp.laneCount();
From 5fa098bf826a709b761486d69f98faf99b7f5f62 Mon Sep 17 00:00:00 2001
From: john spurling
Date: Thu, 1 Oct 2026 15:46:56 +0000
Subject: [PATCH 09/98] 8392088: Shenandoah: ShenandoahNMethodLock footprint
optimization
Reviewed-by: shade, kdnilsen
---
.../share/gc/shenandoah/shenandoahLock.cpp | 61 ++++---------------
.../share/gc/shenandoah/shenandoahLock.hpp | 49 ++++++++-------
.../share/gc/shenandoah/shenandoahNMethod.hpp | 5 +-
.../share/gc/shenandoah/shenandoahUnload.cpp | 3 +-
4 files changed, 43 insertions(+), 75 deletions(-)
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp
index 7e317f53424..340b28faa4b 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp
@@ -89,61 +89,24 @@ void ShenandoahLock::yield_or_sleep(int &yields) {
}
}
-ShenandoahSimpleLock::ShenandoahSimpleLock() {
+ShenandoahSimpleLock::ShenandoahSimpleLock() : _owner(nullptr) {
assert(os::mutex_init_done(), "Too early!");
}
-void ShenandoahSimpleLock::lock(bool allow_block_for_safepoint) {
- _lock.lock();
-}
-
-void ShenandoahSimpleLock::unlock() {
- _lock.unlock();
-}
-
-template
-ShenandoahReentrantLock::ShenandoahReentrantLock() :
- Lock(), _owner(nullptr), _count(0) {
-}
-
-template
-ShenandoahReentrantLock::~ShenandoahReentrantLock() {
- assert(_count == 0, "Unbalance");
-}
-
-template
-void ShenandoahReentrantLock::lock(bool allow_block_for_safepoint) {
- Thread* const thread = Thread::current();
- Thread* const owner = _owner.load_relaxed();
-
- if (owner != thread) {
- Lock::lock(allow_block_for_safepoint);
- _owner.store_relaxed(thread);
+bool ShenandoahSimpleLock::lock() {
+ if (_owner.load_relaxed() == Thread::current()) {
+ return false;
}
- _count++;
-}
-
-template
-void ShenandoahReentrantLock::unlock() {
- assert(owned_by_self(), "Invalid owner");
- assert(_count > 0, "Invalid count");
-
- _count--;
+ _lock.lock();
+ assert(_owner.load_relaxed() == nullptr, "No owner yet.");
+ _owner.store_relaxed(Thread::current());
- if (_count == 0) {
- _owner.store_relaxed((Thread*)nullptr);
- Lock::unlock();
- }
+ return true;
}
-template
-bool ShenandoahReentrantLock::owned_by_self() const {
- Thread* const thread = Thread::current();
- Thread* const owner = _owner.load_relaxed();
- return owner == thread;
+void ShenandoahSimpleLock::unlock() {
+ assert(_owner.load_relaxed() == Thread::current(), "Lock must be held by current thread.");
+ _owner.store_relaxed(nullptr);
+ _lock.unlock();
}
-
-// Explicit template instantiation
-template class ShenandoahReentrantLock;
-template class ShenandoahReentrantLock;
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp
index 5041419b2c7..e342e1474d9 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp
@@ -87,32 +87,18 @@ class ShenandoahLock {
}
};
-// Simple lock using PlatformMonitor
+// Simple lock using PlatformMutex
class ShenandoahSimpleLock {
private:
- PlatformMonitor _lock; // native lock
+ PlatformMutex _lock; // native lock
+ Atomic _owner;
public:
ShenandoahSimpleLock();
- void lock(bool allow_block_for_safepoint = false);
+ bool lock();
void unlock();
-};
-
-// templated reentrant lock
-template
-class ShenandoahReentrantLock : public Lock {
-private:
- Atomic _owner;
- uint64_t _count;
-
-public:
- ShenandoahReentrantLock();
- ~ShenandoahReentrantLock();
-
- void lock(bool allow_block_for_safepoint = false);
- void unlock();
-
- // If the lock already owned by this thread
- bool owned_by_self() const ;
+ bool owned_by_self() const {
+ return _owner.load_relaxed() == Thread::current();
+ }
};
// template based ShenandoahLocker
@@ -130,4 +116,25 @@ class ShenandoahLocker : public StackObj {
}
};
+template
+class ShenandoahReentrantLocker : public StackObj {
+private:
+ Lock* _lock;
+
+public:
+ ShenandoahReentrantLocker(Lock* lock) : _lock(nullptr) {
+ if (lock->lock()) {
+ _lock = lock;
+ }
+ }
+
+ ~ShenandoahReentrantLocker() {
+ if (_lock != nullptr) {
+ _lock->unlock();
+ _lock = nullptr;
+ }
+ }
+};
+
+
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHLOCK_HPP
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp
index 04c6bf0a804..280067f63f5 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp
@@ -35,9 +35,8 @@
class BarrierSetNMethod;
-// Use ShenandoahReentrantLock as ShenandoahNMethodLock
-typedef ShenandoahReentrantLock ShenandoahNMethodLock;
-typedef ShenandoahLocker ShenandoahNMethodLocker;
+typedef ShenandoahSimpleLock ShenandoahNMethodLock;
+typedef ShenandoahReentrantLocker ShenandoahNMethodLocker;
struct ShenandoahPatchableJump {
int32_t _rel_pc;
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp
index 962935b5799..04c2d1e6b3e 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp
@@ -92,8 +92,7 @@ class ShenandoahCompiledICProtectionBehaviour : public CompiledICProtectionBehav
virtual bool lock(nmethod* nm) {
ShenandoahNMethodLock* const lock = ShenandoahNMethod::ic_lock_for_nmethod(nm);
assert(lock != nullptr, "Not yet registered?");
- lock->lock();
- return true;
+ return lock->lock();
}
virtual void unlock(nmethod* nm) {
From b6b2cbe2dd75251889836d0fab60f7033e3619cd Mon Sep 17 00:00:00 2001
From: Joe Wang
Date: Thu, 1 Oct 2026 15:50:00 +0000
Subject: [PATCH 10/98] 8357394: Add JDK specific property for external
resource access
Reviewed-by: lancea, alanb
---
.../xalan/internal/xsltc/compiler/Import.java | 10 +-
.../internal/xsltc/compiler/Include.java | 10 +-
.../xalan/internal/xsltc/compiler/Parser.java | 35 +-
.../xsltc/compiler/util/ErrorMessages.java | 6 +-
.../internal/xsltc/dom/LoadDocument.java | 11 +-
.../xsltc/runtime/AbstractTranslet.java | 40 +-
.../internal/xsltc/trax/TemplatesImpl.java | 8 +-
.../xsltc/trax/TransformerFactoryImpl.java | 10 +-
.../internal/xsltc/trax/TransformerImpl.java | 26 +-
.../impl/XMLDocumentFragmentScannerImpl.java | 3 +-
.../internal/impl/XMLEntityManager.java | 21 +-
.../internal/impl/msg/XMLMessages.properties | 5 +-
.../impl/msg/XMLSchemaMessages.properties | 2 +-
.../internal/impl/xs/XMLSchemaLoader.java | 21 +-
.../impl/xs/traversers/XSDHandler.java | 7 +-
.../internal/jaxp/DocumentBuilderImpl.java | 6 +-
.../xerces/internal/jaxp/SAXParserImpl.java | 9 +-
.../jaxp/validation/XMLSchemaFactory.java | 8 +-
.../XMLSchemaValidatorComponentManager.java | 9 +-
.../xerces/internal/parsers/DOMParser.java | 6 +-
.../xerces/internal/parsers/SAXParser.java | 6 +-
.../internal/xinclude/XIncludeHandler.java | 22 +-
.../classes/jdk/xml/internal/AccessRule.java | 522 ++++++++++++++++++
.../jdk/xml/internal/FeaturePropertyBase.java | 15 +-
.../jdk/xml/internal/JdkConstants.java | 13 +-
.../classes/jdk/xml/internal/JdkXmlUtils.java | 4 +-
.../jdk/xml/internal/SecuritySupport.java | 115 ++--
.../share/classes/jdk/xml/internal/Utils.java | 52 +-
.../jdk/xml/internal/XMLSecurityManager.java | 93 +++-
.../internal/XMLSecurityPropertyManager.java | 12 +-
src/java.xml/share/classes/module-info.java | 194 ++++++-
src/java.xml/share/conf/jaxp.properties | 75 +++
.../common/access/AccessRuleTest.java | 200 +++++++
.../common/access/AccessTestBase.java | 447 +++++++++++++++
.../jaxp/unittest/common/access/DOMTest.java | 65 +++
.../jaxp/unittest/common/access/SAXTest.java | 67 +++
.../unittest/common/access/SchemaTest.java | 83 +++
.../jaxp/unittest/common/access/StAXTest.java | 58 ++
.../unittest/common/access/TransformTest.java | 68 +++
.../unittest/common/access/XIncludeTest.java | 65 +++
.../catalog/testcatalog/TestCatalog.xml | 5 +-
.../jaxp/unittest/common/dtd/DTDTestBase.java | 6 +-
.../jaxp/unittest/common/util/TestBase.java | 124 ++++-
.../unittest/common/xmlfiles/XI_simple.xml | 2 +
44 files changed, 2336 insertions(+), 230 deletions(-)
create mode 100644 src/java.xml/share/classes/jdk/xml/internal/AccessRule.java
create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java
create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/access/AccessTestBase.java
create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/access/DOMTest.java
create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/access/SAXTest.java
create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/access/SchemaTest.java
create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/access/StAXTest.java
create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/access/TransformTest.java
create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/access/XIncludeTest.java
create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/xmlfiles/XI_simple.xml
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Import.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Import.java
index 098d3c8a260..3c8e1edd5b8 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Import.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Import.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -33,6 +33,7 @@
import javax.xml.XMLConstants;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.SecuritySupport;
+import jdk.xml.internal.XMLSecurityManager;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
@@ -41,7 +42,7 @@
* @author Morten Jorgensen
* @author Erwin Bolwidt
* @author Gunnlaugur Briem
- * @LastModified: May 2021
+ * @LastModified: July 2026
*/
final class Import extends TopLevelElement {
@@ -84,8 +85,9 @@ public void parseContents(final Parser parser) {
if (input == null) {
docToLoad = SystemIDResolver.getAbsoluteURI(docToLoad, currLoadedDoc);
String accessError = SecuritySupport.checkAccess(docToLoad,
- (String)xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET),
- JdkConstants.ACCESS_EXTERNAL_ALL);
+ (XMLSecurityManager)xsltc.getProperty(JdkConstants.SECURITY_MANAGER),
+ XMLConstants.ACCESS_EXTERNAL_STYLESHEET,
+ (String)xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET));
if (accessError != null) {
final ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Include.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Include.java
index ecb03df9f1c..8e3b5530320 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Include.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Include.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -33,6 +33,7 @@
import javax.xml.XMLConstants;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.SecuritySupport;
+import jdk.xml.internal.XMLSecurityManager;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
@@ -41,7 +42,7 @@
* @author Morten Jorgensen
* @author Erwin Bolwidt
* @author Gunnlaugur Briem
- * @LastModified: May 2021
+ * @LastModified: July 2026
*/
final class Include extends TopLevelElement {
@@ -84,8 +85,9 @@ public void parseContents(final Parser parser) {
if (input == null) {
docToLoad = SystemIDResolver.getAbsoluteURI(docToLoad, currLoadedDoc);
String accessError = SecuritySupport.checkAccess(docToLoad,
- (String)xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET),
- JdkConstants.ACCESS_EXTERNAL_ALL);
+ (XMLSecurityManager)xsltc.getProperty(JdkConstants.SECURITY_MANAGER),
+ XMLConstants.ACCESS_EXTERNAL_STYLESHEET,
+ (String)xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET));
if (accessError != null) {
final ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java
index 0dde14f455c..f523b65a2b4 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -60,7 +60,7 @@
* @author G. Todd Miller
* @author Morten Jorgensen
* @author Erwin Bolwidt
- * @LastModified: July 2023
+ * @LastModified: July 2026
*/
public class Parser implements Constants, ContentHandler {
@@ -540,23 +540,20 @@ private SyntaxTreeNode getStylesheet(SyntaxTreeNode root)
return(element);
}
else {
- try {
- String path = _target;
- if (path.indexOf(":")==-1) {
- path = "file:" + path;
- }
- path = SystemIDResolver.getAbsoluteURI(path);
- String accessError = SecuritySupport.checkAccess(path,
- (String)_xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET),
- JdkConstants.ACCESS_EXTERNAL_ALL);
- if (accessError != null) {
- ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
- SecuritySupport.sanitizePath(_target), accessError,
- root);
- throw new CompilerException(msg.toString());
- }
- } catch (IOException ex) {
- throw new CompilerException(ex);
+ String path = _target;
+ if (path.indexOf(":")==-1) {
+ path = "file:" + path;
+ }
+ path = SystemIDResolver.getAbsoluteURI(path);
+ String accessError = SecuritySupport.checkAccess(path,
+ (XMLSecurityManager)_xsltc.getProperty(JdkConstants.SECURITY_MANAGER),
+ XMLConstants.ACCESS_EXTERNAL_STYLESHEET,
+ (String)_xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET));
+ if (accessError != null) {
+ ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
+ SecuritySupport.sanitizePath(_target), accessError,
+ root);
+ throw new CompilerException(msg.toString());
}
return(loadExternalStylesheet(_target));
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java
index 660d1194b30..a3875969bb7 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -24,7 +24,7 @@
/**
* @author Morten Jorgensen
- * @LastModified: Dec 2024
+ * @LastModified: July 2026
*/
public class ErrorMessages extends ListResourceBundle {
@@ -469,7 +469,7 @@ public Object[][] getContents()
* Note to translators: access to the stylesheet target is denied
*/
{ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
- "Could not read stylesheet target ''{0}'', because ''{1}'' access is not allowed due to restriction set by the accessExternalStylesheet property."},
+ "Could not read stylesheet target ''{0}'', because access is not allowed due to restriction set by ''{1}''."},
/*
* Note to translators: This message represents an internal error in
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/LoadDocument.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/LoadDocument.java
index 39084c87f0b..e17407e2831 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/LoadDocument.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/LoadDocument.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -39,7 +39,7 @@
/**
* @author Morten Jorgensen
- * @LastModified: Sept 2021
+ * @LastModified: July 2026
*/
public final class LoadDocument {
@@ -197,12 +197,7 @@ private static DTMAxisIterator document(String uri, String base,
throw new TransletException(e);
}
} else {
- String accessError = SecuritySupport.checkAccess(uri, translet.getAllowedProtocols(), JdkConstants.ACCESS_EXTERNAL_ALL);
- if (accessError != null) {
- ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
- SecuritySupport.sanitizePath(uri), accessError);
- throw new Exception(msg.toString());
- }
+ translet.verifyAccess(uri);
// Parse the input document and construct DOM object
// Trust the DTMManager to pick the right parser and
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
index 1612fd61923..620eb670547 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -25,6 +25,7 @@
import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
import com.sun.org.apache.xalan.internal.xsltc.Translet;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
+import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
import com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter;
import com.sun.org.apache.xalan.internal.xsltc.dom.KeyIndex;
import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
@@ -40,11 +41,14 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Templates;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.JdkXmlUtils;
+import jdk.xml.internal.SecuritySupport;
+import jdk.xml.internal.XMLSecurityManager;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
@@ -54,7 +58,7 @@
* @author Morten Jorgensen
* @author G. Todd Miller
* @author John Howard, JohnH@schemasoft.com
- * @LastModified: Sept 2021
+ * @LastModified: July 2026
*/
public abstract class AbstractTranslet implements Translet {
@@ -115,6 +119,7 @@ public abstract class AbstractTranslet implements Translet {
* protocols allowed for external references set by the stylesheet processing instruction, Document() function, Import and Include element.
*/
private String _accessExternalStylesheet = JdkConstants.EXTERNAL_ACCESS_DEFAULT;
+ private XMLSecurityManager _xsm;
// The error message when access to exteranl resources is rejected
private String _accessErr = null;
@@ -789,6 +794,37 @@ public void setAllowedProtocols(String protocols) {
_accessExternalStylesheet = protocols;
}
+ /**
+ * Returns the XMLSecurityManager
+ */
+ public XMLSecurityManager getXMLSecurityManager() {
+ return _xsm;
+ }
+
+ /**
+ * Sets the XMLSecurityManager
+ * @param xsm the XMLSecurityManager instance
+ */
+ public void setXMLSecurityManager(XMLSecurityManager xsm) {
+ _xsm = xsm;
+ }
+
+ /**
+ * Verifies that access to the resource represented by the systemId is permitted.
+ * @param systemId the systemId
+
+ * @throws TransletException if access is not permitted
+ */
+ public void verifyAccess(String systemId) throws TransletException {
+ String accessError = SecuritySupport.checkAccess(systemId, _xsm,
+ XMLConstants.ACCESS_EXTERNAL_STYLESHEET, _accessExternalStylesheet);
+ if (accessError != null) {
+ ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
+ SecuritySupport.sanitizePath(systemId), accessError);
+ throw new TransletException(msg.toString());
+ }
+ }
+
/**
* Returns the access error.
*/
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
index 41b83bce5df..71aad15b09f 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -58,6 +58,7 @@
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.URIResolver;
import jdk.xml.internal.JdkConstants;
+import jdk.xml.internal.XMLSecurityManager;
/**
@@ -65,7 +66,7 @@
* @author G. Todd Millerj
* @author Jochen Cordes
* @author Santiago Pericas-Geertsen
- * @LastModified: Jan 2025
+ * @LastModified: July 2026
*/
public final class TemplatesImpl implements Templates, Serializable {
static final long serialVersionUID = 673094361519270707L;
@@ -147,6 +148,7 @@ public final class TemplatesImpl implements Templates, Serializable {
* protocols allowed for external references set by the stylesheet processing instruction, Import and Include element.
*/
private transient String _accessExternalStylesheet = JdkConstants.EXTERNAL_ACCESS_DEFAULT;
+ private transient XMLSecurityManager _xsm;
/**
* @serialField _name String The Name of the main class
@@ -240,6 +242,7 @@ private void init(String transletName,
_tfactory = tfactory;
_overrideDefaultParser = tfactory.overrideDefaultParser();
_accessExternalStylesheet = (String) tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
+ _xsm = (XMLSecurityManager) tfactory.getAttribute(JdkConstants.SECURITY_MANAGER);
}
/**
* Need for de-serialization, see readObject().
@@ -540,6 +543,7 @@ private Translet getTransletInstance()
translet.setTemplates(this);
translet.setOverrideDefaultParser(_overrideDefaultParser);
translet.setAllowedProtocols(_accessExternalStylesheet);
+ translet.setXMLSecurityManager(_xsm);
if (_auxClasses != null) {
translet.setAuxiliaryClasses(_auxClasses);
}
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java
index ca56223aa44..14bb3d0df82 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -88,7 +88,7 @@
* @author G. Todd Miller
* @author Morten Jorgensen
* @author Santiago Pericas-Geertsen
- * @LastModified: May 2025
+ * @LastModified: July 2026
*/
public class TransformerFactoryImpl
extends SAXTransformerFactory implements SourceLoader
@@ -515,7 +515,7 @@ else if (ImplPropMap.EXTCLSLOADER.is(name)) {
}
if (_xmlSecurityPropertyMgr != null &&
- _xmlSecurityPropertyMgr.setValue(name, FeaturePropertyBase.State.APIPROPERTY, value)) {
+ _xmlSecurityPropertyMgr.setValue(name, JdkProperty.State.APIPROPERTY, value)) {
_accessExternalDTD = _xmlSecurityPropertyMgr.getValue(
Property.ACCESS_EXTERNAL_DTD);
_accessExternalStylesheet = _xmlSecurityPropertyMgr.getValue(
@@ -572,9 +572,9 @@ else if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
// set external access restriction when FSP is explicitly set
if (value) {
_xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD,
- FeaturePropertyBase.State.FSP, JdkConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
+ JdkProperty.State.FSP, JdkConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
_xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_STYLESHEET,
- FeaturePropertyBase.State.FSP, JdkConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
+ JdkProperty.State.FSP, JdkConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
_accessExternalDTD = _xmlSecurityPropertyMgr.getValue(
Property.ACCESS_EXTERNAL_DTD);
_accessExternalStylesheet = _xmlSecurityPropertyMgr.getValue(
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
index b48b9d2a657..89091355484 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -100,7 +100,7 @@
* @author Morten Jorgensen
* @author G. Todd Miller
* @author Santiago Pericas-Geertsen
- * @LastModified: Jan 2025
+ * @LastModified: July 2026
*/
public final class TransformerImpl extends Transformer
implements DOMCache
@@ -1357,21 +1357,13 @@ public DOM retrieveDocument(String baseURI, String href, Translet translet) {
*/
AbstractTranslet t = (AbstractTranslet)translet;
String systemId = SystemIDResolver.getAbsoluteURI(href, baseURI);
- String errMsg = null;
- try {
- String accessError = SecuritySupport.checkAccess(systemId,
- t.getAllowedProtocols(),
- JdkConstants.ACCESS_EXTERNAL_ALL);
- if (accessError != null) {
- ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
- SecuritySupport.sanitizePath(href), accessError);
- errMsg = msg.toString();
- }
- } catch (IOException ioe) {
- errMsg = ioe.getMessage();
- }
- if (errMsg != null) {
- t.setAccessError(errMsg);
+ String accessError = SecuritySupport.checkAccess(systemId,
+ t.getXMLSecurityManager(), XMLConstants.ACCESS_EXTERNAL_STYLESHEET,
+ t.getAllowedProtocols());
+ if (accessError != null) {
+ ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
+ SecuritySupport.sanitizePath(href), accessError);
+ t.setAccessError(msg.toString());
return null;
}
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java
index ccaa9f6c5dd..e9cfd0ff388 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java
@@ -2023,7 +2023,8 @@ public String getDriverName(Driver driver) {
String checkAccess(String systemId, String allowedProtocols) throws IOException {
String baseSystemId = fEntityScanner.getBaseSystemId();
String expandedSystemId = XMLEntityManager.expandSystemId(systemId, baseSystemId, fStrictURI);
- return SecuritySupport.checkAccess(expandedSystemId, allowedProtocols, JdkConstants.ACCESS_EXTERNAL_ALL);
+ return SecuritySupport.checkAccess(expandedSystemId, fSecurityManager,
+ XMLConstants.ACCESS_EXTERNAL_DTD, allowedProtocols);
}
//
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
index 99b4193b39c..db598c6c356 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -93,7 +93,7 @@
* @author K.Venugopal SUN Microsystems
* @author Neeraj Bajaj SUN Microsystems
* @author Sunitha Reddy SUN Microsystems
- * @LastModified: May 2025
+ * @LastModified: July 2026
*/
public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
@@ -1361,20 +1361,15 @@ public void startEntity(boolean isGE, String entityName, boolean literal)
if (external) {
staxInputSource = resolveEntityAsPerStax(externalEntity.entityLocation);
- /** xxx: Waiting from the EG
- * //simply return if there was entity resolver registered and application
- * //returns either XMLStreamReader or XMLEventReader.
- * if(staxInputSource.hasXMLStreamOrXMLEventReader()) return ;
- */
xmlInputSource = staxInputSource.getXMLInputSource() ;
if (!fISCreatedByResolver) {
- String accessError = SecuritySupport.checkAccess(expandedSystemId,
- fAccessExternalDTD, JdkConstants.ACCESS_EXTERNAL_ALL);
+ String accessError = SecuritySupport.checkAccess(expandedSystemId, fSecurityManager,
+ XMLConstants.ACCESS_EXTERNAL_DTD, fAccessExternalDTD);
if (accessError != null) {
- fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN,
- "AccessExternalEntity",
- new Object[] { SecuritySupport.sanitizePath(expandedSystemId), accessError },
- XMLErrorReporter.SEVERITY_FATAL_ERROR);
+ fErrorReporter.reportError(this.getEntityScanner(), XMLMessageFormatter.XML_DOMAIN,
+ "AccessExternalEntity",
+ new Object[]{SecuritySupport.sanitizePath(expandedSystemId), accessError},
+ XMLErrorReporter.SEVERITY_FATAL_ERROR);
}
}
}
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties
index 25182a06a3c..b51e912370a 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties
@@ -283,8 +283,9 @@
# Entity related messages
# 3.1 Start-Tags, End-Tags, and Empty-Element Tags
ReferenceToExternalEntity = The external entity reference \"&{0};\" is not permitted in an attribute value.
- AccessExternalDTD = External DTD: Failed to read external DTD ''{0}'', because ''{1}'' access is not allowed due to restriction set by the accessExternalDTD property.
- AccessExternalEntity = External Entity: Failed to read external document ''{0}'', because ''{1}'' access is not allowed due to restriction set by the accessExternalDTD property.
+ AccessExternalDTD = External DTD: Failed to read external DTD ''{0}'', because access is not allowed due to restriction set by ''{1}''.
+ AccessExternalEntity = External Entity: Failed to read external document ''{0}'', because access is not allowed due to restriction set by ''{1}''.
+ ResourceAccess = Resource Access: Failed to read external document ''{0}'', because the ''{1}'' property is set to not allow accessing the document.
# 4.1 Character and Entity References
EntityNotDeclared = The entity \"{0}\" was referenced, but not declared.
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties
index 4f15b428c8b..2004e41e51d 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties
@@ -108,7 +108,7 @@
#schema valid (3.X.3)
- schema_reference.access = schema_reference: Failed to read schema document ''{0}'', because ''{1}'' access is not allowed due to restriction set by the accessExternalSchema property.
+ schema_reference.access = schema_reference: Failed to read schema document ''{0}'', because access is not allowed due to restriction set by ''{1}''.
schema_reference.4 = schema_reference.4: Failed to read schema document ''{0}'', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not .
src-annotation = src-annotation: elements can only contain and elements, but ''{0}'' was found.
src-attribute.1 = src-attribute.1: The properties ''default'' and ''fixed'' cannot both be present in attribute declaration ''{0}''. Use only one of them.
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaLoader.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaLoader.java
index b4b76546d6d..c884eec6f9f 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaLoader.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -103,7 +103,7 @@
* @xerces.internal
*
* @author Neil Graham, IBM
- * @LastModified: May 2025
+ * @LastModified: July 2026
*/
public class XMLSchemaLoader implements XMLGrammarLoader, XMLComponent, XSElementDeclHelper,
@@ -285,6 +285,7 @@ public class XMLSchemaLoader implements XMLGrammarLoader, XMLComponent, XSElemen
private CMBuilder fCMBuilder;
private XSDDescription fXSDDescription = new XSDDescription();
private String faccessExternalSchema = JdkConstants.EXTERNAL_ACCESS_DEFAULT;
+ private XMLSecurityManager fXMLScurityManager = null;
private WeakHashMap
+ *
+ * The {@link #allows(java.net.URI)} method determines whether a given URI is permitted according to this rule.
+ *
+ */
+public class AccessRule {
+ public static final AccessRule RULE_NONE = new AccessRule("");
+ public static final AccessRule RULE_ALL = new AccessRule("*");
+ private final List rules = new ArrayList<>();
+ private final boolean allowAll;
+ private final boolean denyAll;
+ private final String rawInput;
+
+ public AccessRule(String input) {
+ this.rawInput = input;
+ String trimmedInput = input == null ? "" : input.trim();
+ if (trimmedInput.equals("*")) {
+ allowAll = true;
+ denyAll = false;
+ return;
+ } else if (trimmedInput.isEmpty()) {
+ allowAll = false;
+ denyAll = true;
+ return;
+ }
+ allowAll = false;
+ denyAll = false;
+ String[] tokens = input.split(",");
+ for (String rawToken : tokens) {
+ String token = checkToken(input, rawToken);
+ rules.add(URIPatternRule.parse(token));
+ }
+ }
+
+ private String checkToken(String input, String rawToken) {
+ String token = rawToken.trim();
+ if (token.isEmpty() && !rules.isEmpty()) {
+ throw new IllegalArgumentException("Invalid format for the resource.access property: "
+ + input + ". Empty rule cannot coexist with other rules.");
+ } else if (token.equals("*") && !rules.isEmpty()) {
+ throw new IllegalArgumentException("Invalid format for the resource.access property: "
+ + input + ". All access (*) rule cannot coexist with other rules.");
+ }
+ return token;
+ }
+
+ public boolean allows(URI uri) {
+ if (denyAll) return false;
+ if (allowAll) return true;
+ for (URIPatternRule rule : rules) {
+ if (rule.matches(uri)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() { return rawInput; }
+
+ /**
+ * Represents a parsed URI-based pattern rule.
+ */
+ public static class URIPatternRule {
+ private final String scheme;
+ private final HostPattern hostPattern;
+ private final Integer port; // null if not set
+ private final PathPattern pathPattern;
+ private URIPatternRule(String scheme, HostPattern hostPattern, Integer port, PathPattern pathPattern) {
+ this.scheme = scheme;
+ this.hostPattern = hostPattern;
+ this.port = port;
+ this.pathPattern = pathPattern;
+ }
+
+ /**
+ * Parses the specified pattern string.
+ * Example patterns: file:*, file:/foo, http://foo.com, https://*.foo.com:8080
+ * @param pattern the pattern string
+ * @return an instance of URIPatternRule from the pattern string
+ */
+ public static URIPatternRule parse(String pattern) {
+ // Syntax: [scheme]:/{0,3}[host[:port]][/path-pattern]
+ int schemeSep = pattern.indexOf(':');
+ if (schemeSep <= 0)
+ throw new IllegalArgumentException("Missing or invalid scheme in resource access pattern: " + pattern);
+
+ String scheme = pattern.substring(0, schemeSep).toLowerCase(Locale.ROOT);
+ if (!isSupportedScheme(scheme))
+ throw new IllegalArgumentException("Unsupported scheme in resource access pattern: " + pattern);
+
+ String rest = pattern.substring(schemeSep + 1);
+ int slashCount = countSlashes(rest);
+
+ if ("jrt".equals(scheme) || ("file".equals(scheme) && slashCount != 2)) {
+ return parseLocalPath(scheme, slashCount, rest, pattern);
+ }
+
+ return parseAuthorityForm(scheme, slashCount, rest, pattern);
+ }
+
+ private static URIPatternRule parseAuthorityForm(String scheme, int slashCount,
+ String rest, String pattern) {
+ // Authority must have two leading slashes.
+ if (slashCount != 2) {
+ throw new IllegalArgumentException("Rule for scheme '" + scheme
+ + "' must specify an authority: " + pattern);
+ }
+ String afterSlashes = rest.substring(2);
+ if (afterSlashes.isEmpty() || afterSlashes.startsWith(":") || afterSlashes.startsWith("/")) {
+ throw new IllegalArgumentException("Rule for scheme '" + scheme
+ + "' must specify a non-empty host: " + pattern);
+ }
+
+ String hostPart;
+ String pathPart = null;
+
+ int slashIndex = afterSlashes.indexOf('/');
+ if (slashIndex >= 0) {
+ hostPart = afterSlashes.substring(0, slashIndex);
+ pathPart = afterSlashes.substring(slashIndex);
+ } else {
+ hostPart = afterSlashes;
+ }
+
+ int portSep;
+ int pos = 0;
+ // Check IPv6 literal first as ':' within the brackets belong to the host
+ if (hostPart.startsWith("[")) {
+ pos = hostPart.indexOf(']');
+ if (pos < 0) {
+ throw new IllegalArgumentException("Invalid IPv6 host: " + pattern);
+ }
+ }
+ portSep = hostPart.indexOf(':', pos);
+
+ String host;
+ Integer port = null;
+
+ if (portSep >= 0) {
+ if ("file".equals(scheme)) {
+ throw new IllegalArgumentException("Port component is not supported for file URI: " + pattern);
+ }
+ host = hostPart.substring(0, portSep);
+ String portPart = hostPart.substring(portSep + 1);
+ port = parsePortNumber(portPart, hostPart);
+ } else {
+ host = hostPart;
+ }
+
+ HostPattern hostPattern = HostPattern.of(host);
+
+ PathPattern pathPattern = null;
+ if (pathPart != null) {
+ if (pathPart.isEmpty() || pathPart.equals("/*")) {
+ pathPattern = PathPattern.of("*");
+ } else {
+ pathPattern = PathPattern.of(pathPart);
+ }
+ }
+
+ return new URIPatternRule(scheme, hostPattern, port, pathPattern);
+ }
+
+ private static URIPatternRule parseLocalPath(
+ String scheme, int slashCount, String rest, String pattern) {
+
+ // Remove the leading slashes
+ String path = rest.substring(slashCount);
+
+ if (path.isEmpty()) {
+ throw new IllegalArgumentException(
+ scheme + " rule must have non-empty path: " + pattern);
+ }
+
+ if ("*".equals(path)) {
+ return new URIPatternRule(scheme, null, null, PathPattern.of("*"));
+ }
+
+ // add a slash for the path pattern
+ if (!path.startsWith("/")) {
+ path = "/" + path;
+ }
+
+ return new URIPatternRule(scheme, null, null, PathPattern.of(path));
+ }
+
+ //The slash following the scheme may appear one to three times.
+ private static int countSlashes(String s) {
+ int count = 0;
+ while (count < s.length() && s.charAt(count) == '/') {
+ count++;
+ if (count > 3) {
+ throw new IllegalArgumentException("Too many leading slashes: " + s);
+ }
+ }
+ return count;
+ }
+
+ public boolean matches(URI uri) {
+ if (uri != null && "jar".equalsIgnoreCase(uri.getScheme())) {
+ URI jarFile = getJarFileURI(uri);
+ return jarFile != null && matches(jarFile);
+ }
+
+ // Resource access matching applies only to hierarchical URIs. Opaque URIs
+ // have no hierarchical host/port/path components to match.
+ if (uri == null || uri.isOpaque()) return false;
+
+ // match scheme
+ String testScheme = uri.getScheme();
+ if (testScheme == null || !testScheme.equalsIgnoreCase(scheme)) return false;
+
+ // match host
+ String testHost = uri.getHost();
+ if (hostPattern == null) {
+ // A hostless rule only matches a hostless URI.
+ if (testHost != null) {
+ return false;
+ }
+ } else {
+ // A host-based rule requires a matching host.
+ if (!hostPattern.matches(testHost)) return false;
+ if (port != null && port != (uri.getPort() == -1 ? getDefaultPort(scheme) : uri.getPort())) return false;
+ }
+ if (pathPattern != null) {
+ return pathPattern.matches(uri.getPath());
+ }
+
+ return true;
+ }
+
+ private static URI getJarFileURI(URI jarURI) {
+ String schemeSpecificPart = jarURI.getRawSchemeSpecificPart();
+ int separator = schemeSpecificPart.indexOf("!/");
+ if (separator < 0) {
+ return null;
+ }
+ try {
+ return URI.create(schemeSpecificPart.substring(0, separator));
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+ private static boolean isSupportedScheme(String scheme) {
+ return switch (scheme) {
+ case "http", "https", "ftp", "file", "jrt" -> true;
+ default -> false;
+ };
+ }
+
+ /**
+ * {@return the port number.}
+ * @throws IllegalArgumentException if portPart is not an integer
+ * between 0 and 65535 (valid TCP/UDP port range).
+ */
+ private static int parsePortNumber(String portPart, String pattern) {
+ if (portPart.isEmpty()) {
+ throw new IllegalArgumentException("Empty port: " + pattern);
+ }
+ try {
+ int port = Integer.parseInt(portPart);
+ if (port < 0 || port > 65535)
+ throw new IllegalArgumentException("Port must be 0-65535: " + pattern);
+ return port;
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Port must be numeric: " + pattern, e);
+ }
+ }
+
+ // standard ports for known schemes
+ private static int getDefaultPort(String scheme) {
+ return switch (scheme) {
+ case "http" -> 80;
+ case "https" -> 443;
+ case "ftp" -> 21;
+ default -> -1;
+ };
+ }
+ }
+
+
+ // Host pattern matching for exact, IPv4 and IPv6 hosts.
+ public static class HostPattern {
+ private final String pattern;
+ private final boolean isAny;
+ private final boolean isSubdomainPattern;
+ private final byte[] literalAddress;
+
+ private HostPattern(String pattern, boolean isAny, boolean isSubdomainPattern, byte[] literalAddress) {
+ this.pattern = pattern;
+ this.isAny = isAny;
+ this.isSubdomainPattern = isSubdomainPattern;
+ this.literalAddress = literalAddress;
+ }
+
+ public static HostPattern of(String hostPattern) {
+ String trimmed = hostPattern.trim();
+ if (trimmed.equals("*")) {
+ return new HostPattern("*", true, false, null);
+ }
+ if (trimmed.startsWith("*.")) {
+ // *.example.com
+ return new HostPattern(trimmed.substring(2).toLowerCase(Locale.ROOT), false, true, null);
+ }
+ byte[] literalAddress = parseLiteralAddress(trimmed);
+ if (literalAddress != null)
+ return new HostPattern(trimmed, false, false, literalAddress);
+ // Otherwise, treat as literal domain
+ return new HostPattern(trimmed.toLowerCase(Locale.ROOT), false, false, null);
+ }
+
+ public boolean matches(String testHost) {
+ if (isAny) return true;
+ if (testHost == null) return false;
+ if (literalAddress != null) {
+ byte[] testAddress = parseLiteralAddress(testHost);
+ return testAddress != null && Arrays.equals(literalAddress, testAddress);
+ }
+ testHost = testHost.toLowerCase(Locale.ROOT);
+ // Subdomain wildcard
+ if (isSubdomainPattern) {
+ return testHost.endsWith("." + pattern);
+ }
+ // Exact match (domain, IPv4, or IPv6)
+ return testHost.equals(pattern);
+ }
+
+ private static byte[] parseLiteralAddress(String host) {
+ try {
+ return Inet4Address.ofLiteral(host).getAddress();
+ } catch (IllegalArgumentException ignored) {
+ // Not an IPv4 literal; try IPv6 below.
+ }
+
+ try {
+ return Inet6Address.ofLiteral(host).getAddress();
+ } catch (IllegalArgumentException ignored) {
+ return null;
+ }
+ }
+ }
+
+ public static class PathPattern {
+ private final String pattern; // e.g. /dtds/* or /*
+ private final boolean isAny;
+ private final boolean isDirectory; // endsWith /*
+
+ private PathPattern(String pattern, boolean isAny, boolean isDirectory) {
+ this.pattern = pattern;
+ this.isAny = isAny;
+ this.isDirectory = isDirectory;
+ }
+
+ public static PathPattern of(String pattern) {
+ pattern = (pattern == null || pattern.isEmpty()) ? "/" : pattern;
+ // supports *, /foo/*, /foo/bar
+ if (pattern.equals("*") || pattern.equals("/*")) {
+ return new PathPattern(pattern, true, false);
+ }
+ // Now validate. Note: no validation needed if the whole component is a wildcard
+ validatePath(pattern);
+ if (pattern.endsWith("/*")) {
+ return new PathPattern(pattern.substring(0, pattern.length() - 2), false, true);
+ }
+ return new PathPattern(pattern, false, false);
+ }
+
+ public boolean matches(String testPath) {
+ if (isAny) return true;
+ if (testPath == null) return false;
+ testPath = normalizePath(testPath);
+ if (isDirectory) {
+ // Path starts with this directory
+ return testPath.startsWith(pattern + "/") || testPath.equals(pattern);
+ }
+ return testPath.equals(pattern);
+ }
+
+ /*
+ * Validates the path component. A path is either a literal file or directory
+ * or wildcard (*).
+ */
+ private static void validatePath(String pathPart) {
+ if (pathPart != null) {
+ if (pathPart.indexOf("//") >= 0) {
+ throw new IllegalArgumentException(
+ "Path component must not contain empty segments: " + pathPart);
+ }
+
+ for (String segment : pathPart.split("/")) {
+ if (isDotSegment(segment)) {
+ throw new IllegalArgumentException(
+ "Path component must not contain dot segments: " + pathPart);
+ }
+ }
+ }
+ }
+ }
+
+ // Normalizes URI path for rule matching, consistent with URI.normalize().
+ private static String normalizePath(String path) {
+ boolean absolute = path.startsWith("/");
+ List segments = new ArrayList<>();
+ boolean isDotSegment = false;
+ for (String segment : path.split("/")) {
+ if (segment.isEmpty() || segment.equals(".")) {
+ continue;
+ }
+ // URI spec: A ".." segment is removed only if it is preceded by a non-".." segment
+ if (segment.equals("..")) {
+ if (!segments.isEmpty() && !segments.get(segments.size() - 1).equals("..")) {
+ segments.remove(segments.size() - 1);
+ continue;
+ }
+ }
+ segments.add(segment);
+ }
+ String normalizedPath = String.join("/", segments);
+ return absolute ? "/" + normalizedPath : normalizedPath;
+ }
+
+ /*
+ * Checks whether the specified path segment represents a dot segment,
+ * {@code "."} or {@code ".."}, or encoded as {@code "%2e"}.
+ */
+ private static boolean isDotSegment(String segment) {
+ int len = segment.length();
+
+ if (len == 0 || len > 6) {
+ return false;
+ } else if (".".equals(segment) || "..".equals(segment)) {
+ return true;
+ } else if (segment.indexOf('%') < 0) {
+ return false;
+ }
+
+ // encoded dot segment
+ int dots = 0;
+ for (int i = 0; i < len;) {
+ if (segment.charAt(i) == '.') {
+ dots++;
+ i++;
+ } else if (i + 2 < len
+ && segment.charAt(i) == '%'
+ && segment.charAt(i + 1) == '2'
+ && (segment.charAt(i + 2) == 'e'
+ || segment.charAt(i + 2) == 'E')) {
+ dots++;
+ i += 3;
+ } else {
+ return false;
+ }
+ }
+
+ return dots == 1 || dots == 2;
+ }
+}
diff --git a/src/java.xml/share/classes/jdk/xml/internal/FeaturePropertyBase.java b/src/java.xml/share/classes/jdk/xml/internal/FeaturePropertyBase.java
index 0a17ffa1121..d311b778723 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/FeaturePropertyBase.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/FeaturePropertyBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
* 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,23 +24,12 @@
*/
package jdk.xml.internal;
+import jdk.xml.internal.JdkProperty.State;
/**
* This is the base class for features and properties
*/
public abstract class FeaturePropertyBase {
-
- /**
- * States of the settings of a property, in the order: default value, value
- * set by FEATURE_SECURE_PROCESSING, jaxp.properties file, jaxp system
- * properties, and jaxp api properties
- */
- public static enum State {
- //this order reflects the overriding order
- DEFAULT, FSP, JAXPDOTPROPERTIES, SYSTEMPROPERTY, APIPROPERTY
- }
-
-
/**
* Values of the properties as defined in enum Properties
*/
diff --git a/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java b/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java
index 412eddb5ab0..927d19bc3b3 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -311,6 +311,17 @@ public final class JdkConstants {
//public static final int IGNORE = 1; // same as that of DTD
public static final int STRICT = 2;
+ /**
+ * System Property for the Resource Access property
+ * @since 26
+ */
+ public static final String RESOURCE_ACCESS = "jdk.xml.resource.access";
+
+ // Integer Values that maps to broad access settings such as *, remote
+ public static final int ACCESS_NONE = 0;
+ public static final int ACCESS_ALL = 1; // same as that of DTD
+ public static final int ACCESS_REMOTE = 2;
+
/**
* Values for a feature
*/
diff --git a/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java b/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java
index 9e718b264e4..f66463833ef 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -113,7 +113,7 @@ public static boolean setProperty(XMLSecurityManager xsm, XMLSecurityPropertyMan
return xsm.setLimit(property, JdkProperty.State.APIPROPERTY, value);
} else if (xspm != null && xspm.find(property) != null) {
- return xspm.setValue(property, FeaturePropertyBase.State.APIPROPERTY, value);
+ return xspm.setValue(property, JdkProperty.State.APIPROPERTY, value);
}
return false;
}
diff --git a/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java b/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
index 478d12220d7..2787ba67b5f 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,15 +29,18 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Paths;
import java.security.CodeSource;
import java.text.MessageFormat;
+import java.util.HashSet;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
+import java.util.Set;
/**
* This class contains utility methods for reading resources in the JAXP packages
@@ -267,66 +270,90 @@ public static String sanitizePath(String input) {
return input;
}
+ /**
+ * Checks whether access to resource represented by the systemId is permitted
+ * by Resource Access and/or External Access Properties (EAP)
+ * @param systemId the systemId
+ * @param xsm the XMLSecurityManager
+ * @param eap the External Access Property, e.g. ACCESS_EXTERNAL_DTD
+ * @param allowedProtocols protocols allowed by the EAP
+ * @return true if access is permitted, false otherwise
+ * @throws IOException if the systemId is invalid
+ */
+ public static String checkAccess(String systemId, XMLSecurityManager xsm,
+ String eap, String allowedProtocols) {
+ String errMsg = null;
+ if (xsm != null && !xsm.isAccessAllowed(systemId)) {
+ errMsg = "Resource Access (jdk.xml.resource.access)";
+ }
+
+ if (!checkAccess(systemId, allowedProtocols)) {
+ errMsg = (errMsg != null) ? errMsg + " and " + eap : eap;
+ }
+ return errMsg;
+ }
+
/**
* Check the protocol used in the systemId against allowed protocols
*
* @param systemId the Id of the URI
* @param allowedProtocols a list of allowed protocols separated by comma
- * @param accessAny keyword to indicate allowing any protocol
- * @return the name of the protocol if rejected, null otherwise
+ * @return true if access is permitted, false otherwise
*/
- public static String checkAccess(String systemId, String allowedProtocols,
- String accessAny) throws IOException {
+ public static boolean checkAccess(String systemId, String allowedProtocols) {
+ if (Utils.isEmpty(allowedProtocols)) {
+ return false;
+ }
if (systemId == null || (allowedProtocols != null &&
- allowedProtocols.equalsIgnoreCase(accessAny))) {
- return null;
+ allowedProtocols.equalsIgnoreCase(JdkConstants.ACCESS_EXTERNAL_ALL))) {
+ return true;
}
- String protocol;
- if (!systemId.contains(":")) {
- protocol = "file";
+ URI uri = Utils.createURI(systemId);
+ String scheme = uri.getScheme();
+ if (scheme == null) {
+ scheme = "file";
} else {
- @SuppressWarnings("deprecation")
- URL url = new URL(systemId);
- protocol = url.getProtocol();
- if (protocol.equalsIgnoreCase("jar")) {
- String path = url.getPath();
- protocol = path.substring(0, path.indexOf(":"));
- } else if (protocol.equalsIgnoreCase("jrt")) {
- // if the systemId is "jrt" then allow access if "file" allowed
- protocol = "file";
+ scheme = scheme.toLowerCase(Locale.ROOT);
+ if ("jar".equals(scheme)) {
+ String ssp = uri.getSchemeSpecificPart(); // e.g. file:/x.jar!/a.xml
+ int sep = ssp.indexOf("!/");
+ if (sep != -1) {
+ URI nested = Utils.createURI(ssp.substring(0, sep));
+ String nestedScheme = nested.getScheme();
+ if (nestedScheme != null) {
+ scheme = nestedScheme.toLowerCase(Locale.ROOT);
+ }
+ }
+ } else if ("jrt".equals(scheme)) {
+ // allow access if it's "file"
+ scheme = "file";
}
}
- if (isProtocolAllowed(protocol, allowedProtocols)) {
- //access allowed
- return null;
- } else {
- return protocol;
- }
+ Set allowed = parseProtocols(allowedProtocols);
+ return allowed.contains(scheme);
}
/**
- * Check if the protocol is in the allowed list of protocols. The check
- * is case-insensitive while ignoring whitespaces.
- *
- * @param protocol a protocol
- * @param allowedProtocols a list of allowed protocols
- * @return true if the protocol is in the list
+ * Parses allowed protocols.
+ * @param protocols the protocol setting
+ * @return a set containing allowed protocols
*/
- private static boolean isProtocolAllowed(String protocol, String allowedProtocols) {
- if (allowedProtocols == null) {
- return false;
- }
- String temp[] = allowedProtocols.split(",");
- for (String t : temp) {
- t = t.trim();
- if (t.equalsIgnoreCase(protocol)) {
- return true;
- }
- }
- return false;
- }
+ private static Set parseProtocols(String protocols) {
+ Set set = new HashSet<>();
+ if (protocols == null || protocols.isEmpty()) {
+ return set;
+ }
+
+ for (String p : protocols.split(",")) {
+ String trimmed = p.trim().toLowerCase(Locale.ROOT);
+ if (!trimmed.isEmpty()) {
+ set.add(trimmed);
+ }
+ }
+ return set;
+ }
public static ClassLoader getContextClassLoader() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
diff --git a/src/java.xml/share/classes/jdk/xml/internal/Utils.java b/src/java.xml/share/classes/jdk/xml/internal/Utils.java
index 96d9b1b9521..f7f5c49387b 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/Utils.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/Utils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
package jdk.xml.internal;
import java.lang.reflect.Array;
+import java.net.URI;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Supplier;
@@ -132,6 +134,52 @@ public static Stream streamOfIfNonNull(final T... values) {
* @return {@code true} if the CharSequence is empty or null
*/
public static boolean isEmpty(final CharSequence cs) {
- return cs == null || cs.length() == 0;
+ return cs == null || cs.isEmpty();
+ }
+
+ /**
+ * Checks if a CharSequence is not null and empty ("").
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is not null and empty ("")
+ */
+ public static boolean isNotEmpty(final CharSequence cs) {
+ return cs != null && !cs.isEmpty();
+ }
+
+ /**
+ * Checks if a CharSequence is not null and empty (""), and also does not end
+ * with a wildcard (*).
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is not null and empty ("") and does
+ * not end with a wildcard
+ */
+ public static boolean isNotEmptyOrWildcard(final CharSequence cs) {
+ return cs != null && !cs.isEmpty() && (cs.charAt(cs.length() - 1) != '*');
+ }
+
+ /**
+ * Creates a {@link URI} instance from a systemId.
+ * This method handles strings that are either absolute URIs or local file
+ * system paths.
+ *
+ * @param systemId the systemId
+ * @return a {@link URI} instance corresponding to the systemId
+ */
+ public static URI createURI(String systemId) {
+ if (systemId == null) {
+ return null;
+ }
+
+ try {
+ URI uri = new URI(systemId);
+
+ if (uri.getScheme() == null) {
+ return Path.of(systemId).toUri();
+ }
+ return uri;
+ } catch (Exception e) {
+ // fallback for paths with illegal characters (e.g. spaces)
+ return Path.of(systemId).toUri();
+ }
}
}
diff --git a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java
index a1687c420c3..336b101f8ac 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
import com.sun.org.apache.xerces.internal.util.SecurityManager;
+
+import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -82,6 +84,17 @@ public final class XMLSecurityManager implements Cloneable {
CR_MAP = Collections.unmodifiableMap(map);
}
+ // Valid values for Resource Access, and mappings between the string and
+ // integer values
+ static final Map RA_MAP;
+ // Source Level JDK 8
+ static {
+ Map map = new HashMap<>();
+ map.put("*", 0);
+ map.put("", 2);
+ RA_MAP = Collections.unmodifiableMap(map);
+ }
+
// Value converter for properties of type Boolean
private static final BooleanMapper BOOLMAPPER = new BooleanMapper();
@@ -94,6 +107,9 @@ public final class XMLSecurityManager implements Cloneable {
// Catalog Resolve value mapper
private static final StringMapper CRMAPPER = new StringMapper(CR_MAP);
+ // Resource Access value mapper
+ private static final StringMapper RAMAPPER = new StringMapper(RA_MAP);
+
/**
* Limits managed by the security manager
*/
@@ -129,6 +145,8 @@ public static enum Limit {
STAX_SUPPORT_DTD("supportDTD", XMLInputFactory.SUPPORT_DTD, null, null, 1, 1, Processor.PARSER, BOOLMAPPER),
JDKCATALOG_RESOLVE("JDKCatalogResolve", JdkConstants.JDKCATALOG_RESOLVE, JdkConstants.JDKCATALOG_RESOLVE, null,
JdkConstants.CONTINUE, JdkConstants.CONTINUE, Processor.PARSER, CRMAPPER),
+ RESOURCE_ACCESS("ResourceAccess", JdkConstants.RESOURCE_ACCESS, JdkConstants.RESOURCE_ACCESS, null,
+ JdkConstants.ALLOW, JdkConstants.ALLOW, Processor.PARSER, RAMAPPER),
;
final String key;
@@ -262,6 +280,8 @@ public static enum Processor {
private final int indexEntityCountInfo = 10000;
private String printEntityCountInfo = "";
+ private AccessRule accessRule = null;
+
/**
* Default constructor. Establishes default values for known security
* vulnerabilities.
@@ -289,6 +309,11 @@ public XMLSecurityManager(boolean secureProcessing) {
states[limit.ordinal()] = State.DEFAULT;
}
}
+ if (secureProcessing) {
+ accessRule = (Limit.RESOURCE_ACCESS.secureValue == JdkConstants.ALLOW) ? AccessRule.RULE_ALL : AccessRule.RULE_NONE;
+ } else {
+ accessRule = (Limit.RESOURCE_ACCESS.defaultValue() == JdkConstants.ALLOW) ? AccessRule.RULE_ALL : AccessRule.RULE_NONE;
+ }
}
/**
@@ -380,6 +405,15 @@ public boolean isSecureProcessingSet() {
* @return the limit's new name if found, null otherwise
*/
public String find(String propertyName) {
+ /*
+ * Access property is unique in its value type. Using the SecurityManager
+ * infrastructure, but handles differently than other limits
+ */
+ if (Limit.RESOURCE_ACCESS.is(propertyName)) {
+ return (Limit.RESOURCE_ACCESS.systemProperty != null)
+ ? Limit.RESOURCE_ACCESS.systemProperty
+ : Limit.RESOURCE_ACCESS.apiProperty;
+ }
for (Limit limit : Limit.values()) {
if (limit.is(propertyName)) {
// current spec: new property name == systemProperty
@@ -440,6 +474,24 @@ public void setLimit(Limit limit, State state, int value) {
* @param value the value of the property
*/
public void setLimit(Limit limit, State state, Object value) {
+ /*
+ * Access property is unique in its value type. Using the SecurityManager
+ * infrastructure, but handles differently than other limits
+ */
+ if (limit == Limit.RESOURCE_ACCESS) {
+ int index = limit.ordinal();
+ if (state.compareTo(states[index]) >= 0) {
+ String ruleValue = (String)value;
+ AccessRule rule = new AccessRule(ruleValue);
+ int intValue = limit.mapper().toInt(ruleValue);
+ accessRule = rule;
+ values[index] = intValue;
+ states[index] = state;
+ isSet[index] = true;
+ }
+ return;
+ }
+
int intValue = limit.mapper().toInt(value);
if (intValue < 0) {
intValue = 0;
@@ -469,6 +521,29 @@ public void setLimit(int index, State state, int value) {
}
}
+ public AccessRule getAccessRule() {
+ return accessRule;
+ }
+
+ public boolean isAccessAllowed(String systemId) {
+ URI uri = Utils.createURI(systemId);
+ if (uri == null) return true;
+ return isAccessAllowed(uri);
+ }
+
+ /**
+ * Checks the RESOURCE_ACCESS property to see if access to the specified
+ * uri is allowed.
+ *
+ * @param uri the specified uri
+ * @return true if the RESOURCE_ACCESS property is set to allow access to the
+ * specified uri, false otherwise
+ */
+ public boolean isAccessAllowed(URI uri) {
+ return accessRule.allows(uri);
+ }
+
+
/**
* Return the value of the specified property
*
@@ -477,6 +552,10 @@ public void setLimit(int index, State state, int value) {
* by this manager, its value shall not be null.
*/
public String getLimitAsString(String propertyName) {
+ if (Limit.RESOURCE_ACCESS.is(propertyName)) {
+ return accessRule.toString();
+ }
+
int index = getIndex(propertyName);
if (index > -1) {
return getLimitValueByIndex(index);
@@ -620,10 +699,10 @@ public boolean isOverLimit(int index, String entityName, int size,
}
/**
- * Check against cumulated value
+ * Check limit against the cumulated value
*
* @param limit the type of the limit property
- * @param size the size (count or length) of the entity
+ * @param limitAnalyzer the limit analyzer
* @return true if the size is over the limit, false otherwise
*/
public boolean isOverLimit(Limit limit, XMLLimitAnalyzer limitAnalyzer) {
@@ -739,7 +818,7 @@ private boolean getSystemProperty(Limit limit, String sysPropertyName) {
try {
String value = System.getProperty(sysPropertyName);
- if (value != null && !value.equals("")) {
+ if (isPropertyValuePresent(limit, value)) {
setLimit(limit, State.SYSTEMPROPERTY, value);
return true;
}
@@ -760,7 +839,7 @@ private boolean getSystemProperty(Limit limit, String sysPropertyName) {
private boolean getPropertyConfig(Limit limit, String sysPropertyName) {
try {
String value = SecuritySupport.readConfig(sysPropertyName);
- if (value != null && !value.equals("")) {
+ if (isPropertyValuePresent(limit, value)) {
setLimit(limit, State.JAXPDOTPROPERTIES, value);
return true;
}
@@ -771,6 +850,10 @@ private boolean getPropertyConfig(Limit limit, String sysPropertyName) {
return false;
}
+ private boolean isPropertyValuePresent(Limit limit, String value) {
+ return value != null && (!value.isEmpty() || limit == Limit.RESOURCE_ACCESS);
+ }
+
/**
* Convert a value set through setProperty to XMLSecurityManager.
* If the value is an instance of XMLSecurityManager, use it to override the default;
diff --git a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityPropertyManager.java b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityPropertyManager.java
index ff9ab621fab..226a5e34fbc 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityPropertyManager.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityPropertyManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
package jdk.xml.internal;
import javax.xml.XMLConstants;
+import jdk.xml.internal.JdkProperty.State;
/**
* This class manages security related properties
@@ -161,6 +162,15 @@ public String getValue(Property property) {
return values[property.ordinal()];
}
+ /**
+ * {@return the state of the specified property}
+ *
+ * @param property the specified property
+ */
+ public State getState(Property property) {
+ return states[property.ordinal()];
+ }
+
/**
* Read from system properties, or those in jaxp.properties
*/
diff --git a/src/java.xml/share/classes/module-info.java b/src/java.xml/share/classes/module-info.java
index 1b4f345eb72..a27354ff6a6 100644
--- a/src/java.xml/share/classes/module-info.java
+++ b/src/java.xml/share/classes/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,8 @@
* questions.
*/
+import java.net.URI;
+
/**
* Defines the Java APIs for XML Processing (JAXP).
*
@@ -197,6 +199,14 @@
*
*
*
+ * If more than one property affects an aspect of operation, all properties must
+ * permit the operation in order for it to proceed. For example, both the
+ * Resource Access property
+ * and External Access Properties (EAPs) must
+ * be set to allow in order for a direct fetch of an external resource to be
+ * carried out. For more details, refer to the
+ * External Resource Resolution Process.
+ *
* Using the {@link javax.xml.catalog.CatalogFeatures CatalogFeatures}' RESOLVE
* property as an example, the following illustrates how these rules are applied:
*
* The catalog is loaded once when the first JAXP processor factory is created.
*
- *
External Resource Resolution Process with the built-in Catalog
- * The JDK creates a {@link javax.xml.catalog.CatalogResolver CatalogResolver}
- * with the built-in catalog when needed. This CatalogResolver is used as the
- * default external resource resolver.
+ *
External Resource Resolution Process
+ *
+ * The XML processor resolves external resources using the following steps:
+ *
+ *
User-defined resolver, such as {@link org.xml.sax.EntityResolver EntityResolver},
+ * {@link javax.xml.stream.XMLResolver XMLResolver}, if registered on the XML factory
+ *
{@link javax.xml.catalog.CatalogResolver CatalogResolver} if registered or
+ * if a catalog file is provided
+ *
The JDK Built-in Catalog
+ *
Direct fetch
+ *
+ *
*
- * XML processors may use resolvers (such as {@link org.xml.sax.EntityResolver EntityResolver},
- * {@link javax.xml.stream.XMLResolver XMLResolver}, and {@link javax.xml.catalog.CatalogResolver CatalogResolver})
- * to handle external references. In the absence of the user-defined resolvers,
- * the JDK XML processors fall back to the default CatalogResolver to attempt to
- * find a resolution before making a connection to fetch the resources. The fall-back
- * also takes place if a user-defined resolver exists but allows the process to
- * continue when unable to resolve the resource.
+ * If a resolver or catalog successfully resolves the resource, the process ends.
+ * Otherwise, the XML processor evaluates the signal returned to decide whether
+ * to continue, ignore, or reject the resource.
+ *
+ * It continues to the next step if:
+ *
+ *
User-defined resolver returns {@code null}
+ *
{@link javax.xml.catalog.CatalogResolver CatalogResolver} returns {@code null}
+ * and the {@link javax.xml.catalog.CatalogFeatures.Feature#RESOLVE RESOLVE} feature
+ * is set to {@code continue}
+ *
+ *
The JDK Built-in Catalog returns {@code null} and its Resolve property
+ * {@code jdk.xml.jdkcatalog.resolve} is set to {@code continue}
- * If the default CatalogResolver is unable to locate a resource, it may signal
- * the XML processors to continue processing, or skip the resource, or
- * throw a CatalogException. The behavior is configured with the
- * {@code jdk.xml.jdkcatalog.resolve} property.
+ * It ignores the resource and returns an empty source if:
+ *
+ *
User-defined resolver returns an empty source
+ *
{@link javax.xml.catalog.CatalogResolver CatalogResolver} returns an empty source
+ * and the {@link javax.xml.catalog.CatalogFeatures.Feature#RESOLVE RESOLVE} feature
+ * is set to {@code ignore}
+ *
+ *
+ *
+ * It terminates and throws an exception if:
+ *
+ *
User-defined resolver throws an exception
+ *
{@link javax.xml.catalog.CatalogResolver CatalogResolver} returns {@code null},
+ * the {@link javax.xml.catalog.CatalogFeatures.Feature#RESOLVE RESOLVE} feature
+ * is {@code strict}
+ *
* In addition to the standard JAXP Properties,
@@ -871,7 +915,7 @@
*
Determines whether extension functions in the Transform API are to be allowed.
* The extension functions in the XPath API are not affected by this property.
*
- *
yes
+ *
yes
*
Boolean
*
* true or false. True indicates that extension functions are allowed; False otherwise.
@@ -994,6 +1038,109 @@
*
Defines allowed access to external resources by specifying a list
+ * of URI patterns, each following the syntax:
+ * {@code scheme:[/][host][:port]/[path]}
+ * Except where this specification explicitly extends or overrides the syntax or
+ * semantics defined by the {@link java.net.URI URI} class, such as the support for wildcard
+ * patterns, the definitions of {@link java.net.URI URI} apply.
+ * Where:
+ *
+ *
Component Syntax: A resource access entry is either:
+ *
+ *
+ * An exact-match URI, where the scheme, host, port, and path components
+ * must conform to the syntax requirements of the {@link java.net.URI URI}
+ * class and the URI is interpreted as a hierarchical URI.
+ *
+ *
+ * A wildcard URI pattern, where the URI syntax is extended to allow
+ * the wildcard {@code *} in the components explicitly defined by this specification.
+ * The wildcard matching rules for each supported component are described below.
+ *
+ *
+ * For both forms, the scheme and host are case-insensitive, while the path is case-sensitive.
+ *
+ *
scheme: The URI scheme. Unless the entire pattern is the single wildcard {@code *},
+ * the scheme must be one of the supported schemes (http, https, ftp, file, or jrt).
+ *
+ *
jar: jar URIs are matched against the URI of the underlying JAR file
+ * using the corresponding rule pattern. For example, the rule pattern
+ * {@code file:/tmp/foo.jar} permits access to {@code jar:file:/tmp/foo.jar!/dtds/test.dtd}.
+ *
+ * Permission to access the JAR file automatically grants access to all entries within
+ * that JAR; entry-level restrictions are not supported.
+ *
+ *
/ (slash): The slash following the scheme may appear one to three times.
+ * Two slashes (//) indicate the start of an authority (for example, http://example.com).
+ * One or three slashes (/ or ///) indicate the start of a local resource path
+ * (for example, {@code file:/foo/bar.dtd, file:///foo/bar.dtd}).
+ *
+ *
host: Optional. A domain name, IPv4 address, IPv6 literal, or supported
+ * wildcard pattern. The wildcard {@code *} denotes any host. A leading wildcard followed
+ * by a domain, such as {@code*.example.com}, matches all subdomains of {@code example.com}.
+ * For network schemes, the host component must not be empty.
+ *
IPv6 Literals: IPv6 literals must be enclosed in square brackets,
+ * as defined by {@link java.net.URI URI}, for example {@code https://[2001:db8::6]}
+ *
port: Optional. A decimal port number, as per the URI standard,
+ * to indicate only the specified port is permitted. If specified,
+ * it can not be empty. {@code http://example.com:}, for example, is illegal.
+ *
path: Optional. Specifies a resource path. Wildcard {@code *}
+ * may be used in the path to match any sequence (e.g., {@code /foo/*} matches
+ * all resources under {@code /foo/}). For local schemes, paths are typically
+ * absolute (e.g., {@code file:/dtds/*}). To match all resources under a directory,
+ * the wildcard {@code *} must be added. Without it, the path is treated as
+ * a literal file or directory.
+ *
entire pattern: can be a wildcard {@code *} or empty "", which
+ * represents all access or no access permitted respectively.
+ *
wildcard: The wildcard {@code *} may be used only in the forms
+ * explicitly defined by this specification:
+ *
+ *
as the entire pattern ({@code *});
+ *
as the entire host component ({@code http://*});
+ *
as a leading wildcard in the host component ({@code http://*.example.com});
+ *
as the final path segment ({@code file:/foo/*}).
+ *
+ * Any other occurrence of {@code *} is treated as a literal character and does not perform wildcard matching.
+ *
@@ -1037,6 +1184,11 @@
* These three properties control whether DTDs as a whole shall be processed. When
* they are set to deny or ignore, other properties that regulate a part or an
* aspect of DTD shall have no effect.
+ *
+ * [8] In the current release, the state of the {@code jdk.xml.resource.access}
+ * property does not change when {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING FEATURE_SECURE_PROCESSING}
+ * (FSP) is enabled. In future releases, it will transition to a restrictive setting
+ * when FSP is enabled.
*
*
Legacy Property Names (deprecated)
* JDK releases prior to JDK 17 support the use of URI style prefix for properties.
diff --git a/src/java.xml/share/conf/jaxp.properties b/src/java.xml/share/conf/jaxp.properties
index 2b7136319ce..514793cd932 100644
--- a/src/java.xml/share/conf/jaxp.properties
+++ b/src/java.xml/share/conf/jaxp.properties
@@ -95,6 +95,81 @@ jdk.xml.overrideDefaultParser=false
# javax.xml.accessExternalStylesheet="all"
#
#
+# XML Resource Access Property:
+#
+# A comma-separated list of URI patterns, * (wildcard), or "" (empty string),
+# each following the syntax: scheme:[/][host][:port]/[path]
+#
+# Component Syntax: A resource access entry is either:
+# - An exact-match URI, where the scheme, host, port, and path components must conform
+# to the syntax requirements of the java.net.URI class.
+# - A wildcard URI pattern, where the URI syntax is extended to allow the wildcard *
+# in the components explicitly defined by this specification.
+#
+# For both forms, the scheme and host are case-insensitive, while the path is case-sensitive.
+#
+# scheme: The URI scheme. Unless the entire pattern is the single wildcard *,
+# the scheme must be one of the supported schemes (http, https, ftp, file, or jrt).
+#
+# jar: jar URIs are matched against the URI of the underlying JAR file using the
+# corresponding rule pattern. For example, the rule pattern file:/tmp/foo.jar permits
+# access to jar:file:/tmp/foo.jar!/dtds/test.dtd.
+#
+# Permission to access the JAR file automatically grants access to all entries within that JAR;
+# entry-level restrictions are not supported.
+
+# / (slash): The slash following the scheme may appear one to three times.
+# Two slashes (//) indicate the start of an authority (for example, http://example.com).
+# One or three slashes (/ or ///) indicate the start of a local resource path
+# (for example, file:/foo/bar.dtd or file:///foo/bar.dtd).
+
+# host: Optional. A domain name, IPv4 address, IPv6 literal, or supported wildcard pattern.
+# The wildcard * denotes any host. A leading wildcard followed by a domain,
+# such as *.example.com, matches all subdomains of example.com. For network schemes,
+# the host component must not be empty.
+#
+# IPv6 Literals: IPv6 literals must be enclosed in square brackets,
+# as defined by java.net.URI, for example https://[2001:db8::6].
+#
+# port: Optional. A decimal port number, as per the URI standard, to indicate only
+# the specified port is permitted. If specified, it can not be empty.
+# http://example.com:, for example, is illegal.
+#
+# path: Optional. Specifies a resource path. Wildcard * may be used in the path
+# to match any sequence (e.g., /foo/* matches all resources under /foo/).
+# For local schemes, paths are typically absolute (e.g., file:/dtds/*).
+# To match all resources under a directory, the wildcard * must be added.
+# Without it, the path is treated as a literal file or directory.
+#
+# entire pattern: can be a wildcard * or empty "", which represents all access
+# or no access permitted respectively.
+#
+# wildcard: The wildcard * may be used only in the forms explicitly defined by this specification:
+# - as the entire pattern (*);
+# - as the entire host component (http://*);
+# - as a leading wildcard in the host component (http://*.example.com);
+# - as the final path segment (file:/foo/*).
+#
+# Any other occurrence of * is treated as a literal character and does not perform wildcard matching.
+#
+#
+# Example:
+# jdk.xml.resource.access = https://*.sun.com, http://www.w3.org, https://127.0.0.1, file:/dtds/, jrt:*, file:/tmp/foo.jar
+#Examples:
+#
+# jdk.xml.resource.access = https://*.example.com, http://www.example.com, https://127.0.0.1, \
+# https://127.0.0.1:80, https://[fe80::1%lo0], https://[fe80::1%lo0]:80, file:/dtds/*, jrt:/*, file:/tmp/foo.jar
+#
+# This configuration permits access to:
+# - https access to any subdomain of example.com, e.g. foo.example.com
+# - Resources from the specific domain as listed in the example, example.com, 127.0.0.1 and [fe80::1%lo0]
+# - All local resources under the dtds directory
+# - Resources from the Java runtime image
+# - The local /tmp/foo.jar file and its contents
+#
+# The default setting allows unrestricted access
+jdk.xml.resource.access=*
+#
# Catalog Properties:
#
# The Catalog API defines four features: FILES, PREFER, DEFER and RESOLVE.
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java
new file mode 100644
index 00000000000..999b7f3f67c
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common.access;
+
+import jdk.xml.internal.AccessRule;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.net.URI;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+
+/*
+ * @test
+ * @bug 8357394
+ * @summary Verifies access rules defined by property jdk.xml.resource.access
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest /test/lib
+ * @modules java.xml/jdk.xml.internal
+ * @run junit/othervm common.access.AccessRuleTest
+ */
+public class AccessRuleTest {
+ /**
+ * Returns test data for testAccessRule.
+ * Data: rules, URI strings, result (true if allowed, false otherwise)
+ * @return test data for testAccessRule
+ */
+ private static Stream testData() {
+
+ return Stream.of(
+ Arguments.of("*", "http://all.access", true),
+ Arguments.of("", "http://no.access", false),
+ Arguments.of("http://*", "http://all.http.access", true),
+ Arguments.of("http://*.oracle.com", "http://subdomains.oracle.com/dtds/example.dtd", true),
+ Arguments.of("https://*", "https://all.https.access", true),
+ Arguments.of("https://*.oracle.com", "https://subdomains.oracle.com/dtds/example.dtd", true),
+ // If port is omitted, matches all ports.
+ Arguments.of("http://www.oracle.com",
+ "http://www.oracle.com/dtds/example.dtd; http://www.oracle.com:80/dtds/example.dtd; http://www.oracle.com:8080/dtds/example.dtd", true),
+ // An explicitly specified default port also matches an omitted port.
+ Arguments.of("http://www.oracle.com:80",
+ "http://www.oracle.com/dtds/example.dtd; http://www.oracle.com:80/dtds/example.dtd", true),
+ // An explicitly specified default port does not match a non-default port.
+ Arguments.of("http://www.oracle.com:80", "http://www.oracle.com:8080/dtds/example.dtd", false),
+ // If port is specified, matches only the specified port.
+ Arguments.of("http://www.oracle.com:8080",
+ "http://www.oracle.com/dtds/example.dtd; http://www.oracle.com:80/dtds/example.dtd", false),
+ Arguments.of("http://www.oracle.com:8080", "http://www.oracle.com:8080/dtds/example.dtd", true),
+
+ Arguments.of("http://www.oracle.com, http://*.oracle.com",
+ "http://www.oracle.com/dtds/example.dtd; http://subdomains.oracle.com/dtds/example.dtd", true),
+ Arguments.of("file:/dtds/dtd1.dtd", "file:/dtds/dtd1.dtd", true),
+ Arguments.of("file:/dtds/dtd1.dtd, file:/xsds/*", "file:/dtds/dtd1.dtd; file:/xsds/example.xsd", true),
+ // To match all resources under a directory, the wildcard * must be added
+ Arguments.of("file:/dir/*", "file:/dir/child.dtd; file:/dir/sub/example.dtd", true),
+ // Without the wildcard *, a directory path does not match resources under the directory.
+ Arguments.of("file:/dir/", "file:/dir/child.dtd; file:/dir/sub/example.dtd", false),
+
+ Arguments.of("http://www.oracle.com, file:/dtds/dtd1.dtd, file:/xsds/*",
+ "http://www.oracle.com/dtds/example.dtd; file:/dtds/dtd1.dtd; file:/xsds/example.xsd", true),
+ Arguments.of("http://[2001:db8::1]", "http://[2001:0db8:0000:0000:0000:0000:0000:0001]/dtds/example.dtd; "
+ + "http://[2001:db8:0:0:0:0:0:1]/dtds/example.dtd", true),
+ Arguments.of("http://[2001:0db8:0000:0000:0000:0000:0000:0001]", "http://[2001:db8::1]/dtds/example.dtd", true),
+ Arguments.of("jrt:/*; jrt:/java.xml/*", "jrt:/java.xml/jdk/xml/internal/jdkcatalog/JDKCatalog.xml", true),
+ Arguments.of("file:/tmp/foo.jar",
+ "jar:file:/tmp/foo.jar!/dtds/example.dtd; jar:file:/tmp/foo.jar!/xsds/example.xsd", true),
+ Arguments.of("file:/tmp/foo.jar", "jar:file:/tmp/bar.jar!/dtds/example.dtd", false),
+
+ // URI normalization: each "." segment is simply removed
+ Arguments.of("file:/dir/*", "file:/dir/./foo.dtd; file:/dir/sub/./foo.dtd; file:/dir/./sub/foo.dtd", true),
+ // A ".." segment is removed only if it is preceded by a non-".." segment
+ Arguments.of("file:/dir/*", "file:/dir/../dir/foo.dtd; file:/dir/sub/../foo.dtd", true),
+ Arguments.of("file:/dir/*", "file:/../dir/foo.dtd; file:/../../dir/foo.dtd; file:/dir/../foo.dtd;" +
+ " file:/dir/sub/../../foo.dtd; file:/dir/a/b/../../../foo.dtd", false),
+
+ // both "." and ".." segments
+ Arguments.of("file:/dir/*", "file:/dir/sub/../foo.dtd; file:/dir/./sub/../foo.dtd", true),
+ Arguments.of("file:/dir/*", "file:/dir/./sub/../foo.dtd; file:/dir/sub/./../sub/../foo.dtd", true),
+ Arguments.of("file:/dir/*", "file:/dir/./../sub/../foo.dtd; file:/dir/sub/./../../foo.dtd", false),
+
+ // encoded dot segments
+ Arguments.of("file:/dir/*", "file:/dir/%2e/sub/../foo.dtd", true),
+ Arguments.of("file:/dir/*", "file:/dir/%2e%2e/foo.dtd; file:/dir/%2E%2E/foo.dtd", false),
+ Arguments.of("file:/dir/*", "file:/dir/.%2e/foo.dtd; file:/dir/%2e./foo.dtd", false),
+ Arguments.of("file:/dir/*", "file:/%2e%2e%2fdir%2ffoo.dtd; file:/dir/%2e%2e%2ffoo.dtd; file:/dir%2f%2e%2e%2ffoo.dtd; file:/dir%2f..%2f..%2ffoo.dtd", false),
+
+ // rule allows all file access
+ Arguments.of("file:/*; file:///*", "file:/dir/../../foo.dtd; file:/../foo.dtd; file:/dir/sub/../foo.dtd", true),
+ Arguments.of("file:/*; file:///*", "file:/all.file.access; file:///all.file.access", true),
+ Arguments.of("file://*", "file://all.file.access", true),
+
+ // file scheme with server authority, including Windows UNC path
+ Arguments.of("file://server/*", "file://server/foo.dtd; file://server/dir/foo.dtd", true),
+ Arguments.of("file://server/share/*", "file://server/share/foo.dtd; file://SERVER/share/foo.dtd", true),
+ Arguments.of("file://server/share/foo.dtd", "file://server/share/foo.dtd", true),
+ Arguments.of("file://server/*", "file://server1/foo.dtd; file:/foo.dtd", false),
+ Arguments.of("file://server/share/*", "file://server1/share/foo.dtd; file://server/SHARE/foo.dtd", false),
+ Arguments.of("file:/share/*", "file://server/share/foo.dtd", false),
+ Arguments.of("file:/*", "file://server/foo.dtd", false),
+ Arguments.of("file://[2001:db8::1]", "file://[2001:0db8::1]/dtds/example.dtd; file://[2001:db8:0:0:0:0:0:1]/dtds/example.dtd", true)
+ );
+ }
+
+ /**
+ * Returns test data for testInvalidRules.
+ * Data: rules, exception class
+ * @return test data for testInvalidRules
+ */
+ private static Stream testInvalidInput() {
+
+ return Stream.of(
+ Arguments.of("scheme", IllegalArgumentException.class),
+ Arguments.of("http; http:; http:*; http:/; http:/*; http://; http://:", IllegalArgumentException.class),
+ Arguments.of("file; file:; file:*, file:/; file://; file://:", IllegalArgumentException.class),
+ Arguments.of("jrt; jrt:; jrt:*, jrt:/", IllegalArgumentException.class),
+ Arguments.of("http://:8080; http://example.com:", IllegalArgumentException.class),
+ Arguments.of("file://:8080; file://server:8080/", IllegalArgumentException.class),
+ Arguments.of("http:///dtds", IllegalArgumentException.class),
+ Arguments.of("http://example.com, , file:*", IllegalArgumentException.class),
+ Arguments.of("http://example.com, *, file:*", IllegalArgumentException.class),
+ Arguments.of("jar:file:/tmp/foo.jar!/dtds/*", IllegalArgumentException.class),
+ Arguments.of("file:/dir/./foo.dtd; file:/dir/../foo.dtd; file:/dir/%2e/foo.dtd; " +
+ "file:/dir/%2e%2e/foo.dtd; file:/dir/.%2e/foo.dtd; file:/dir/%2e./foo.dtd", IllegalArgumentException.class),
+ Arguments.of("file://server/share/../foo.dtd", IllegalArgumentException.class)
+ );
+ }
+
+ /**
+ * Verifies access rules set by the Resource Access property.
+ * @param rules the access rules separate by ";"
+ * @param systemIds system IDs represented as semicolon-separated URI strings
+ * @param permitted the flag indicating whether the rules permit the resource
+ * represented by the systemId
+ * @throws Exception if the test fails due to test configuration issues other
+ * than the expected result
+ */
+ @ParameterizedTest
+ @MethodSource("testData")
+ public void testAccessRule(String rules, String systemIds, boolean permitted)
+ throws Exception {
+ String[] accessRules = rules.split(";");
+ for (String rule : accessRules) {
+ AccessRule accessRule = new AccessRule(rule.trim());
+ String[] ids = systemIds.split(";");
+ for (String systemId : ids) {
+ assertEquals(accessRule.allows(URI.create(systemId.trim())), permitted);
+ }
+ }
+ }
+
+ /**
+ * Verifies that the specified rule is invalid.
+ * @param rule indicates whether there is a custom resolver
+ * @param expectedType the expected throw type
+ * @throws Exception if the test fails other than the expected Exception, which
+ * would indicate an issue in configuring the test
+ */
+ @ParameterizedTest
+ @MethodSource("testInvalidInput")
+ public void testAccessRule(String rule, Class expectedType) throws Exception {
+ assertThrows(expectedType, () -> parseRules(rule));
+ }
+
+ /**
+ * Attempts to parse one or a semi-colon separated list of access rules.
+ * @param rule the access rule(s)
+
+ * @throws Exception if error occurs while attempting to create an AccessRule.
+ */
+ private void parseRules(String rule) {
+ String[] rules = rule.split(";");
+ for (String rule1 : rules) {
+ System.out.println("Test invalid rule: [" + rule1 + "]");
+ AccessRule accessRule = new AccessRule(rule1.trim());
+ }
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessTestBase.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessTestBase.java
new file mode 100644
index 00000000000..7b6c0423209
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessTestBase.java
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common.access;
+
+import common.util.TestBase;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.validation.SchemaFactory;
+
+/**
+ * Test base for Access Rule test.
+ */
+public class AccessTestBase extends TestBase {
+ /*
+ * Test scenarios for verifying preferences.
+ *
+ * Fields:
+ * file, FSP, state of setting, config file, system property, api property,
+ * Custom Catalog, error expected, error code or expected result
+ */
+ public Object[][] getConfigs(Processor processor) {
+ // file with an external DTD that's not in JdkCatalog
+ String fileDTDNotInC = "properties1.xml";
+ // file with an external DTD that's in the Custom Catalog
+ String fileDTDInCC = "test.xml";
+ // file with an external DTD that's in JdkCatalog
+ String javaDTD = "properties.xml";
+
+ // error code when CATALOG=strict; The cause for DOM
+ String errCode = "JAXP09040001";
+
+ // error (not from catalog) is expect when CATALOG=continue
+ boolean isErrExpected = true;
+ String expected1 = UNKNOWN_HOST;
+
+ // expected when reference is resolved by Catalog
+ String expected2 = "";
+ switch (processor) {
+ case SAX:
+ errCode = "JAXP00090001";
+ break;
+ case STAX:
+ errCode = "JAXP00090001";
+ // StAX is non-validating parser
+ isErrExpected = false;
+ expected1 = ".*[\\w\\s]*(value1)[\\w\\s]*.*";
+ expected2 = ".*(123)[\\w\\s]*.*";
+ break;
+ default:
+ break;
+ }
+
+ return new Object[][]{
+ /**
+ * Case 1: all properties must permit
+ * Note: External reference not in the built-in catalog
+ * Expect: error as the parser continues and tries to access an invalid site
+ * java.net.UnknownHostException: invalid.site.com
+ */
+ /**
+ * Case 1-1: by default, both RESOURCE_ACCESS and EAP allow access
+ */
+ {fileDTDNotInC, null, null, null, null, null, null, isErrExpected, expected1},
+ /**
+ * Case 1-2: FSP is set, both RESOURCE_ACCESS and EAP are set to allow
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, null, new Properties[]{Properties.ACCESS0, Properties.AED0}, null, isErrExpected, expected1},
+ /**
+ * Case 2: access is denied unless all properties permit the operation
+ *
+ * Sample Error Message: [Fatal Error] properties1.xml:7:11: External DTD: Failed to read external DTD 'properties1.dtd',
+ * because access is not allowed due to restriction set by 'Resource Access (jdk.xml.resource.access) and http://javax.xml.XMLConstants/property/accessExternalDTD'.
+ *
+ */
+ /**
+ * Case 2-1: FSP is set. RESOURCE_ACCESS is unchanged, and EAP denies access
+
+ * Expect: [Fatal Error] access denied by ACCESS_EXTERNAL_DTD
+ */
+ {fileDTDNotInC, Properties.FSP, null, null, null, null, null, true, XMLConstants.ACCESS_EXTERNAL_DTD},
+ /**
+ * Case 2-2: RESOURCE_ACCESS is set to deny access though EAP allows it
+
+ * Expect: [Fatal Error] access denied by RESOURCE_ACCESS
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.API, null, null, new Properties[]{Properties.ACCESS1, Properties.AED0}, null, true, SP_ACCESS},
+ /**
+ * Case 2-3: ACCESS_EXTERNAL_DTD is set to deny access though RESOURCE_ACCESS allows it
+
+ * Expect: [Fatal Error] access denied by ACCESS_EXTERNAL_DTD
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.API, null, null, new Properties[]{Properties.ACCESS0, Properties.AED2}, null, true, XMLConstants.ACCESS_EXTERNAL_DTD},
+ /**
+ * Case 2-4: System properties override FSP secure values.
+ *
+ * Expect: error as the parser continues and tries to access an invalid site
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.SYSTEM, null, new Properties[]{Properties.ACCESS0, Properties.AED0}, null, null, isErrExpected, expected1},
+ /**
+ * Case 2-5: API property setting overrides system property setting.
+ *
+ * Expect: error as the parser continues and tries to access an invalid site
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, new Properties[]{Properties.ACCESS1, Properties.AED0}, new Properties[]{Properties.ACCESS0, Properties.AED0}, null, isErrExpected, expected1},
+ /**
+ * Case 2-6: API property setting overrides system property setting.
+ *
+ * Expect: [Fatal Error] access denied by RESOURCE_ACCESS
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, new Properties[]{Properties.ACCESS0, Properties.AED0}, new Properties[]{Properties.ACCESS1, Properties.AED0}, null, true, SP_ACCESS},
+
+ /**
+ * Case 3: Resolvers and Catalogs take precedence in the resource resolution process
+ *
+ * Sample Error Message when access is denied by Catalog's Resolve property:
+ * [Fatal Error] properties1.xml:7:11: JAXP00090001: The CatalogResolver is enabled with the catalog "JDKCatalog.xml", but a CatalogException is returned.
+ * org.xml.sax.SAXException: javax.xml.catalog.CatalogException: JAXP09040001: No match found for publicId 'null' and systemId 'http://invalid.site.com/dtd/properties1.dtd'.
+ *
+ */
+ /**
+ * Case 3-1: the built-in catalog's Resolve property is set to "strict", both Resource Access (jdk.xml.resource.access) and External Access Properties (EAPs) have no effect,
+ * regardless of their configured values
+ *
+ * Expect: error as access is denied by the Catalog's Resolve property
+ */
+ {fileDTDNotInC, null, PropertyState.CONFIG_FILE_SYSTEM_API, Properties.CONFIG_FILE_CATALOG_STRICT, null, new Properties[]{Properties.ACCESS0, Properties.AED0}, null, true, errCode},
+ /**
+ * Case 3-2: the reference is resolved by the built-in catalog before direct fetch.
+ * FSP sets EAP to deny direct fetch, but catalog resolution completes first.
+ *
+ * Expect: no error
+ */
+ {javaDTD, Properties.FSP, PropertyState.CONFIG_FILE, Properties.CONFIG_FILE_CATALOG_STRICT, null, null, null, false, expected1},
+ /**
+ * Case 3-3: the reference is resolved by a custom catalog before direct fetch.
+ * FSP sets EAP to deny direct fetch, but catalog resolution completes first.
+ *
+ * Expect: no error
+ */
+ {fileDTDInCC, Properties.FSP, PropertyState.CONFIG_FILE, Properties.CONFIG_FILE_CATALOG_STRICT, null, null, CustomCatalog.STRICT, false, expected2}
+ };
+ }
+
+ /*
+ * Test scenarios for XInclude. XInclude direct fetches are controlled by
+ * RESOURCE_ACCESS, while resolver/catalog results take precedence.
+ */
+ public Object[][] getXIncludeConfigs(Processor processor) {
+ String xinclude = "XI_roottest.xml";
+
+ return new Object[][]{
+ /**
+ * Case 1-1: by default, RESOURCE_ACCESS allows direct XInclude access.
+ */
+ {xinclude, null, null, null, null, null, null, false, ""},
+ /**
+ * Case 1-2: FSP is set, RESOURCE_ACCESS is explicitly set to allow.
+ */
+ {xinclude, Properties.FSP, PropertyState.API, null, null,
+ new Properties[]{Properties.ACCESS0}, null, false, ""},
+ /**
+ * Case 2-1: RESOURCE_ACCESS is set to deny direct XInclude access.
+ *
+ * Expect: access denied by RESOURCE_ACCESS
+ */
+ {xinclude, Properties.FSP, PropertyState.API, null, null,
+ new Properties[]{Properties.ACCESS1}, null, true, SP_ACCESS},
+ /**
+ * Case 2-2: system properties override FSP.
+ */
+ {xinclude, Properties.FSP, PropertyState.SYSTEM, null,
+ new Properties[]{Properties.ACCESS0}, null, null, false, ""},
+ /**
+ * Case 2-3: API property setting overrides system property setting.
+ */
+ {xinclude, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null,
+ new Properties[]{Properties.ACCESS1},
+ new Properties[]{Properties.ACCESS0}, null, false, ""},
+ /**
+ * Case 2-4: API property setting overrides system property setting.
+ *
+ * Expect: access denied by RESOURCE_ACCESS
+ */
+ {xinclude, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null,
+ new Properties[]{Properties.ACCESS0},
+ new Properties[]{Properties.ACCESS1}, null, true, SP_ACCESS},
+ /**
+ * Case 3-1: custom catalog resolves the reference before direct fetch.
+ * FSP sets EAP to deny direct fetch, but catalog resolution completes first.
+ *
+ * Expect: no error
+ */
+ {xinclude, Properties.FSP, PropertyState.CONFIG_FILE,
+ Properties.CONFIG_FILE_CATALOG_STRICT, null, null,
+ CustomCatalog.STRICT, false, ""},
+ };
+ }
+
+ /*
+ * Test scenarios for configuring properties for validation or transform.
+ *
+ * Fields:
+ * xml file, xsd or xsl file, FSP, state of setting, config file, system property,
+ * api property, Custom Catalog, error expected, error code or expected result
+ */
+ public Object[][] getConfig(String m) {
+ // Schema Import
+ String xmlFile = "XSDImport_company.xsd";
+ String xsdOrXsl = null;
+ String expected = "";
+ String errCode = "JAXP00090001";
+ Properties eapAllow = Properties.AES0;
+ Properties eapDeny = Properties.AES2;
+ String eapName = "accessExternalDTD,accessExternalSchema";
+
+ switch (m) {
+ case "SchemaTest2":
+ // Schema Include
+ xmlFile = "XSDInclude_company.xsd";
+ break;
+ case "Validation":
+ // Schema Location
+ xmlFile = "val_test.xml";
+ break;
+ case "Stylesheet":
+ errCode = "JAXP09040001";
+ xmlFile = "XSLDTD.xsl";
+ eapAllow = Properties.AED0;
+ eapDeny = Properties.AED2;
+ eapName = XMLConstants.ACCESS_EXTERNAL_DTD;
+ break;
+ case "Transform":
+ xmlFile = "XSLPI.xml";
+ errCode = "JAXP00090001";
+ xsdOrXsl = ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + " ";
+ eapAllow = Properties.AEX0;
+ eapDeny = Properties.AEX2;
+ eapName = XMLConstants.ACCESS_EXTERNAL_STYLESHEET;
+ break;
+ default:
+ break;
+ }
+
+ return new Object[][]{
+ /**
+ * Case 1: all properties must permit.
+ *
+ * Case 1-1: by default, both RESOURCE_ACCESS and EAP allow access.
+ */
+ {xmlFile, xsdOrXsl, null, null, null, null, null, null, false, expected},
+ /**
+ * Case 1-2: FSP is set, both RESOURCE_ACCESS and EAP are set to allow.
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, null, false, expected},
+ /**
+ * Case 2: access is denied unless all properties permit the operation.
+ *
+ * Case 2-1: FSP is set. RESOURCE_ACCESS is unchanged, and EAP denies access.
+ *
+ * Expect: access denied by EAP
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE, null, null, null, null, true, eapName},
+ /**
+ * Case 2-2: RESOURCE_ACCESS is set to deny access though EAP allows it.
+ *
+ * Expect: access denied by RESOURCE_ACCESS
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.API, null, null, new Properties[]{Properties.ACCESS1, Properties.AED0, eapAllow}, null, true, SP_ACCESS},
+ /**
+ * Case 2-3: EAP is set to deny access though RESOURCE_ACCESS allows it.
+ *
+ * Expect: access denied by EAP
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.API, null, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapDeny}, null, true, eapName},
+ /**
+ * Case 2-4: system properties override FSP secure values.
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.SYSTEM, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, null, null, false, expected},
+ /**
+ * Case 2-5: API property setting overrides system property setting.
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, new Properties[]{Properties.ACCESS1, Properties.AED0, eapAllow}, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, null, false, expected},
+ /**
+ * Case 2-6: API property setting overrides system property setting.
+ *
+ * Expect: access denied by RESOURCE_ACCESS
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, new Properties[]{Properties.ACCESS1, Properties.AED0, eapAllow}, null, true, SP_ACCESS},
+ /**
+ * Case 3: Catalogs take precedence in the resource resolution process.
+ *
+ * Case 3-1: the built-in catalog's Resolve property is set to "strict",
+ * and the reference is not in the built-in catalog.
+ *
+ * Expect: error as access is denied by the Catalog's Resolve property
+ */
+ {xmlFile, xsdOrXsl, null, PropertyState.CONFIG_FILE_SYSTEM_API, Properties.CONFIG_FILE_CATALOG_STRICT, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, null, true, errCode},
+ /**
+ * Case 3-2: custom catalog resolves the reference before direct fetch.
+ * FSP sets EAP to deny direct fetch, but catalog resolution completes first.
+ *
+ * Expect: no error
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE, Properties.CONFIG_FILE_CATALOG_STRICT, null, null, CustomCatalog.STRICT, false, expected},
+ };
+ }
+
+ public void testDOM(String filename, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ DocumentBuilderFactory dbf = getDBF(fsp, state, config, sysProp, apiProp, cc);
+ process(filename, dbf, expectError, error);
+ }
+
+ public void testSAX(String filename, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ SAXParser parser = getSAXParser(fsp, state, config, sysProp, apiProp, cc);
+ process(filename, parser, expectError, error);
+ }
+
+ public void testStAX(String filename, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ XMLInputFactory xif = getXMLInputFactory(state, config, sysProp, apiProp, cc);
+ process(filename, xif, expectError, error);
+ }
+
+ public void testSchema1(String filename, String xsd, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ SchemaFactory sf = getSchemaFactory(fsp, state, config, sysProp, apiProp, cc);
+ process(filename, sf, expectError, error);
+ }
+
+ public void testSchema2(String filename, String xsd, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+ testSchema1(filename, xsd, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ }
+
+ public void testValidation(String filename, String xsd, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ SchemaFactory sf = getSchemaFactory(fsp, state, config, sysProp, apiProp, cc);
+ validate(filename, sf, expectError, error);
+ }
+
+ public void testStylesheet(String filename, String xsl, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ TransformerFactory tf = getTransformerFactory(fsp, state, config, sysProp, apiProp, cc);
+ process(filename, tf, expectError, error);
+ }
+
+ public void testTransform(String filename, String xsl, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ TransformerFactory tf = getTransformerFactory(fsp, state, config, sysProp, apiProp, cc);
+ transform(filename, xsl, tf, expectError, error);
+ }
+
+ // parameters in the same order as the test method
+ String filename; String xsd; String xsl; Properties fsp; PropertyState state;
+ Properties config; Properties[] sysProp; Properties[] apiProp; CustomCatalog cc;
+ boolean expectError; String error;
+
+ // Maps the scenario array to individual parameters
+ public void paramMap(Processor processor, String method, String index) {
+ int i = 0;
+ Object[][] params;
+ if (processor == Processor.VALIDATOR ||
+ processor == Processor.TRANSFORMER) {
+ params = getConfig(method);
+ i = 1;
+ } else {
+ params = getConfigs(processor);
+ }
+ Object[] param = params[Integer.parseInt(index)];
+ filename = (String)param[0];
+ if (processor == Processor.VALIDATOR) {
+ xsd = (String)param[i];
+ } else if (processor == Processor.TRANSFORMER) {
+ xsl = (String)param[i];
+ }
+ fsp = (Properties)param[i + 1];
+ state = (PropertyState)param[i + 2];
+ config = (Properties)param[i + 3];
+ sysProp = (Properties[])param[i + 4];
+ apiProp = (Properties[])param[i + 5];
+ cc = (CustomCatalog)param[i + 6];
+ expectError = (boolean)param[i + 7];
+ error = (String)param[i + 8];
+ }
+
+ public void paramMapXInclude(Processor processor, String index) {
+ Object[] param = getXIncludeConfigs(processor)[Integer.parseInt(index)];
+ filename = (String)param[0];
+ fsp = (Properties)param[1];
+ state = (PropertyState)param[2];
+ config = (Properties)param[3];
+ sysProp = (Properties[])param[4];
+ apiProp = (Properties[])param[5];
+ cc = (CustomCatalog)param[6];
+ expectError = (boolean)param[7];
+ error = (String)param[8];
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/DOMTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/DOMTest.java
new file mode 100644
index 00000000000..e0223f93459
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/DOMTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common.access;
+
+import java.net.ProxySelector;
+
+/**
+ * @test @bug 8357394
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.DOMTest 0 // by default, both RESOURCE_ACCESS and EAP allow access
+ * @run driver common.access.DOMTest 1 // FSP is set, both RESOURCE_ACCESS and EAP are set to allow
+ * @run driver common.access.DOMTest 2 // FSP is set, RESOURCE_ACCESS is unchanged, EAP denies access
+ * @run driver common.access.DOMTest 3 // RESOURCE_ACCESS denies access though EAP allows it
+ * @run driver common.access.DOMTest 4 // ACCESS_EXTERNAL_DTD denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.DOMTest 5 // system properties override FSP secure values
+ * @run driver common.access.DOMTest 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.DOMTest 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.DOMTest 8 // the built-in catalog's Resolve property is strict
+ * @run driver common.access.DOMTest 9 // the built-in catalog resolves the reference before direct fetch
+ * @run driver common.access.DOMTest 10 // the custom catalog resolves the reference before direct fetch
+ * @summary Tests the interaction between Resource Access (jdk.xml.resource.access),
+ * External Access Properties (EAPs), and the built-in catalog's Resolve setting,
+ * ensuring correct precedence and behavior across different combinations of these
+ * configuration mechanisms
+ */
+public class DOMTest extends AccessTestBase {
+ public static void main(String[] args) throws Exception {
+ final ProxySelector previous = ProxySelector.getDefault();
+ // disable proxy
+ ProxySelector.setDefault(ProxySelector.of(null));
+ try {
+ new DOMTest().run(args[0]);
+ } finally {
+ // reset to the previous proxy selector
+ ProxySelector.setDefault(previous);
+ }
+ }
+
+ public void run(String index) throws Exception {
+ paramMap(Processor.DOM, null, index);
+ super.testDOM(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/SAXTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/SAXTest.java
new file mode 100644
index 00000000000..d17852b895b
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/SAXTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common.access;
+
+import common.util.TestBase;
+
+import java.net.ProxySelector;
+
+/**
+ * @test @bug 8357394
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.SAXTest 0 // by default, both RESOURCE_ACCESS and EAP allow access
+ * @run driver common.access.SAXTest 1 // FSP is set, both RESOURCE_ACCESS and EAP are set to allow
+ * @run driver common.access.SAXTest 2 // FSP is set, RESOURCE_ACCESS is unchanged, EAP denies access
+ * @run driver common.access.SAXTest 3 // RESOURCE_ACCESS denies access though EAP allows it
+ * @run driver common.access.SAXTest 4 // ACCESS_EXTERNAL_DTD denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.SAXTest 5 // system properties override FSP secure values
+ * @run driver common.access.SAXTest 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.SAXTest 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.SAXTest 8 // the built-in catalog's Resolve property is strict
+ * @run driver common.access.SAXTest 9 // the built-in catalog resolves the reference before direct fetch
+ * @run driver common.access.SAXTest 10 // the custom catalog resolves the reference before direct fetch
+ * @summary Tests the interaction between Resource Access (jdk.xml.resource.access),
+ * External Access Properties (EAPs), and the built-in catalog's Resolve setting,
+ * ensuring correct precedence and behavior across different combinations of these
+ * configuration mechanisms
+ */
+public class SAXTest extends AccessTestBase {
+ public static void main(String[] args) throws Exception {
+ final ProxySelector previous = ProxySelector.getDefault();
+ // disable proxy
+ ProxySelector.setDefault(ProxySelector.of(null));
+ try {
+ new SAXTest().run(args[0]);
+ } finally {
+ // reset to the previous proxy selector
+ ProxySelector.setDefault(previous);
+ }
+ }
+
+ public void run(String index) throws Exception {
+ paramMap(TestBase.Processor.SAX, null, index);
+ super.testSAX(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/SchemaTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/SchemaTest.java
new file mode 100644
index 00000000000..e984bc16639
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/SchemaTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common.access;
+
+import java.net.ProxySelector;
+
+/**
+ * @test @bug 8306632
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.SchemaTest SchemaTest1 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow access
+ * @run driver common.access.SchemaTest SchemaTest1 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow
+ * @run driver common.access.SchemaTest SchemaTest1 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_SCHEMA denies
+ * @run driver common.access.SchemaTest SchemaTest1 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_SCHEMA allows it
+ * @run driver common.access.SchemaTest SchemaTest1 4 // ACCESS_EXTERNAL_SCHEMA denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.SchemaTest SchemaTest1 5 // system properties override FSP secure values
+ * @run driver common.access.SchemaTest SchemaTest1 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.SchemaTest SchemaTest1 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.SchemaTest SchemaTest1 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.SchemaTest SchemaTest1 9 // custom catalog resolves before direct fetch
+ * @run driver common.access.SchemaTest SchemaTest2 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow access
+ * @run driver common.access.SchemaTest SchemaTest2 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow
+ * @run driver common.access.SchemaTest SchemaTest2 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_SCHEMA denies
+ * @run driver common.access.SchemaTest SchemaTest2 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_SCHEMA allows it
+ * @run driver common.access.SchemaTest SchemaTest2 4 // ACCESS_EXTERNAL_SCHEMA denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.SchemaTest SchemaTest2 5 // system properties override FSP secure values
+ * @run driver common.access.SchemaTest SchemaTest2 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.SchemaTest SchemaTest2 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.SchemaTest SchemaTest2 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.SchemaTest SchemaTest2 9 // custom catalog resolves before direct fetch
+ * @run driver common.access.SchemaTest Validation 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow access
+ * @run driver common.access.SchemaTest Validation 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow
+ * @run driver common.access.SchemaTest Validation 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_SCHEMA denies
+ * @run driver common.access.SchemaTest Validation 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_SCHEMA allows it
+ * @run driver common.access.SchemaTest Validation 4 // ACCESS_EXTERNAL_SCHEMA denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.SchemaTest Validation 5 // system properties override FSP secure values
+ * @run driver common.access.SchemaTest Validation 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.SchemaTest Validation 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.SchemaTest Validation 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.SchemaTest Validation 9 // custom catalog resolves before direct fetch
+ * @summary verifies Schema and Validation support for Resource Access, ACCESS_EXTERNAL_SCHEMA, and catalog precedence.
+ */
+public class SchemaTest extends AccessTestBase {
+
+ public static void main(String args[]) throws Exception {
+ new SchemaTest().run(args[0], args[1]);
+ }
+
+ public void run(String method, String index) throws Exception {
+ paramMap(Processor.VALIDATOR, method, index);
+ switch (method) {
+ case "SchemaTest1":
+ super.testSchema1(filename, xsd, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ case "SchemaTest2":
+ super.testSchema2(filename, xsd, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ case "Validation":
+ super.testValidation(filename, xsd, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ }
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/StAXTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/StAXTest.java
new file mode 100644
index 00000000000..65b73ee03ed
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/StAXTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common.access;
+
+
+import common.util.TestBase;
+
+import java.net.ProxySelector;
+
+/**
+ * @test @bug 8357394
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.StAXTest 0 // by default, both RESOURCE_ACCESS and EAP allow access
+ * @run driver common.access.StAXTest 3 // RESOURCE_ACCESS denies access though EAP allows it
+ * @run driver common.access.StAXTest 4 // ACCESS_EXTERNAL_DTD denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.StAXTest 5 // system properties override FSP secure values
+ * @run driver common.access.StAXTest 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.StAXTest 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.StAXTest 8 // the built-in catalog's Resolve property is strict
+ * @run driver common.access.StAXTest 9 // the built-in catalog resolves the reference before direct fetch
+ * @run driver common.access.StAXTest 10 // the custom catalog resolves the reference before direct fetch
+ * @summary Tests the interaction between Resource Access (jdk.xml.resource.access),
+ * External Access Properties (EAPs), and the built-in catalog's Resolve setting,
+ * ensuring correct precedence and behavior across different combinations of these
+ * configuration mechanisms
+ */
+public class StAXTest extends AccessTestBase {
+ public static void main(String[] args) throws Exception {
+ new StAXTest().run(args[0]);
+ }
+
+ public void run(String index) throws Exception {
+ paramMap(TestBase.Processor.STAX, null, index);
+ super.testStAX(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/TransformTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/TransformTest.java
new file mode 100644
index 00000000000..38a5ec18b72
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/TransformTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common.access;
+
+/**
+ * @test @bug 8306632
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.TransformTest Stylesheet 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_DTD allow access
+ * @run driver common.access.TransformTest Stylesheet 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_DTD allow
+ * @run driver common.access.TransformTest Stylesheet 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_DTD denies
+ * @run driver common.access.TransformTest Stylesheet 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_DTD allows it
+ * @run driver common.access.TransformTest Stylesheet 4 // ACCESS_EXTERNAL_DTD denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.TransformTest Stylesheet 5 // system properties override FSP secure values
+ * @run driver common.access.TransformTest Stylesheet 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.TransformTest Stylesheet 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.TransformTest Stylesheet 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.TransformTest Stylesheet 9 // custom catalog resolves before direct fetch
+ * @run driver common.access.TransformTest Transform 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_STYLESHEET allow access
+ * @run driver common.access.TransformTest Transform 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_STYLESHEET allow
+ * @run driver common.access.TransformTest Transform 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_STYLESHEET denies
+ * @run driver common.access.TransformTest Transform 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_STYLESHEET allows it
+ * @run driver common.access.TransformTest Transform 4 // ACCESS_EXTERNAL_STYLESHEET denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.TransformTest Transform 5 // system properties override FSP secure values
+ * @run driver common.access.TransformTest Transform 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.TransformTest Transform 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.TransformTest Transform 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.TransformTest Transform 9 // custom catalog resolves before direct fetch
+ * @summary verifies Transform support for Resource Access, external access properties, and catalog precedence.
+ */
+public class TransformTest extends AccessTestBase {
+
+ public static void main(String args[]) throws Exception {
+ new TransformTest().run(args[0], args[1]);
+ }
+
+ public void run(String method, String index) throws Exception {
+ paramMap(Processor.TRANSFORMER, method, index);
+ switch (method) {
+ case "Stylesheet":
+ super.testStylesheet(filename, xsl, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ case "Transform":
+ super.testTransform(filename, xsl, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ }
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/XIncludeTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/XIncludeTest.java
new file mode 100644
index 00000000000..47b5aa6e85a
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/XIncludeTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common.access;
+
+/**
+ * @test @bug 8306632
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.XIncludeTest DOM 0 // default RESOURCE_ACCESS allows direct XInclude access
+ * @run driver common.access.XIncludeTest DOM 1 // FSP with explicit RESOURCE_ACCESS allow
+ * @run driver common.access.XIncludeTest DOM 2 // RESOURCE_ACCESS denies direct XInclude access
+ * @run driver common.access.XIncludeTest DOM 3 // system properties override FSP
+ * @run driver common.access.XIncludeTest DOM 4 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.XIncludeTest DOM 5 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.XIncludeTest DOM 6 // custom catalog resolves before direct fetch
+ * @run driver common.access.XIncludeTest SAX 0 // default RESOURCE_ACCESS allows direct XInclude access
+ * @run driver common.access.XIncludeTest SAX 1 // FSP with explicit RESOURCE_ACCESS allow
+ * @run driver common.access.XIncludeTest SAX 2 // RESOURCE_ACCESS denies direct XInclude access
+ * @run driver common.access.XIncludeTest SAX 3 // system properties override FSP
+ * @run driver common.access.XIncludeTest SAX 4 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.XIncludeTest SAX 5 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.XIncludeTest SAX 6 // custom catalog resolves before direct fetch
+ * @summary verifies XInclude support for Resource Access and catalog precedence.
+ */
+public class XIncludeTest extends AccessTestBase {
+
+ public static void main(String args[]) throws Exception {
+ new XIncludeTest().run(args[0], args[1]);
+ }
+
+ public void run(String processor, String index) throws Exception {
+ Processor p = Processor.valueOf(processor);
+ paramMapXInclude(p, index);
+ switch (p) {
+ case DOM:
+ super.testDOM(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ case SAX:
+ super.testSAX(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported processor: " + processor);
+ }
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/testcatalog/TestCatalog.xml b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/testcatalog/TestCatalog.xml
index 216b3b81543..f1912ed877a 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/testcatalog/TestCatalog.xml
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/testcatalog/TestCatalog.xml
@@ -18,6 +18,9 @@
+
+
+
@@ -26,7 +29,7 @@
-
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDTestBase.java b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDTestBase.java
index b37b7da4e9a..81ac14ce9e9 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDTestBase.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDTestBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package common.dtd;
@@ -12,7 +12,7 @@
import common.util.TestBase;
/**
- * @bug 8306632
+ * @bug 8306632 8357394
* @summary tests the DTD property jdk.xml.dtd.support.
* The DTD property controls how DTDs are processed.
*/
@@ -126,7 +126,7 @@ public Object[][] getConfigs(Processor processor) {
* Expect: error as the parser processes DTD and tries to access the invalid site
* Error: JAXP00010008 java.net.UnknownHostException: invalid.site.com
*/
- {fileDTDNotInC, null, null, null, null, null, isErrExpected, expected},
+ {fileDTDNotInC, null, null, null, null, null, isErrExpected, expected1},
/**
* Case 1-2: DTD=deny in config file
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java b/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java
index 77672609147..b6c54115e9b 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,8 +28,8 @@
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
+import java.nio.file.Path;
import java.util.Objects;
-import java.util.regex.Pattern;
import javax.xml.XMLConstants;
import javax.xml.catalog.CatalogFeatures;
import javax.xml.parsers.DocumentBuilder;
@@ -44,6 +44,7 @@
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
@@ -53,8 +54,9 @@
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
-import org.w3c.dom.Document;
+
import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
@@ -90,8 +92,8 @@ public class TestBase {
private static final String CONFIG_FILE = "java.xml.config.file";
// CATALOG Abbreviation: C
- static final String C_FILE = CatalogFeatures.Feature.FILES.getPropertyName();
- static final String C_RESOLVE = CatalogFeatures.Feature.RESOLVE.getPropertyName();
+ public static final String C_FILE = CatalogFeatures.Feature.FILES.getPropertyName();
+ public static final String C_RESOLVE = CatalogFeatures.Feature.RESOLVE.getPropertyName();
// Xerces Property
public static final String DISALLOW_DTD = "http://apache.org/xml/features/disallow-doctype-decl";
@@ -106,15 +108,31 @@ public class TestBase {
public static final String SP_CATALOG = "jdk.xml.jdkcatalog.resolve";
public static final String OVERRIDE_PARSER = "jdk.xml.overrideDefaultParser";
+ //System Properties corresponding to ACCESS_EXTERNAL_* properties
+ public static final String SP_ACCESS_EXTERNAL_STYLESHEET = "javax.xml.accessExternalStylesheet";
+ public static final String SP_ACCESS_EXTERNAL_DTD = "javax.xml.accessExternalDTD";
+ public static final String SP_ACCESS_EXTERNAL_SCHEMA = "javax.xml.accessExternalSchema";
+ //Values for the ACCESS_EXTERNAL_* properties
+ public static final String ACCESS_EXTERNAL_ALL = "all";
+ public static final String ACCESS_EXTERNAL_NONE = "";
+
+ // JDK 27
+ public static final String SP_ACCESS = "jdk.xml.resource.access";
+
// DTD/CATALOG constants
public static final String RESOLVE_CONTINUE = "continue";
public static final String RESOLVE_IGNORE = "ignore";
public static final String RESOLVE_STRICT = "strict";
+ public static final String RESOLVE_STRICT_NONLOCAL = "strict:non-local";
public static final String DTD_ALLOW = "allow";
public static final String DTD_IGNORE = "ignore";
public static final String DTD_DENY = "deny";
+ // resource access constants
+ public static final String ACCESS_ALLOW = "*";
+ public static final String ACCESS_DENY = "";
+
// JAXP Configuration File(JCF) location
// DTD = deny
public static final String JCF_DTD2 = "dtd2.properties";
@@ -126,6 +144,8 @@ public class TestBase {
public static final String CONFIG_DEFAULT = "jaxp.properties";
public static final String CONFIG_STRICT = "jaxp-strict.properties";
public static final String CONFIG_TEMPLATE_STRICT = "jaxp-strict.properties.template";
+ public static final String CONFIG_COMPAT = "jaxp-compat.properties";
+ public static final String CONFIG_TEMPLATE_COMPAT = "jaxp-compat.properties.template";
public static final String UNKNOWN_HOST = "invalid.site.com";
@@ -150,6 +170,16 @@ public static enum Properties {
CATALOG0(SP_CATALOG, "ditto", Type.PROPERTY, RESOLVE_CONTINUE),
CATALOG1(SP_CATALOG, "ditto", Type.PROPERTY, RESOLVE_IGNORE),
CATALOG2(SP_CATALOG, "ditto", Type.PROPERTY, RESOLVE_STRICT),
+ CATALOG_NONLOCAL(SP_CATALOG, "ditto", Type.PROPERTY, RESOLVE_STRICT_NONLOCAL),
+ AED0(XMLConstants.ACCESS_EXTERNAL_DTD, SP_ACCESS_EXTERNAL_DTD, Type.PROPERTY, ACCESS_EXTERNAL_ALL),
+ AED2(XMLConstants.ACCESS_EXTERNAL_DTD, SP_ACCESS_EXTERNAL_DTD, Type.PROPERTY, ACCESS_EXTERNAL_NONE),
+ AES0(XMLConstants.ACCESS_EXTERNAL_SCHEMA, SP_ACCESS_EXTERNAL_SCHEMA, Type.PROPERTY, ACCESS_EXTERNAL_ALL),
+ AES2(XMLConstants.ACCESS_EXTERNAL_SCHEMA, SP_ACCESS_EXTERNAL_SCHEMA, Type.PROPERTY, ACCESS_EXTERNAL_NONE),
+ AEX0(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, SP_ACCESS_EXTERNAL_STYLESHEET, Type.PROPERTY, ACCESS_EXTERNAL_ALL),
+ AEX2(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, SP_ACCESS_EXTERNAL_STYLESHEET, Type.PROPERTY, ACCESS_EXTERNAL_NONE),
+
+ ACCESS0(SP_ACCESS, "ditto", Type.PROPERTY, ACCESS_ALLOW),
+ ACCESS1(SP_ACCESS, "ditto", Type.PROPERTY, ACCESS_DENY),
// StAX properties
SUPPORT_DTD(XMLInputFactory.SUPPORT_DTD, null, Type.FEATURE, "true"),
@@ -243,10 +273,21 @@ protected void process(String filename, DocumentBuilderFactory dbf, boolean expe
String error) throws Exception {
//dbf.setAttribute(CatalogFeatures.Feature.RESOLVE.getPropertyName(), "continue");
DocumentBuilder builder = dbf.newDocumentBuilder();
+ builder.setEntityResolver((String publicId, String systemId) -> {
+ InputSource dtd = null;
+ InputStream is = null;
+ if ("http://foo.bar/dtd/test.dtd".equals(systemId)) {
+ is = getClass().getResourceAsStream("/local/store/path/test.dtd");
+ }
+ if (is != null) {
+ dtd = new InputSource(is);
+ }
+ return dtd;
+ });
File file = new File(getPath(TEST_SOURCE_DIR, filename));
try {
- Document document = builder.parse(file);
- Assert.assertTrue(!expectError);
+ builder.parse(file);
+ processResult(expectError, error);
} catch (Exception e) {
e.printStackTrace();
processError(expectError, error, e);
@@ -259,7 +300,7 @@ protected void process(String filename, SAXParser parser, boolean expectError,
File file = new File(getPath(TEST_SOURCE_DIR, filename));
try {
parser.parse(file, new DefaultHandler());
- Assert.assertTrue(!expectError);
+ processResult(expectError, error);
} catch (Exception e) {
//e.printStackTrace();
processError(expectError, error, e);
@@ -275,8 +316,7 @@ protected void process(String filename, XMLInputFactory xif, boolean expectError
XMLStreamReader streamReader = xif.createXMLStreamReader(xml, entityxml);
String text = getText(streamReader, XMLStreamConstants.CHARACTERS);
System.out.println("Text: [" + text.trim() + "]");
- Assert.assertTrue(Pattern.matches(expected, text.trim()));
- Assert.assertTrue(!expectError);
+ processResult(expectError, expected);
} catch (Exception e) {
e.printStackTrace();
processError(expectError, expected, e);
@@ -289,8 +329,8 @@ protected void process(String filename, SchemaFactory sf, boolean expectError,
String xsd = getPath(TEST_SOURCE_DIR, filename);
try {
Schema schema = sf.newSchema(new StreamSource(new File(xsd)));
- Assert.assertTrue(!expectError);
- } catch (Exception e) {
+ processResult(expectError, expected);
+ } catch (SAXException e) {
e.printStackTrace();
processError(expectError, expected, e);
}
@@ -298,13 +338,13 @@ protected void process(String filename, SchemaFactory sf, boolean expectError,
protected void process(String filename, TransformerFactory tf, boolean expectError,
String expected) throws Exception {
- String xsl = getPath(TEST_SOURCE_DIR, filename);
+ String xsl = getSystemId(TEST_SOURCE_DIR, filename);
try {
SAXSource xslSource = new SAXSource(new InputSource(xsl));
xslSource.setSystemId(xsl);
Transformer transformer = tf.newTransformer(xslSource);
- Assert.assertTrue(!expectError);
- } catch (Exception e) {
+ processResult(expectError, expected);
+ } catch (TransformerConfigurationException e) {
//e.printStackTrace();
processError(expectError, expected, e);
}
@@ -312,15 +352,14 @@ protected void process(String filename, TransformerFactory tf, boolean expectErr
protected void transform(String xmlFile, String xsl, TransformerFactory tf,
boolean expectError, String expected) throws Exception {
- String xmlSysId = getPath(TEST_SOURCE_DIR, xmlFile);
+ String xmlSysId = getSystemId(TEST_SOURCE_DIR, xmlFile);
try {
SAXSource xslSource = new SAXSource(new InputSource(new StringReader(xsl)));
- //SAXSource xslSource = new SAXSource(new InputSource(xslSysId));
xslSource.setSystemId(xmlSysId);
Transformer transformer = tf.newTransformer(xslSource);
StringWriter sw = new StringWriter();
transformer.transform(getSource(SourceType.STREAM, xmlSysId), new StreamResult(sw));
- Assert.assertTrue(!expectError);
+ processResult(expectError, expected);
} catch (Exception e) {
processError(expectError, expected, e);
}
@@ -333,16 +372,23 @@ protected void validate(String filename, SchemaFactory sf, boolean expectError,
Schema schema = sf.newSchema();
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new File(xml)));
- Assert.assertTrue(!expectError);
+ processResult(expectError, expected);
} catch (Exception e) {
e.printStackTrace();
processError(expectError, expected, e);
}
}
+ protected void processResult(boolean expectError, String expected) {
+ if (expectError) {
+ Assert.assertTrue(false, "Expected error, but processing succeeded.");
+ }
+ }
+
protected void processError(boolean expectError, String error, Exception e)
throws Exception {
String str = e.getMessage();
+ String errorText = getErrorText(e);
if (!expectError) {
Assert.assertTrue(false, "Expected pass, but Exception is thrown " + str);
} else {
@@ -351,11 +397,33 @@ protected void processError(boolean expectError, String error, Exception e)
if (UNKNOWN_HOST.equals(error)) {
Assert.assertTrue((str != null) && str.equals(error));
} else {
- Assert.assertTrue((str != null) && str.contains(error));
+ String matched = null;
+ for (String err : error.split(",")) {
+ String trimmed = err.trim();
+ if (!trimmed.isEmpty() && errorText.contains(trimmed)) {
+ matched = trimmed;
+ break;
+ }
+ }
+ if (matched == null) {
+ Assert.assertTrue(false,"Missing expected error code(s): " + error);
+ }
+ Assert.assertTrue(true, "Found expected error code: " + matched);
}
}
}
+ private String getErrorText(Throwable t) {
+ StringBuilder sb = new StringBuilder();
+ while (t != null) {
+ if (t.getMessage() != null) {
+ sb.append(t.getMessage()).append('\n');
+ }
+ t = t.getCause();
+ }
+ return sb.toString();
+ }
+
/**
* Returns a DocumentBuilderFactory with settings as specified.
*
@@ -667,11 +735,15 @@ protected void setSystemProperty1(Properties config, PropertyState state, Proper
System.setProperty(property.spName, property.value);
break;
case CONFIG_FILE:
- System.setProperty(CONFIG_FILE, config.value);
+ if (config != null) {
+ System.setProperty(CONFIG_FILE, config.value);
+ }
break;
case CONFIG_FILE_SYSTEM:
case CONFIG_FILE_SYSTEM_API:
- System.setProperty(CONFIG_FILE, config.value);
+ if (config != null) {
+ System.setProperty(CONFIG_FILE, config.value);
+ }
if (property != null) {
System.setProperty(property.spName, property.value);
}
@@ -714,7 +786,11 @@ protected void clearSystemProperty1(PropertyState m, Properties property) {
}
}
- static String getPath(String base, String file) {
+ public static String getSystemId(String base, String file) {
+ return Path.of(base, file).toUri().toString();
+ }
+
+ public static String getPath(String base, String file) {
String temp = base + file;
if (IS_WINDOWS) {
temp = "/" + temp;
@@ -734,6 +810,8 @@ public static void assertTrue(boolean condition, String message) {
} else {
throw new RuntimeException("Expected true but was false. ");
}
+ } else if (message != null && !message.isEmpty()) {
+ System.out.println("Passed: " + message);
}
}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/xmlfiles/XI_simple.xml b/test/jaxp/javax/xml/jaxp/unittest/common/xmlfiles/XI_simple.xml
new file mode 100644
index 00000000000..98155ece7bb
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/xmlfiles/XI_simple.xml
@@ -0,0 +1,2 @@
+
+123
From 212b4009a75076836b8f6b87893665b449f0d994 Mon Sep 17 00:00:00 2001
From: William Kemper
Date: Thu, 1 Oct 2026 16:59:42 +0000
Subject: [PATCH 11/98] 8393348: Shenandoah: Use Event::log, not EventMark for
simple messages
Reviewed-by: shade, xpeng, ruili
---
.../gc/shenandoah/shenandoahGenerationalControlThread.cpp | 5 +++--
src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp
index 3f9d789123b..1c2571af208 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp
@@ -787,8 +787,9 @@ void ShenandoahGenerationalControlThread::set_gc_mode(GCMode new_mode) {
void ShenandoahGenerationalControlThread::set_gc_mode(MonitorLocker& ml, GCMode new_mode) {
if (_gc_mode != new_mode) {
- log_debug(gc, thread)("Transition from: %s to: %s", gc_mode_name(_gc_mode), gc_mode_name(new_mode));
- EventMark event("Control thread transition from: %s, to %s", gc_mode_name(_gc_mode), gc_mode_name(new_mode));
+ FormatBuffer<> msg("Transition from: %s to: %s", gc_mode_name(_gc_mode), gc_mode_name(new_mode));
+ log_debug(gc, thread)("%s", msg.buffer());
+ Events::log(this, "%s", msg.buffer());
_gc_mode = new_mode;
ml.notify_all();
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
index 020c66aa1fe..be09113c3b5 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
@@ -513,8 +513,9 @@ const char* ShenandoahOldGeneration::state_name(State state) {
void ShenandoahOldGeneration::transition_to(State new_state) {
if (_state != new_state) {
- log_debug(gc, thread)("Old generation transition from %s to %s", state_name(_state), state_name(new_state));
- EventMark event("Old was %s, now is %s", state_name(_state), state_name(new_state));
+ FormatBuffer<> msg("Old was %s, now is %s", state_name(_state), state_name(new_state));
+ log_debug(gc, thread)("%s", msg.buffer());
+ Events::log(Thread::current(), "%s", msg.buffer());
validate_transition(new_state);
_state = new_state;
}
From b7704a5642dedd44e9da6860ede0df716d3c165d Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev
Date: Thu, 1 Oct 2026 17:55:17 +0000
Subject: [PATCH 12/98] 8393319: ClassPathZipEntry::has_entry exposes
unhandlized oops
Reviewed-by: dholmes, iklam
---
src/hotspot/share/classfile/classLoader.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp
index 15a8a0c576a..d27681e0b26 100644
--- a/src/hotspot/share/classfile/classLoader.cpp
+++ b/src/hotspot/share/classfile/classLoader.cpp
@@ -392,8 +392,8 @@ bool ClassPathZipEntry::has_entry(JavaThread* current, const char* name, Handle
assert(SystemDictionaryShared::is_builtin_loader(ClassLoaderData::class_loader_data(class_loader())), "must be");
JavaValue result(T_OBJECT);
oop class_name_oop = java_lang_String::create_oop_from_str(name, current);
- oop zip_name_oop = CDSProtectionDomain::to_file_URL(_zip_name, Handle(), current);
Handle h_class_name(current, class_name_oop);
+ oop zip_name_oop = CDSProtectionDomain::to_file_URL(_zip_name, Handle(), current);
Handle h_zip_name(current, zip_name_oop);
// URL ClassLoader.getResource(String name)
From 63fd3e87adfdbc7d32e145c882632d309d5c6235 Mon Sep 17 00:00:00 2001
From: Phil Race
Date: Thu, 1 Oct 2026 20:38:01 +0000
Subject: [PATCH 13/98] 8393155: Remove unused medialib code for Convolve edge
mode MLIB_EDGE_SRC_EXTEND
Reviewed-by: serb, jdv
---
.../libawt/awt/medialib/awt_ImagingLib.c | 60 -
.../native/libmlib_image/mlib_ImageConv.h | 70 -
.../mlib_ImageConvCopyEdge_Bit.c | 353 -----
.../native/libmlib_image/mlib_ImageConvEdge.h | 24 -
.../native/libmlib_image/mlib_ImageConvMxN.c | 53 -
.../libmlib_image/mlib_ImageConvMxN_Fp.c | 570 -------
.../libmlib_image/mlib_ImageConvMxN_ext.c | 304 ----
.../libmlib_image/mlib_ImageConv_16ext.c | 1340 ----------------
.../libmlib_image/mlib_ImageConv_8ext.c | 1325 ----------------
.../libmlib_image/mlib_ImageConv_u16ext.c | 1348 -----------------
.../native/libmlib_image/mlib_c_ImageConv.h | 48 -
.../libmlib_image/mlib_c_ImageConvCopyEdge.c | 165 --
.../native/libmlib_image/mlib_c_ImageConv_f.c | 28 -
13 files changed, 5688 deletions(-)
delete mode 100644 src/java.desktop/share/native/libmlib_image/mlib_ImageConvCopyEdge_Bit.c
delete mode 100644 src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_ext.c
delete mode 100644 src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16ext.c
delete mode 100644 src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8ext.c
delete mode 100644 src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16ext.c
delete mode 100644 src/java.desktop/share/native/libmlib_image/mlib_c_ImageConvCopyEdge.c
diff --git a/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c b/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c
index b6e10617cc3..64a0579b90e 100644
--- a/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c
+++ b/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c
@@ -2133,36 +2133,6 @@ allocateArray(JNIEnv *env, BufImageS_t *imageP,
/* increment width. Expanding top and left requires bumping */
/* around pointers and incrementing the width/height */
-#if 0
- if (0 && useEdges) {
- baseWidth = rasterP->baseRasterWidth;
- baseHeight = rasterP->baseRasterHeight;
- baseXoff = rasterP->baseOriginX;
- baseYoff = rasterP->baseOriginY;
-
- if (rasterP->minX + rasterP->width < baseXoff + baseWidth) {
- /* Can use edge */
- width++;
- }
- if (rasterP->minY + rasterP->height < baseYoff + baseHeight) {
- /* Can use edge */
- height++;
- }
-
- if (rasterP->minX > baseXoff ) {
- /* Can use edge */
- width++;
- /* NEED TO BUMP POINTER BACK A PIXELSTRIDE */
- }
- if (rasterP->minY > baseYoff) {
- /* Can use edge */
- height++;
- /* NEED TO BUMP POINTER BACK A SCANLINE */
- }
-
-
- }
-#endif
if (cvtToDefault) {
int status = 0;
*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height);
@@ -2317,36 +2287,6 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
/* increment width. Expanding top and left requires bumping */
/* around pointers and incrementing the width/height */
-#if 0
- if (0 && useEdges) {
- baseWidth = rasterP->baseRasterWidth;
- baseHeight = rasterP->baseRasterHeight;
- baseXoff = rasterP->baseOriginX;
- baseYoff = rasterP->baseOriginY;
-
- if (rasterP->minX + rasterP->width < baseXoff + baseWidth) {
- /* Can use edge */
- width++;
- }
- if (rasterP->minY + rasterP->height < baseYoff + baseHeight) {
- /* Can use edge */
- height++;
- }
-
- if (rasterP->minX > baseXoff ) {
- /* Can use edge */
- width++;
- /* NEED TO BUMP POINTER BACK A PIXELSTRIDE */
- }
- if (rasterP->minY > baseYoff) {
- /* Can use edge */
- height++;
- /* NEED TO BUMP POINTER BACK A SCANLINE */
- }
-
-
- }
-#endif
switch (rasterP->type) {
case sun_awt_image_IntegerComponentRaster_TYPE_INT_8BIT_SAMPLES:
if (!((rasterP->chanOffsets[0] == 0 || SAFE_TO_ALLOC_2(rasterP->chanOffsets[0], 4)) &&
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv.h b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv.h
index 2528fb1eae7..b3e7a2b3d5e 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv.h
+++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv.h
@@ -39,18 +39,6 @@ if (k != akernel) mlib_free(k); \
return status
#endif /* FREE_AND_RETURN_STATUS */
-mlib_status mlib_convMxNext_s32(mlib_image *dst,
- const mlib_image *src,
- const mlib_s32 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 scale,
- mlib_s32 cmask);
-
mlib_status mlib_convMxNnw_d64(mlib_image *dst,
const mlib_image *src,
const mlib_d64 *ker,
@@ -125,64 +113,6 @@ mlib_status mlib_convMxNnw_u8(mlib_image *dst,
mlib_s32 scale,
mlib_s32 cmask);
-mlib_status mlib_convMxNext_u8(mlib_image *dst,
- const mlib_image *src,
- const mlib_s32 *kern,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 scale,
- mlib_s32 cmask);
-
-mlib_status mlib_convMxNext_s16(mlib_image *dst,
- const mlib_image *src,
- const mlib_s32 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 scale,
- mlib_s32 cmask);
-
-mlib_status mlib_convMxNext_u16(mlib_image *dst,
- const mlib_image *src,
- const mlib_s32 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 scale,
- mlib_s32 cmask);
-
-mlib_status mlib_convMxNext_f32(mlib_image *dst,
- const mlib_image *src,
- const mlib_d64 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask);
-
-mlib_status mlib_convMxNext_d64(mlib_image *dst,
- const mlib_image *src,
- const mlib_d64 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask);
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvCopyEdge_Bit.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvCopyEdge_Bit.c
deleted file mode 100644
index d9686db5ca7..00000000000
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvCopyEdge_Bit.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
- * 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.
- */
-
-
-/*
- * FUNCTIONS
- * mlib_ImageConvCopyEdge_Bit - Copy src edges to dst edges
- *
- *
- * SYNOPSIS
- * mlib_status mlib_ImageConvCopyEdge_Bit(mlib_image *dst,
- * const mlib_image *src,
- * mlib_s32 dx_l,
- * mlib_32 dx_r,
- * mlib_s32 dy_t,
- * mlib_32 dy_b,
- * mlib_s32 cmask);
- *
- * ARGUMENT
- * dst Pointer to an dst image.
- * src Pointer to an src image.
- * dx_l Number of columns on the left side of the
- * image to be copied.
- * dx_r Number of columns on the right side of the
- * image to be copied.
- * dy_t Number of rows on the top edge of the
- * image to be copied.
- * dy_b Number of rows on the top edge of the
- * image to be copied.
- * cmask Channel mask to indicate the channels to be convolved.
- * Each bit of which represents a channel in the image. The
- * channels corresponded to 1 bits are those to be processed.
- *
- * RESTRICTION
- * The src and the dst must be the MLIB_BIT type, same width, same height and have same number
- * of channels (1). The unselected channels are not
- * overwritten. If both src and dst have just one channel,
- * cmask is ignored.
- *
- * DESCRIPTION
- * Copy src edges to dst edges.
- *
- * The unselected channels are not overwritten.
- * If src and dst have just one channel,
- * cmask is ignored.
- */
-
-#include "mlib_image.h"
-#include "mlib_ImageConvEdge.h"
-
-/***************************************************************/
-mlib_status mlib_ImageConvCopyEdge_Bit(mlib_image *dst,
- const mlib_image *src,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask)
-{
- mlib_u8 *pdst = mlib_ImageGetData(dst), *pd;
- mlib_u8 *psrc = mlib_ImageGetData(src), *ps;
- mlib_s32 img_height = mlib_ImageGetHeight(dst);
- mlib_s32 img_width = mlib_ImageGetWidth(dst);
- mlib_s32 img_strided = mlib_ImageGetStride(dst);
- mlib_s32 img_strides = mlib_ImageGetStride(src);
- mlib_s32 bitoffd = mlib_ImageGetBitOffset(dst);
- mlib_s32 bitoffs = mlib_ImageGetBitOffset(src);
- mlib_s32 bitoff_end, test, shift1, shift2;
- mlib_u32 s0, s1, tmp;
- mlib_u8 mask, mask_end;
- mlib_u8 tmp_start, tmp_end;
- mlib_s32 i, j, amount;
-
- if (bitoffd == bitoffs) {
- pd = pdst;
- ps = psrc;
-
- if (dx_l > 0) {
- if (bitoffd + dx_l <= 8) {
- mask = (0xFF >> bitoffd) & (0xFF << ((8 - (bitoffd + dx_l)) & 7));
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- pd[i*img_strided] = (pd[i*img_strided] & ~mask) | (ps[i*img_strides] & mask);
- }
-
- } else {
- mask = (0xFF >> bitoffd);
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- pd[i*img_strided] = (pd[i*img_strided] & ~mask) | (ps[i*img_strides] & mask);
- }
-
- amount = (bitoffd + dx_l + 7) >> 3;
- mask = (0xFF << ((8 - (bitoffd + dx_l)) & 7));
-
- for (j = 1; j < amount - 1; j++) {
- for (i = dy_t; i < (img_height - dy_b); i++) {
- pd[i*img_strided + j] = ps[i*img_strides + j];
- }
- }
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- pd[i*img_strided + amount - 1] = (pd[i*img_strided + amount - 1] & ~mask) |
- (ps[i*img_strides + amount - 1] & mask);
- }
- }
- }
-
- if (dx_r > 0) {
- pd = pdst + (img_width + bitoffd - dx_r) / 8;
- ps = psrc + (img_width + bitoffd - dx_r) / 8;
- bitoffd = (img_width + bitoffd - dx_r) & 7;
-
- if (bitoffd + dx_r <= 8) {
- mask = (0xFF >> bitoffd) & (0xFF << ((8 - (bitoffd + dx_r)) & 7));
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- pd[i*img_strided] = (pd[i*img_strided] & ~mask) | (ps[i*img_strides] & mask);
- }
-
- } else {
- mask = (0xFF >> bitoffd);
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- pd[i*img_strided] = (pd[i*img_strided] & ~mask) | (ps[i*img_strides] & mask);
- }
-
- amount = (bitoffd + dx_r + 7) >> 3;
- mask = (0xFF << ((8 - (bitoffd + dx_r)) & 7));
-
- for (j = 1; j < amount - 1; j++) {
- for (i = dy_t; i < (img_height - dy_b); i++) {
- pd[i*img_strided + j] = ps[i*img_strides + j];
- }
- }
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- pd[i*img_strided + amount - 1] = (pd[i*img_strided + amount - 1] & ~mask) |
- (ps[i*img_strides + amount - 1] & mask);
- }
- }
- }
-
- bitoffd = mlib_ImageGetBitOffset(dst);
- bitoff_end = (bitoffd + img_width) & 7;
- amount = (bitoffd + img_width + 7) >> 3;
- mask = (0xFF >> bitoffd);
- mask_end = (0xFF << ((8 - bitoff_end) & 7));
-
- pd = pdst;
- ps = psrc;
-
- for (i = 0; i < dy_t; i++) {
- tmp_start = pd[i*img_strided];
- tmp_end = pd[i*img_strided+amount-1];
- for (j = 0; j < amount; j++) {
- pd[i*img_strided + j] = ps[i*img_strides + j];
- }
-
- pd[i*img_strided] = (tmp_start & (~mask)) | (pd[i*img_strided] & mask);
- pd[i*img_strided+amount-1] = (tmp_end & (~mask_end)) |
- (pd[i*img_strided+amount-1] & mask_end);
- }
-
- pd = pdst + (img_height-1)*img_strided;
- ps = psrc + (img_height-1)*img_strides;
-
- for (i = 0; i < dy_b; i++) {
- tmp_start = pd[-i*img_strided];
- tmp_end = pd[-i*img_strided+amount-1];
- for (j = 0; j < amount; j++) {
- pd[-i*img_strided + j] = ps[-i*img_strides + j];
- }
-
- pd[-i*img_strided] = (tmp_start & (~mask)) | (pd[-i*img_strided] & mask);
- pd[-i*img_strided+amount-1] = (tmp_end & (~mask_end)) |
- (pd[-i*img_strided+amount-1] & mask_end);
- }
-
- } else {
- pd = pdst;
-
- if (bitoffs > bitoffd) {
- ps = psrc;
- shift2 = (8 - (bitoffs - bitoffd));
- test = 0;
- } else {
- test = 1;
- ps = psrc - 1;
- shift2 = bitoffd - bitoffs;
- }
-
- shift1 = 8 - shift2;
-
- if (dx_l > 0) {
- if (bitoffd + dx_l <= 8) {
- mask = (0xFF >> bitoffd) & (0xFF << ((8 - (bitoffd + dx_l)) & 7));
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- s0 = ps[i*img_strides];
- s1 = ps[i*img_strides+1];
- tmp = (s0 << shift1) | (s1 >> shift2);
- pd[i*img_strided] = (pd[i*img_strided] & ~mask) | (tmp & mask);
- }
-
- } else {
- mask = (0xFF >> bitoffd);
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- s0 = ps[i*img_strides];
- s1 = ps[i*img_strides+1];
- tmp = (s0 << shift1) | (s1 >> shift2);
- pd[i*img_strided] = (pd[i*img_strided] & ~mask) | (tmp & mask);
- }
-
- amount = (bitoffd + dx_l + 7) >> 3;
- mask = (0xFF << ((8 - (bitoffd + dx_l)) & 7));
-
- for (j = 1; j < amount - 1; j++) {
- for (i = dy_t; i < (img_height - dy_b); i++) {
- s0 = ps[i*img_strides+j];
- s1 = ps[i*img_strides+j+1];
- pd[i*img_strided + j] = (s0 << shift1) | (s1 >> shift2);
- s0 = s1;
- }
- }
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- s0 = ps[i*img_strides+amount-1];
- s1 = ps[i*img_strides+amount];
- tmp = (s0 << shift1) | (s1 >> shift2);
- pd[i*img_strided + amount - 1] = (pd[i*img_strided + amount - 1] & ~mask) |
- (tmp & mask);
- }
- }
- }
-
- if (dx_r > 0) {
- pd = pdst + (img_width + bitoffd - dx_r) / 8;
- ps = psrc + (img_width + bitoffd - dx_r) / 8;
- bitoffd = (img_width + bitoffd - dx_r) & 7;
- ps -= test;
-
- if (bitoffd + dx_r <= 8) {
- mask = (0xFF >> bitoffd) & (0xFF << ((8 - (bitoffd + dx_r)) & 7));
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- s0 = ps[i*img_strides];
- s1 = ps[i*img_strides+1];
- tmp = (s0 << shift1) | (s1 >> shift2);
- pd[i*img_strided] = (pd[i*img_strided] & ~mask) | (tmp & mask);
- }
-
- } else {
- mask = (0xFF >> bitoffd);
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- s0 = ps[i*img_strides];
- s1 = ps[i*img_strides+1];
- tmp = (s0 << shift1) | (s1 >> shift2);
- pd[i*img_strided] = (pd[i*img_strided] & ~mask) | (tmp & mask);
- }
-
- amount = (bitoffd + dx_r + 7) >> 3;
- mask = (0xFF << ((8 - (bitoffd + dx_r)) & 7));
-
- for (j = 1; j < amount - 1; j++) {
- for (i = dy_t; i < (img_height - dy_b); i++) {
- s0 = ps[i*img_strides+j];
- s1 = ps[i*img_strides+j+1];
- pd[i*img_strided + j] = (s0 << shift1) | (s1 >> shift2);
- }
- }
-
- for (i = dy_t; i < (img_height - dy_b); i++) {
- s0 = ps[i*img_strides+amount-1];
- s1 = ps[i*img_strides+amount];
- tmp = (s0 << shift1) | (s1 >> shift2);
- pd[i*img_strided + amount - 1] = (pd[i*img_strided + amount - 1] & ~mask) |
- (tmp & mask);
- }
- }
- }
-
- bitoffd = mlib_ImageGetBitOffset(dst);
- bitoff_end = (bitoffd + img_width) & 7;
- amount = (bitoffd + img_width + 7) >> 3;
- mask = (0xFF >> bitoffd);
- mask_end = (0xFF << ((8 - bitoff_end) & 7));
-
- pd = pdst;
- ps = psrc-test;
-
- for (i = 0; i < dy_t; i++) {
- tmp_start = pd[i*img_strided];
- tmp_end = pd[i*img_strided+amount-1];
- s0 = ps[i*img_strides];
- for (j = 0; j < amount; j++) {
- s1 = ps[i*img_strides+j+1];
- pd[i*img_strided + j] = (s0 << shift1) | (s1 >> shift2);
- s0 = s1;
- }
-
- pd[i*img_strided] = (tmp_start & (~mask)) | (pd[i*img_strided] & mask);
- pd[i*img_strided+amount-1] = (tmp_end & (~mask_end)) |
- (pd[i*img_strided+amount-1] & mask_end);
- }
-
- pd = pdst + (img_height-1)*img_strided;
- ps = psrc + (img_height-1)*img_strides - test;
-
- for (i = 0; i < dy_b; i++) {
- tmp_start = pd[-i*img_strided];
- tmp_end = pd[-i*img_strided+amount-1];
- s0 = ps[-i*img_strides];
- for (j = 0; j < amount; j++) {
- s1 = ps[-i*img_strides+j+1];
- pd[-i*img_strided + j] = (s0 << shift1) | (s1 >> shift2);
- s0 = s1;
- }
-
- pd[-i*img_strided] = (tmp_start & (~mask)) | (pd[-i*img_strided] & mask);
- pd[-i*img_strided+amount-1] = (tmp_end & (~mask_end)) |
- (pd[-i*img_strided+amount-1] & mask_end);
- }
- }
-
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvEdge.h b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvEdge.h
index 86108443371..7aaabfcc20b 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvEdge.h
+++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvEdge.h
@@ -62,30 +62,6 @@ mlib_status mlib_ImageConvZeroEdge(mlib_image *dst,
mlib_s32 dy_b,
mlib_s32 cmask);
-mlib_status mlib_ImageConvCopyEdge_Bit(mlib_image *dst,
- const mlib_image *src,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask);
-
-mlib_status mlib_ImageConvCopyEdge(mlib_image *dst,
- const mlib_image *src,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask);
-
-mlib_status mlib_ImageConvCopyEdge_Fp(mlib_image *dst,
- const mlib_image *src,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask);
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c
index bdc0bb0372a..7723b3c6191 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c
+++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c
@@ -216,9 +216,6 @@ mlib_status mlib_ImageConvMxN_f(mlib_image *dst,
case MLIB_EDGE_DST_FILL_ZERO:
mlib_ImageConvZeroEdge(dst_e, dx_l, dx_r, dy_t, dy_b, cmask);
break;
- case MLIB_EDGE_DST_COPY_SRC:
- mlib_ImageConvCopyEdge(dst_e, src_e, dx_l, dx_r, dy_t, dy_b, cmask);
- break;
default:
/* Other edge conditions do not need additional handling.
* Note also that they are not exposed in public Java API
@@ -226,56 +223,6 @@ mlib_status mlib_ImageConvMxN_f(mlib_image *dst,
break;
}
}
- else { /* MLIB_EDGE_SRC_EXTEND */
- /* adjust src_e image */
- mlib_ImageSetSubimage(src_e, src_e, dx_l - dm, dy_t - dn,
- mlib_ImageGetWidth(src_e), mlib_ImageGetHeight(src_e));
-
- switch (type) {
- case MLIB_BYTE:
- ret =
- mlib_convMxNext_u8(dst_e, src_e, kernel, m, n, dx_l, dx_r, dy_t, dy_b, scale,
- cmask);
- break;
- case MLIB_SHORT:
- if (mlib_ImageConvVersion(m, n, scale, type) == 0)
- ret =
- mlib_convMxNext_s16(dst_e, src_e, kernel, m, n, dx_l, dx_r, dy_t, dy_b, scale,
- cmask);
- else
- ret =
- mlib_i_convMxNext_s16(dst_e, src_e, kernel, m, n, dx_l, dx_r, dy_t, dy_b,
- scale, cmask);
- break;
- case MLIB_USHORT:
- if (mlib_ImageConvVersion(m, n, scale, type) == 0)
- ret =
- mlib_convMxNext_u16(dst_e, src_e, kernel, m, n, dx_l, dx_r, dy_t, dy_b, scale,
- cmask);
- else
- ret =
- mlib_i_convMxNext_u16(dst_e, src_e, kernel, m, n, dx_l, dx_r, dy_t, dy_b,
- scale, cmask);
- break;
- case MLIB_INT:
- ret =
- mlib_convMxNext_s32(dst_e, src_e, kernel, m, n, dx_l, dx_r, dy_t, dy_b, scale,
- cmask);
- break;
- case MLIB_FLOAT:
- mlib_convMxNext_f32(dst_e, src_e, kernel, m, n, dx_l, dx_r, dy_t, dy_b, cmask);
- break;
- case MLIB_DOUBLE:
- mlib_convMxNext_d64(dst_e, src_e, kernel, m, n, dx_l, dx_r, dy_t, dy_b, cmask);
- break;
- default:
- /* For some reasons, there is no convolution routine for type MLIB_BIT.
- * For now, we silently ignore it (because this image type is not used by java),
- * but probably we have to report an error.
- */
- break;
- }
- }
return ret;
}
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c
index bc2df9b0b1a..11d7e9d3387 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c
+++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c
@@ -78,60 +78,6 @@
#include "mlib_ImageConv.h"
#include "safe_math.h"
-/***************************************************************/
-static void mlib_ImageConvMxNMulAdd_F32(mlib_f32 *dst,
- const mlib_f32 *src,
- const mlib_d64 *kernel,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch,
- mlib_s32 dnch);
-
-static void mlib_ImageConvMxNF322F32_ext(mlib_f32 *dst,
- const mlib_f32 *src,
- mlib_s32 n,
- mlib_s32 nch,
- mlib_s32 dx_l,
- mlib_s32 dx_r);
-
-static void mlib_ImageConvMxNMulAdd_D64(mlib_d64 *dst,
- const mlib_d64 *src,
- const mlib_d64 *kernel,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch,
- mlib_s32 dnch);
-
-static void mlib_ImageConvMxND642D64_ext(mlib_d64 *dst,
- const mlib_d64 *src,
- mlib_s32 n,
- mlib_s32 nch,
- mlib_s32 dx_l,
- mlib_s32 dx_r);
-
-/***************************************************************/
-#if 0
-static void mlib_ImageConvMxNMulAdd2_F32(mlib_f32 *hdst,
- mlib_f32 *vdst,
- const mlib_f32 *src,
- const mlib_d64 *hfilter,
- const mlib_d64 *vfilter,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch,
- mlib_s32 dnch);
-
-static void mlib_ImageConvMxNMulAdd2_D64(mlib_d64 *hdst,
- mlib_d64 *vdst,
- const mlib_d64 *src,
- const mlib_d64 *hfilter,
- const mlib_d64 *vfilter,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch,
- mlib_s32 dnch);
-#endif /* 0 */
-
/***************************************************************/
mlib_status mlib_ImageConvMxN_Fp(mlib_image *dst,
const mlib_image *src,
@@ -155,519 +101,3 @@ mlib_status mlib_ImageConvMxN_Fp(mlib_image *dst,
}
/***************************************************************/
-void mlib_ImageConvMxNMulAdd_F32(mlib_f32 *dst,
- const mlib_f32 *src,
- const mlib_d64 *kernel,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch,
- mlib_s32 dnch)
-{
- mlib_f32 *hdst1 = dst + dnch;
- mlib_s32 i, j;
-
- for (j = 0; j < m - 2; j += 3, src += 3 * nch, kernel += 3) {
- const mlib_f32 *src2 = src + 2 * nch;
- mlib_f32 hval0 = (mlib_f32) kernel[0];
- mlib_f32 hval1 = (mlib_f32) kernel[1];
- mlib_f32 hval2 = (mlib_f32) kernel[2];
- mlib_f32 val0 = src[0];
- mlib_f32 val1 = src[nch];
- mlib_f32 hdvl = dst[0];
-
- for (i = 0; i < n; i++) {
- mlib_f32 hdvl0 = val0 * hval0 + hdvl;
- mlib_f32 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- hdvl0 += val1 * hval1;
- hdvl0 += val2 * hval2;
- val0 = val1;
- val1 = val2;
-
- dst[i * dnch] = hdvl0;
- }
- }
-
- if (j < m - 1) {
- const mlib_f32 *src2 = src + 2 * nch;
- mlib_f32 hval0 = (mlib_f32) kernel[0];
- mlib_f32 hval1 = (mlib_f32) kernel[1];
- mlib_f32 val0 = src[0];
- mlib_f32 val1 = src[nch];
- mlib_f32 hdvl = dst[0];
- for (i = 0; i < n; i++) {
- mlib_f32 hdvl0 = val0 * hval0 + hdvl;
- mlib_f32 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- hdvl0 += val1 * hval1;
- val0 = val1;
- val1 = val2;
-
- dst[i * dnch] = hdvl0;
- }
-
- }
- else if (j < m) {
- const mlib_f32 *src2 = src + 2 * nch;
- mlib_f32 hval0 = (mlib_f32) kernel[0];
- mlib_f32 val0 = src[0];
- mlib_f32 val1 = src[nch];
- mlib_f32 hdvl = dst[0];
-
- for (i = 0; i < n; i++) {
- mlib_f32 hdvl0 = val0 * hval0 + hdvl;
- mlib_f32 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- val0 = val1;
- val1 = val2;
-
- dst[i * dnch] = hdvl0;
- }
- }
-}
-
-/***************************************************************/
-void mlib_ImageConvMxNF322F32_ext(mlib_f32 *dst,
- const mlib_f32 *src,
- mlib_s32 n,
- mlib_s32 nch,
- mlib_s32 dx_l,
- mlib_s32 dx_r)
-{
- mlib_s32 i;
- mlib_f32 val = src[0];
-
- for (i = 0; i < dx_l; i++)
- dst[i] = val;
- for (; i < n - dx_r; i++)
- dst[i] = src[nch * (i - dx_l)];
- val = dst[n - dx_r - 1];
- for (; i < n; i++)
- dst[i] = val;
-}
-
-/***************************************************************/
-mlib_status mlib_convMxNext_f32(mlib_image *dst,
- const mlib_image *src,
- const mlib_d64 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask)
-{
- mlib_d64 dspace[1024], *dsa = dspace;
- mlib_s32 wid_e = mlib_ImageGetWidth(src);
- mlib_f32 *fsa;
- mlib_f32 *da = mlib_ImageGetData(dst);
- mlib_f32 *sa = mlib_ImageGetData(src);
- mlib_s32 dlb = mlib_ImageGetStride(dst) >> 2;
- mlib_s32 slb = mlib_ImageGetStride(src) >> 2;
- mlib_s32 dw = mlib_ImageGetWidth(dst);
- mlib_s32 dh = mlib_ImageGetHeight(dst);
- mlib_s32 nch = mlib_ImageGetChannels(dst);
- mlib_s32 i, j, j1, k;
-
- if (!SAFE_TO_MULT(3, wid_e) || !SAFE_TO_ADD(3 * wid_e, m)) {
- return MLIB_FAILURE;
- }
- if (3 * wid_e + m > 1024) {
- dsa = mlib_malloc((3 * wid_e + m) * sizeof(mlib_d64));
-
- if (dsa == NULL)
- return MLIB_FAILURE;
- }
-
- fsa = (mlib_f32 *) dsa;
-
- for (j = 0; j < dh; j++, da += dlb) {
- for (k = 0; k < nch; k++)
- if (cmask & (1 << (nch - 1 - k))) {
- const mlib_f32 *sa1 = sa + k;
- mlib_f32 *da1 = da + k;
- const mlib_d64 *kernel1 = kernel;
-
- for (i = 0; i < dw; i++)
- da1[i * nch] = 0.f;
- for (j1 = 0; j1 < n; j1++, kernel1 += m) {
- mlib_ImageConvMxNF322F32_ext(fsa, sa1, dw + m - 1, nch, dx_l, dx_r);
- mlib_ImageConvMxNMulAdd_F32(da1, fsa, kernel1, dw, m, 1, nch);
-
- if ((j + j1 >= dy_t) && (j + j1 < dh + n - dy_b - 2))
- sa1 += slb;
- }
- }
-
- if ((j >= dy_t) && (j < dh + n - dy_b - 2))
- sa += slb;
- }
-
- if (dsa != dspace)
- mlib_free(dsa);
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
-#if 0
-
-void mlib_ImageConvMxNMulAdd2_F32(mlib_f32 *hdst,
- mlib_f32 *vdst,
- const mlib_f32 *src,
- const mlib_d64 *hfilter,
- const mlib_d64 *vfilter,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch,
- mlib_s32 dnch)
-{
- mlib_f32 *hdst1 = hdst + dnch, *vdst1 = vdst + dnch;
- mlib_s32 i, j;
-
- for (j = 0; j < m - 2; j += 3, src += 3 * nch, hfilter += 3, vfilter += 3) {
- mlib_f32 *src2 = src + 2 * nch;
- mlib_f32 hval0 = (mlib_f32) hfilter[0];
- mlib_f32 vval0 = (mlib_f32) vfilter[0];
- mlib_f32 hval1 = (mlib_f32) hfilter[1];
- mlib_f32 vval1 = (mlib_f32) vfilter[1];
- mlib_f32 hval2 = (mlib_f32) hfilter[2];
- mlib_f32 vval2 = (mlib_f32) vfilter[2];
- mlib_f32 val0 = src[0];
- mlib_f32 val1 = src[nch];
- mlib_f32 hdvl = hdst[0];
- mlib_f32 vdvl = vdst[0];
-
- for (i = 0; i < n; i++) {
- mlib_f32 hdvl0 = val0 * hval0 + hdvl;
- mlib_f32 vdvl0 = val0 * vval0 + vdvl;
- mlib_f32 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- vdvl = vdst1[i * dnch];
- hdvl0 += val1 * hval1;
- vdvl0 += val1 * vval1;
- hdvl0 += val2 * hval2;
- vdvl0 += val2 * vval2;
- val0 = val1;
- val1 = val2;
-
- hdst[i * dnch] = hdvl0;
- vdst[i * dnch] = vdvl0;
- }
- }
-
- if (j < m - 1) {
- mlib_f32 *src2 = src + 2 * nch;
- mlib_f32 hval0 = (mlib_f32) hfilter[0];
- mlib_f32 vval0 = (mlib_f32) vfilter[0];
- mlib_f32 hval1 = (mlib_f32) hfilter[1];
- mlib_f32 vval1 = (mlib_f32) vfilter[1];
- mlib_f32 val0 = src[0];
- mlib_f32 val1 = src[nch];
- mlib_f32 hdvl = hdst[0];
- mlib_f32 vdvl = vdst[0];
-
- for (i = 0; i < n; i++) {
- mlib_f32 hdvl0 = val0 * hval0 + hdvl;
- mlib_f32 vdvl0 = val0 * vval0 + vdvl;
- mlib_f32 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- vdvl = vdst1[i * dnch];
- hdvl0 += val1 * hval1;
- vdvl0 += val1 * vval1;
- val0 = val1;
- val1 = val2;
-
- hdst[i * dnch] = hdvl0;
- vdst[i * dnch] = vdvl0;
- }
-
- }
- else if (j < m) {
- mlib_f32 *src2 = src + 2 * nch;
- mlib_f32 hval0 = (mlib_f32) hfilter[0];
- mlib_f32 vval0 = (mlib_f32) vfilter[0];
- mlib_f32 val0 = src[0];
- mlib_f32 val1 = src[nch];
- mlib_f32 hdvl = hdst[0];
- mlib_f32 vdvl = vdst[0];
-
- for (i = 0; i < n; i++) {
- mlib_f32 hdvl0 = val0 * hval0 + hdvl;
- mlib_f32 vdvl0 = val0 * vval0 + vdvl;
- mlib_f32 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- vdvl = vdst1[i * dnch];
- val0 = val1;
- val1 = val2;
-
- hdst[i * dnch] = hdvl0;
- vdst[i * dnch] = vdvl0;
- }
- }
-}
-
-/***************************************************************/
-void mlib_ImageConvMxNMulAdd2_D64(mlib_d64 *hdst,
- mlib_d64 *vdst,
- const mlib_d64 *src,
- const mlib_d64 *hfilter,
- const mlib_d64 *vfilter,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch,
- mlib_s32 dnch)
-{
- mlib_d64 *hdst1 = hdst + dnch, *vdst1 = vdst + dnch;
- mlib_s32 i, j;
-
- for (j = 0; j < m - 2; j += 3, src += 3 * nch, hfilter += 3, vfilter += 3) {
- mlib_d64 *src2 = src + 2 * nch;
- mlib_d64 hval0 = hfilter[0];
- mlib_d64 vval0 = vfilter[0];
- mlib_d64 hval1 = hfilter[1];
- mlib_d64 vval1 = vfilter[1];
- mlib_d64 hval2 = hfilter[2];
- mlib_d64 vval2 = vfilter[2];
- mlib_d64 val0 = src[0];
- mlib_d64 val1 = src[nch];
- mlib_d64 hdvl = hdst[0];
- mlib_d64 vdvl = vdst[0];
-
- for (i = 0; i < n; i++) {
- mlib_d64 hdvl0 = val0 * hval0 + hdvl;
- mlib_d64 vdvl0 = val0 * vval0 + vdvl;
- mlib_d64 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- vdvl = vdst1[i * dnch];
- hdvl0 += val1 * hval1;
- vdvl0 += val1 * vval1;
- hdvl0 += val2 * hval2;
- vdvl0 += val2 * vval2;
- val0 = val1;
- val1 = val2;
-
- hdst[i * dnch] = hdvl0;
- vdst[i * dnch] = vdvl0;
- }
- }
-
- if (j < m - 1) {
- mlib_d64 *src2 = src + 2 * nch;
- mlib_d64 hval0 = hfilter[0];
- mlib_d64 vval0 = vfilter[0];
- mlib_d64 hval1 = hfilter[1];
- mlib_d64 vval1 = vfilter[1];
- mlib_d64 val0 = src[0];
- mlib_d64 val1 = src[nch];
- mlib_d64 hdvl = hdst[0];
- mlib_d64 vdvl = vdst[0];
-
- for (i = 0; i < n; i++) {
- mlib_d64 hdvl0 = val0 * hval0 + hdvl;
- mlib_d64 vdvl0 = val0 * vval0 + vdvl;
- mlib_d64 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- vdvl = vdst1[i * dnch];
- hdvl0 += val1 * hval1;
- vdvl0 += val1 * vval1;
- val0 = val1;
- val1 = val2;
-
- hdst[i * dnch] = hdvl0;
- vdst[i * dnch] = vdvl0;
- }
-
- }
- else if (j < m) {
- mlib_d64 *src2 = src + 2 * nch;
- mlib_d64 hval0 = hfilter[0];
- mlib_d64 vval0 = vfilter[0];
- mlib_d64 val0 = src[0];
- mlib_d64 val1 = src[nch];
- mlib_d64 hdvl = hdst[0];
- mlib_d64 vdvl = vdst[0];
-
- for (i = 0; i < n; i++) {
- mlib_d64 hdvl0 = val0 * hval0 + hdvl;
- mlib_d64 vdvl0 = val0 * vval0 + vdvl;
- mlib_d64 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- vdvl = vdst1[i * dnch];
- val0 = val1;
- val1 = val2;
-
- hdst[i * dnch] = hdvl0;
- vdst[i * dnch] = vdvl0;
- }
- }
-}
-
-#endif /* 0 */
-
-/***************************************************************/
-void mlib_ImageConvMxNMulAdd_D64(mlib_d64 *dst,
- const mlib_d64 *src,
- const mlib_d64 *kernel,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch,
- mlib_s32 dnch)
-{
- mlib_d64 *hdst1 = dst + dnch;
- mlib_s32 i, j;
-
- for (j = 0; j < m - 2; j += 3, src += 3 * nch, kernel += 3) {
- const mlib_d64 *src2 = src + 2 * nch;
- mlib_d64 hval0 = kernel[0];
- mlib_d64 hval1 = kernel[1];
- mlib_d64 hval2 = kernel[2];
- mlib_d64 val0 = src[0];
- mlib_d64 val1 = src[nch];
- mlib_d64 hdvl = dst[0];
-
- for (i = 0; i < n; i++) {
- mlib_d64 hdvl0 = val0 * hval0 + hdvl;
- mlib_d64 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- hdvl0 += val1 * hval1;
- hdvl0 += val2 * hval2;
- val0 = val1;
- val1 = val2;
-
- dst[i * dnch] = hdvl0;
- }
- }
-
- if (j < m - 1) {
- const mlib_d64 *src2 = src + 2 * nch;
- mlib_d64 hval0 = kernel[0];
- mlib_d64 hval1 = kernel[1];
- mlib_d64 val0 = src[0];
- mlib_d64 val1 = src[nch];
- mlib_d64 hdvl = dst[0];
-
- for (i = 0; i < n; i++) {
- mlib_d64 hdvl0 = val0 * hval0 + hdvl;
- mlib_d64 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- hdvl0 += val1 * hval1;
- val0 = val1;
- val1 = val2;
-
- dst[i * dnch] = hdvl0;
- }
-
- }
- else if (j < m) {
- const mlib_d64 *src2 = src + 2 * nch;
- mlib_d64 hval0 = kernel[0];
- mlib_d64 val0 = src[0];
- mlib_d64 val1 = src[nch];
- mlib_d64 hdvl = dst[0];
-
- for (i = 0; i < n; i++) {
- mlib_d64 hdvl0 = val0 * hval0 + hdvl;
- mlib_d64 val2 = src2[i * nch];
-
- hdvl = hdst1[i * dnch];
- val0 = val1;
- val1 = val2;
-
- dst[i * dnch] = hdvl0;
- }
- }
-}
-
-/***************************************************************/
-void mlib_ImageConvMxND642D64_ext(mlib_d64 *dst,
- const mlib_d64 *src,
- mlib_s32 n,
- mlib_s32 nch,
- mlib_s32 dx_l,
- mlib_s32 dx_r)
-{
- mlib_s32 i;
- mlib_d64 val = src[0];
-
- for (i = 0; i < dx_l; i++)
- dst[i] = val;
- for (; i < n - dx_r; i++)
- dst[i] = src[nch * (i - dx_l)];
- val = dst[n - dx_r - 1];
- for (; i < n; i++)
- dst[i] = val;
-}
-
-/***************************************************************/
-mlib_status mlib_convMxNext_d64(mlib_image *dst,
- const mlib_image *src,
- const mlib_d64 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask)
-{
- mlib_d64 dspace[1024], *dsa = dspace;
- mlib_s32 wid_e = mlib_ImageGetWidth(src);
- mlib_d64 *da = mlib_ImageGetData(dst);
- mlib_d64 *sa = mlib_ImageGetData(src);
- mlib_s32 dlb = mlib_ImageGetStride(dst) >> 3;
- mlib_s32 slb = mlib_ImageGetStride(src) >> 3;
- mlib_s32 dw = mlib_ImageGetWidth(dst);
- mlib_s32 dh = mlib_ImageGetHeight(dst);
- mlib_s32 nch = mlib_ImageGetChannels(dst);
- mlib_s32 i, j, j1, k;
-
- if (!SAFE_TO_MULT(3, wid_e) || !SAFE_TO_ADD(3 * wid_e, m)) {
- return MLIB_FAILURE;
- }
- if (3 * wid_e + m > 1024) {
- dsa = mlib_malloc((3 * wid_e + m) * sizeof(mlib_d64));
-
- if (dsa == NULL)
- return MLIB_FAILURE;
- }
-
- for (j = 0; j < dh; j++, da += dlb) {
- for (k = 0; k < nch; k++)
- if (cmask & (1 << (nch - 1 - k))) {
- mlib_d64 *sa1 = sa + k;
- mlib_d64 *da1 = da + k;
- const mlib_d64 *kernel1 = kernel;
-
- for (i = 0; i < dw; i++)
- da1[i * nch] = 0.;
- for (j1 = 0; j1 < n; j1++, kernel1 += m) {
- mlib_ImageConvMxND642D64_ext(dsa, sa1, dw + m - 1, nch, dx_l, dx_r);
- mlib_ImageConvMxNMulAdd_D64(da1, dsa, kernel1, dw, m, 1, nch);
-
- if ((j + j1 >= dy_t) && (j + j1 < dh + n - dy_b - 2))
- sa1 += slb;
- }
- }
-
- if ((j >= dy_t) && (j < dh + n - dy_b - 2))
- sa += slb;
- }
-
- if (dsa != dspace)
- mlib_free(dsa);
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_ext.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_ext.c
deleted file mode 100644
index 5869b0a54af..00000000000
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_ext.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-
-/*
- * FUNCTION
- * mlib_ImageConvMxN - image convolution with edge condition
- *
- * SYNOPSIS
- * mlib_status mlib_ImageConvMxN(mlib_image *dst,
- * const mlib_image *src,
- * const mlib_s32 *kernel,
- * mlib_s32 m,
- * mlib_s32 n,
- * mlib_s32 dm,
- * mlib_s32 dn,
- * mlib_s32 scale,
- * mlib_s32 cmask,
- * mlib_edge edge)
- *
- * ARGUMENTS
- * dst Pointer to destination image.
- * src Pointer to source image.
- * m Kernel width (m must be not less than 1).
- * n Kernel height (n must be not less than 1).
- * dm, dn Position of key element in convolution kernel.
- * kernel Pointer to convolution kernel.
- * scale The scaling factor to convert the input integer
- * coefficients into floating-point coefficients:
- * floating-point coefficient = integer coefficient * 2^(-scale)
- * cmask Channel mask to indicate the channels to be convolved.
- * Each bit of which represents a channel in the image. The
- * channels corresponded to 1 bits are those to be processed.
- * edge Type of edge condition.
- *
- * DESCRIPTION
- * 2-D convolution, MxN kernel.
- *
- * The center of the source image is mapped to the center of the
- * destination image.
- * The unselected channels are not overwritten. If both src and dst have
- * just one channel, cmask is ignored.
- *
- * The edge condition can be one of the following:
- * MLIB_EDGE_DST_NO_WRITE (default)
- * MLIB_EDGE_DST_FILL_ZERO
- * MLIB_EDGE_DST_COPY_SRC
- * MLIB_EDGE_SRC_EXTEND
- *
- * RESTRICTION
- * The src and the dst must be the same type and have same number
- * of channels (1, 2, 3, or 4).
- * m >= 1, n >= 1,
- * 0 <= dm < m, 0 <= dn < n.
- * For data type MLIB_BYTE: 16 <= scale <= 31 (to be compatible with VIS version)
- * For data type MLIB_USHORT: 17 <= scale <= 32 (to be compatible with VIS version)
- * For data type MLIB_SHORT: 17 <= scale <= 32 (to be compatible with VIS version)
- * For data type MLIB_INT: scale >= 0
- */
-
-#include "mlib_image.h"
-#include "mlib_ImageConv.h"
-#include "safe_math.h"
-
-/***************************************************************/
-static void mlib_ImageConvMxNMulAdd_S32(mlib_d64 *dst,
- const mlib_s32 *src,
- const mlib_d64 *dkernel,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch);
-
-static void mlib_ImageConvMxNMedian_S32(mlib_s32 *dst,
- mlib_d64 *src,
- mlib_s32 n,
- mlib_s32 nch);
-
-static void mlib_ImageConvMxNS322S32_ext(mlib_s32 *dst,
- const mlib_s32 *src,
- mlib_s32 n,
- mlib_s32 nch,
- mlib_s32 dx_l,
- mlib_s32 dx_r);
-
-/***************************************************************/
-#ifdef MLIB_USE_FTOI_CLAMPING
-
-#define CLAMP_S32(dst, src) \
- dst = (mlib_s32)(src)
-
-#else
-
-#define CLAMP_S32(dst, src) { \
- mlib_d64 s0 = (mlib_d64)(src); \
- if (s0 > (mlib_d64)MLIB_S32_MAX) s0 = (mlib_d64)MLIB_S32_MAX; \
- if (s0 < (mlib_d64)MLIB_S32_MIN) s0 = (mlib_d64)MLIB_S32_MIN; \
- dst = (mlib_s32)s0; \
-}
-
-#endif /* MLIB_USE_FTOI_CLAMPING */
-
-/***************************************************************/
-void mlib_ImageConvMxNMulAdd_S32(mlib_d64 *dst,
- const mlib_s32 *src,
- const mlib_d64 *dkernel,
- mlib_s32 n,
- mlib_s32 m,
- mlib_s32 nch)
-{
- mlib_d64 *dst1 = dst + 1;
- mlib_s32 i, j;
-
- for (j = 0; j < m; j += 3, src += 3 * nch, dkernel += 3) {
- const mlib_s32 *src2 = src + 2 * nch;
- mlib_d64 hval0 = dkernel[0];
- mlib_d64 hval1 = dkernel[1];
- mlib_d64 hval2 = dkernel[2];
- mlib_d64 val0 = src[0];
- mlib_d64 val1 = src[nch];
- mlib_d64 dval = dst[0];
-
- if (j == m - 2) {
- hval2 = 0.f;
- }
- else if (j == m - 1) {
- hval1 = 0.f;
- hval2 = 0.f;
- }
-
- for (i = 0; i < n; i++) {
- mlib_d64 dval0 = val0 * hval0 + dval;
- mlib_d64 val2 = src2[i * nch];
-
- dval = dst1[i];
- dval0 += val1 * hval1;
- dval0 += val2 * hval2;
- val0 = val1;
- val1 = val2;
-
- dst[i] = dval0;
- }
- }
-}
-
-/***************************************************************/
-void mlib_ImageConvMxNMedian_S32(mlib_s32 *dst,
- mlib_d64 *src,
- mlib_s32 n,
- mlib_s32 nch)
-{
- mlib_s32 i;
-
- for (i = 0; i < n; i++) {
- mlib_s32 res;
-
- CLAMP_S32(res, src[i]);
- src[i] = 0.5;
- dst[i * nch] = res;
- }
-}
-
-/***************************************************************/
-void mlib_ImageConvMxNS322S32_ext(mlib_s32 *dst,
- const mlib_s32 *src,
- mlib_s32 n,
- mlib_s32 nch,
- mlib_s32 dx_l,
- mlib_s32 dx_r)
-{
- mlib_s32 i;
- mlib_d64 val = src[0];
-
- for (i = 0; i < dx_l; i++)
- dst[i] = (mlib_s32) val;
- for (; i < n - dx_r; i++)
- dst[i] = src[nch * (i - dx_l)];
- val = dst[n - dx_r - 1];
- for (; i < n; i++)
- dst[i] = (mlib_s32) val;
-}
-
-/***************************************************************/
-mlib_status mlib_convMxNext_s32(mlib_image *dst,
- const mlib_image *src,
- const mlib_s32 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 scale,
- mlib_s32 cmask)
-{
- mlib_d64 dspace[1024], *dsa = dspace;
- mlib_d64 akernel[256], *dkernel = akernel, fscale = 1.0;
- mlib_s32 wid_e = mlib_ImageGetWidth(src);
- mlib_d64 *dsh, *dsv;
- mlib_s32 *isa;
- mlib_s32 *da = mlib_ImageGetData(dst);
- mlib_s32 *sa = mlib_ImageGetData(src);
- mlib_s32 dlb = mlib_ImageGetStride(dst) >> 2;
- mlib_s32 slb = mlib_ImageGetStride(src) >> 2;
- mlib_s32 dw = mlib_ImageGetWidth(dst);
- mlib_s32 dh = mlib_ImageGetHeight(dst);
- mlib_s32 nch = mlib_ImageGetChannels(dst);
- mlib_s32 i, j, j1, k, mn;
-
- /* internal buffer */
-
- if (!SAFE_TO_MULT(3, wid_e) || !SAFE_TO_ADD(3 * wid_e, m)) {
- return MLIB_FAILURE;
- }
- if (3 * wid_e + m > 1024) {
- dsa = mlib_malloc((3 * wid_e + m) * sizeof(mlib_d64));
-
- if (dsa == NULL)
- return MLIB_FAILURE;
- }
-
- isa = (mlib_s32 *) dsa;
-
- /* load kernel */
- mn = m * n;
-
- if (mn > 256) {
- dkernel = mlib_malloc(mn * sizeof(mlib_d64));
-
- if (dkernel == NULL) {
- if (dsa != dspace) mlib_free(dsa);
- return MLIB_FAILURE;
- }
- }
-
- while (scale > 30) {
- fscale /= (1 << 30);
- scale -= 30;
- }
-
- fscale /= (1 << scale);
-
- for (i = 0; i < mn; i++) {
- dkernel[i] = ((mlib_s32 *) kernel)[i] * fscale;
- }
-
- dsh = dsa + dw + m;
- dsv = dsh + dw;
-
- for (i = 0; i < dw; i++) {
- dsh[i] = 0.5;
- dsv[i] = 0.5;
- }
-
- for (j = 0; j < dh; j++, da += dlb) {
- for (k = 0; k < nch; k++)
- if (cmask & (1 << (nch - 1 - k))) {
- mlib_s32 *sa1 = sa + k;
- mlib_d64 *dkernel1 = dkernel;
-
- for (j1 = 0; j1 < n; j1++, dkernel1 += m) {
- mlib_ImageConvMxNS322S32_ext(isa, sa1, dw + m - 1, nch, dx_l, dx_r);
- mlib_ImageConvMxNMulAdd_S32(dsh, isa, dkernel1, dw, m, 1);
-
- if ((j + j1 >= dy_t) && (j + j1 < dh + n - dy_b - 2))
- sa1 += slb;
- }
-
- mlib_ImageConvMxNMedian_S32(da + k, dsh, dw, nch);
- }
-
- if ((j >= dy_t) && (j < dh + n - dy_b - 2))
- sa += slb;
- }
-
- if (dkernel != akernel)
- mlib_free(dkernel);
- if (dsa != dspace)
- mlib_free(dsa);
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16ext.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16ext.c
deleted file mode 100644
index 00469d25719..00000000000
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_16ext.c
+++ /dev/null
@@ -1,1340 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-
-/*
- * FUNCTION
- * Internal functions for mlib_ImageConv* on U8/S16/U16 type and
- * MLIB_EDGE_SRC_EXTEND mask
- */
-
-#include "mlib_image.h"
-#include "mlib_ImageConv.h"
-#include "mlib_c_ImageConv.h"
-#include "safe_math.h"
-
-/*
- * This define switches between functions of different data types
- */
-
-#define IMG_TYPE 2
-
-/***************************************************************/
-#if IMG_TYPE == 1
-
-#define DTYPE mlib_u8
-#define CONV_FUNC(KERN) mlib_c_conv##KERN##ext_u8(PARAM)
-#define CONV_FUNC_MxN mlib_c_convMxNext_u8(PARAM_MxN)
-#define CONV_FUNC_I(KERN) mlib_i_conv##KERN##ext_u8(PARAM)
-#define CONV_FUNC_MxN_I mlib_i_convMxNext_u8(PARAM_MxN)
-#define DSCALE (1 << 24)
-#define FROM_S32(x) (((x) >> 24) ^ 128)
-#define S64TOS32(x) (x)
-#define SAT_OFF -(1u << 31)
-
-#elif IMG_TYPE == 2
-
-#define DTYPE mlib_s16
-#define CONV_FUNC(KERN) mlib_conv##KERN##ext_s16(PARAM)
-#define CONV_FUNC_MxN mlib_convMxNext_s16(PARAM_MxN)
-#define CONV_FUNC_I(KERN) mlib_i_conv##KERN##ext_s16(PARAM)
-#define CONV_FUNC_MxN_I mlib_i_convMxNext_s16(PARAM_MxN)
-#define DSCALE 65536.0
-#define FROM_S32(x) ((x) >> 16)
-#define S64TOS32(x) ((x) & 0xffffffff)
-#define SAT_OFF
-
-#elif IMG_TYPE == 3
-
-#define DTYPE mlib_u16
-#define CONV_FUNC(KERN) mlib_conv##KERN##ext_u16(PARAM)
-#define CONV_FUNC_MxN mlib_convMxNext_u16(PARAM_MxN)
-#define CONV_FUNC_I(KERN) mlib_i_conv##KERN##ext_u16(PARAM)
-#define CONV_FUNC_MxN_I mlib_i_convMxNext_u16(PARAM_MxN)
-#define DSCALE 65536.0
-#define FROM_S32(x) (((x) >> 16) ^ 0x8000)
-#define S64TOS32(x) (x)
-#define SAT_OFF -(1u << 31)
-
-#endif /* IMG_TYPE == 1 */
-
-/***************************************************************/
-#define PARAM \
- mlib_image *dst, \
- const mlib_image *src, \
- mlib_s32 dx_l, \
- mlib_s32 dx_r, \
- mlib_s32 dy_t, \
- mlib_s32 dy_b, \
- const mlib_s32 *kern, \
- mlib_s32 scalef_expon, \
- mlib_s32 cmask
-
-/***************************************************************/
-#define PARAM_MxN \
- mlib_image *dst, \
- const mlib_image *src, \
- const mlib_s32 *kernel, \
- mlib_s32 m, \
- mlib_s32 n, \
- mlib_s32 dx_l, \
- mlib_s32 dx_r, \
- mlib_s32 dy_t, \
- mlib_s32 dy_b, \
- mlib_s32 scale, \
- mlib_s32 cmask
-
-/***************************************************************/
-#define FTYPE mlib_d64
-
-#ifndef MLIB_USE_FTOI_CLAMPING
-
-#define CLAMP_S32(x) \
- (((x) <= MLIB_S32_MIN) ? MLIB_S32_MIN : (((x) >= MLIB_S32_MAX) ? MLIB_S32_MAX : (mlib_s32)(x)))
-
-#else
-
-#define CLAMP_S32(x) ((mlib_s32)(x))
-
-#endif /* MLIB_USE_FTOI_CLAMPING */
-
-/***************************************************************/
-#define D2I(x) CLAMP_S32((x) SAT_OFF)
-
-/***************************************************************/
-#ifdef _LITTLE_ENDIAN
-
-#define STORE2(res0, res1) \
- dp[0 ] = res1; \
- dp[chan1] = res0
-
-#else
-
-#define STORE2(res0, res1) \
- dp[0 ] = res0; \
- dp[chan1] = res1
-
-#endif /* _LITTLE_ENDIAN */
-
-/***************************************************************/
-#ifdef _NO_LONGLONG
-
-#define LOAD_BUFF(buff) \
- buff[i ] = sp[0]; \
- buff[i + 1] = sp[chan1]
-
-#else /* _NO_LONGLONG */
-
-#ifdef _LITTLE_ENDIAN
-
-#define LOAD_BUFF(buff) \
- *(mlib_s64*)(buff + i) = (((mlib_s64)sp[chan1]) << 32) | S64TOS32((mlib_s64)sp[0])
-
-#else /* _LITTLE_ENDIAN */
-
-#define LOAD_BUFF(buff) \
- *(mlib_s64*)(buff + i) = (((mlib_s64)sp[0]) << 32) | S64TOS32((mlib_s64)sp[chan1])
-
-#endif /* _LITTLE_ENDIAN */
-#endif /* _NO_LONGLONG */
-
-/***************************************************************/
-typedef union {
- mlib_d64 d64;
- struct {
- mlib_s32 i0;
- mlib_s32 i1;
- } i32s;
-} d64_2x32;
-
-/***************************************************************/
-#define GET_SRC_DST_PARAMETERS(type) \
- hgt = mlib_ImageGetHeight(src); \
- wid = mlib_ImageGetWidth(src); \
- nchannel = mlib_ImageGetChannels(src); \
- sll = mlib_ImageGetStride(src) / sizeof(type); \
- dll = mlib_ImageGetStride(dst) / sizeof(type); \
- adr_src = (type *)mlib_ImageGetData(src); \
- adr_dst = (type *)mlib_ImageGetData(dst)
-
-/***************************************************************/
-#if IMG_TYPE == 1
-
-/*
- * Test for the presence of any "1" bit in bits
- 8 to 31 of val. If present, then val is either
- negative or >255. If over/underflows of 8 bits
- are uncommon, then this technique can be a win,
- since only a single test, rather than two, is
- necessary to determine if clamping is needed.
- On the other hand, if over/underflows are common,
- it adds an extra test.
-*/
-#define CLAMP_STORE(dst, val) \
- if (val & 0xffffff00) { \
- if (val < MLIB_U8_MIN) \
- dst = MLIB_U8_MIN; \
- else \
- dst = MLIB_U8_MAX; \
- } else { \
- dst = (mlib_u8)val; \
- }
-
-#elif IMG_TYPE == 2
-
-#define CLAMP_STORE(dst, val) \
- if (val >= MLIB_S16_MAX) \
- dst = MLIB_S16_MAX; \
- else if (val <= MLIB_S16_MIN) \
- dst = MLIB_S16_MIN; \
- else \
- dst = (mlib_s16)val
-
-#elif IMG_TYPE == 3
-
-#define CLAMP_STORE(dst, val) \
- if (val >= MLIB_U16_MAX) \
- dst = MLIB_U16_MAX; \
- else if (val <= MLIB_U16_MIN) \
- dst = MLIB_U16_MIN; \
- else \
- dst = (mlib_u16)val
-
-#endif /* IMG_TYPE == 1 */
-
-/***************************************************************/
-#define MAX_KER 7
-#define MAX_N 15
-#define BUFF_SIZE 1600
-#define CACHE_SIZE (64*1024)
-
-static mlib_status mlib_ImageConv1xN_ext(mlib_image *dst,
- const mlib_image *src,
- const mlib_d64 *k,
- mlib_s32 n,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask)
-{
- DTYPE *adr_src, *sl;
- DTYPE *adr_dst, *dl, *dp;
- FTYPE buff[BUFF_SIZE];
- FTYPE *buffd;
- FTYPE *pbuff = buff;
- const FTYPE *pk;
- FTYPE k0, k1, k2, k3;
- FTYPE p0, p1, p2, p3, p4;
- FTYPE *sbuff;
- mlib_s32 l, k_off, off, bsize;
- mlib_s32 max_hsize, smax_hsize, shgt, hsize, kh;
- mlib_s32 d0, d1, ii;
- mlib_s32 wid, hgt, sll, dll;
- mlib_s32 nchannel;
- mlib_s32 i, j, c;
- GET_SRC_DST_PARAMETERS(DTYPE);
-
- max_hsize = ((CACHE_SIZE/sizeof(DTYPE))/sll) - (n - 1);
-
- if (max_hsize < 1) max_hsize = 1;
- if (max_hsize > hgt) max_hsize = hgt;
-
- shgt = hgt + (n - 1);
- if (!SAFE_TO_ADD(max_hsize, (n - 1))) {
- return MLIB_FAILURE;
- }
- smax_hsize = max_hsize + (n - 1);
-
- if (!SAFE_TO_ADD(smax_hsize, 1) || !SAFE_TO_MULT(2, (smax_hsize + 1))) {
- return MLIB_FAILURE;
- }
- bsize = 2 * (smax_hsize + 1);
-
- if (bsize > BUFF_SIZE) {
- pbuff = mlib_malloc(sizeof(FTYPE)*bsize);
-
- if (pbuff == NULL) return MLIB_FAILURE;
- }
-
- sbuff = pbuff;
- buffd = sbuff + smax_hsize;
-
- shgt -= (dy_t + dy_b);
- k_off = 0;
-
- for (l = 0; l < hgt; l += hsize) {
- hsize = hgt - l;
-
- if (hsize > max_hsize) hsize = max_hsize;
-
- smax_hsize = hsize + (n - 1);
-
- for (c = 0; c < nchannel; c++) {
- if (!(cmask & (1 << (nchannel - 1 - c)))) continue;
-
- sl = adr_src + c;
- dl = adr_dst + c;
-
- for (i = 0; i < hsize; i++) buffd[i] = 0.0;
-
- for (j = 0; j < wid; j++) {
- FTYPE *buff = sbuff;
-
- for (i = k_off, ii = 0; (i < dy_t) && (ii < smax_hsize); i++, ii++) {
- sbuff[i - k_off] = (FTYPE)sl[0];
- }
-
- for (; (i < shgt + dy_t) && (ii < smax_hsize); i++, ii++) {
- sbuff[i - k_off] = (FTYPE)sl[(i - dy_t)*sll];
- }
-
- for (; (i < shgt + dy_t + dy_b) && (ii < smax_hsize); i++, ii++) {
- sbuff[i - k_off] = (FTYPE)sl[(shgt - 1)*sll];
- }
-
- pk = k;
-
- for (off = 0; off < (n - 4); off += 4) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- for (i = 0; i < hsize; i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3;
- }
-
- pk += 4;
- buff += 4;
- }
-
- dp = dl;
- kh = n - off;
-
- if (kh == 4) {
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = p2; p1 = p3; p2 = p4;
- p3 = buff[i + 3];
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i]);
- dp[0] = FROM_S32(d0);
- buffd[i] = 0.0;
- }
-
- } else if (kh == 3) {
-
- p2 = buff[0]; p3 = buff[1];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = p2; p1 = p3;
- p2 = buff[i + 2];
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + buffd[i]);
- dp[0] = FROM_S32(d0);
-
- buffd[i] = 0.0;
- }
-
- } else if (kh == 2) {
-
- p2 = buff[0];
- k0 = pk[0]; k1 = pk[1];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- d0 = D2I(p0*k0 + p1*k1 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = p2;
- p1 = buff[i + 1];
- d0 = D2I(p0*k0 + p1*k1 + buffd[i]);
- dp[0] = FROM_S32(d0);
-
- buffd[i] = 0.0;
- }
-
- } else /* kh == 1 */{
-
- k0 = pk[0];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = buff[i]; p1 = buff[i + 1];
-
- d0 = D2I(p0*k0 + buffd[i ]);
- d1 = D2I(p1*k0 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = buff[i];
- d0 = D2I(p0*k0 + buffd[i]);
- dp[0] = FROM_S32(d0);
-
- buffd[i] = 0.0;
- }
- }
-
- /* next line */
- sl += nchannel;
- dl += nchannel;
- }
- }
-
- k_off += max_hsize;
- adr_dst += max_hsize*dll;
- }
-
- if (pbuff != buff) mlib_free(pbuff);
-
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
-mlib_status CONV_FUNC_MxN
-{
- DTYPE *adr_src, *sl, *sp = NULL;
- DTYPE *adr_dst, *dl, *dp = NULL;
- FTYPE buff[BUFF_SIZE], *buffs_arr[2*(MAX_N + 1)];
- FTYPE **buffs = buffs_arr, *buffd;
- FTYPE akernel[256], *k = akernel, fscale = DSCALE;
- FTYPE *pbuff = buff;
- FTYPE k0, k1, k2, k3, k4, k5, k6;
- FTYPE p0, p1, p2, p3, p4, p5, p6, p7;
- mlib_s32 *buffi;
- mlib_s32 mn, l, off, kw, bsize, buff_ind;
- mlib_s32 d0, d1;
- mlib_s32 wid, hgt, sll, dll;
- mlib_s32 nchannel, chan1, chan2;
- mlib_s32 i, j, c, swid;
- d64_2x32 dd;
- mlib_status status = MLIB_SUCCESS;
-
- GET_SRC_DST_PARAMETERS(DTYPE);
-
- if (scale > 30) {
- fscale *= 1.0/(1 << 30);
- scale -= 30;
- }
-
- fscale /= (1 << scale);
-
- mn = m*n;
-
- if (mn > 256) {
- k = mlib_malloc(mn*sizeof(mlib_d64));
-
- if (k == NULL) return MLIB_FAILURE;
- }
-
- for (i = 0; i < mn; i++) {
- k[i] = kernel[i]*fscale;
- }
-
- if (m == 1) {
- status = mlib_ImageConv1xN_ext(dst, src, k, n, dy_t, dy_b, cmask);
- FREE_AND_RETURN_STATUS;
- }
-
- if (!SAFE_TO_ADD(wid, (m - 1))) {
- status = MLIB_FAILURE;
- FREE_AND_RETURN_STATUS;
- }
- swid = wid + (m - 1);
-
- if (!SAFE_TO_MULT((n + 3), swid)) {
- status = MLIB_FAILURE;
- FREE_AND_RETURN_STATUS;
- }
- bsize = (n + 3)*swid;
-
- if ((bsize > BUFF_SIZE) || (n > MAX_N)) {
- pbuff = mlib_malloc(sizeof(FTYPE)*bsize + sizeof(FTYPE *)*2*(n + 1));
-
- if (pbuff == NULL) {
- status = MLIB_FAILURE;
- FREE_AND_RETURN_STATUS;
- }
- buffs = (FTYPE **)(pbuff + bsize);
- }
-
- for (l = 0; l < (n + 1); l++) buffs[l] = pbuff + l*swid;
- for (l = 0; l < (n + 1); l++) buffs[l + (n + 1)] = buffs[l];
- buffd = buffs[n] + swid;
- buffi = (mlib_s32*)(buffd + swid);
-
- chan1 = nchannel;
- chan2 = chan1 + chan1;
-
- swid -= (dx_l + dx_r);
-
- for (c = 0; c < nchannel; c++) {
- if (!(cmask & (1 << (chan1 - 1 - c)))) continue;
-
- sl = adr_src + c;
- dl = adr_dst + c;
-
- for (l = 0; l < n; l++) {
- FTYPE *buff = buffs[l];
-
- for (i = 0; i < dx_l; i++) {
- buff[i] = (FTYPE)sl[0];
- }
-
- for (i = 0; i < swid; i++) {
- buff[i + dx_l] = (FTYPE)sl[i*chan1];
- }
-
- for (i = 0; i < dx_r; i++) {
- buff[swid + dx_l + i] = buff[swid + dx_l - 1];
- }
-
- if ((l >= dy_t) && (l < hgt + n - dy_b - 2)) sl += sll;
- }
-
- buff_ind = 0;
-
- for (i = 0; i < wid; i++) buffd[i] = 0.0;
-
- for (j = 0; j < hgt; j++) {
- FTYPE **buffc = buffs + buff_ind;
- FTYPE *buffn = buffc[n];
- FTYPE *pk = k;
-
- for (l = 0; l < n; l++) {
- FTYPE *buff_l = buffc[l];
-
- for (off = 0; off < m;) {
- FTYPE *buff = buff_l + off;
-
- kw = m - off;
-
- if (kw > 2*MAX_KER) kw = MAX_KER; else
- if (kw > MAX_KER) kw = kw/2;
- off += kw;
-
- sp = sl;
- dp = dl;
-
- if (kw == 7) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4]; p7 = buff[5];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5]; k6 = pk[6];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 6) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 5) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 4) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 3) {
-
- p2 = buff[0]; p3 = buff[1];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else /* if (kw == 2) */ {
-
- p2 = buff[0];
- k0 = pk[0]; k1 = pk[1];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- buffd[i ] += p0*k0 + p1*k1;
- buffd[i + 1] += p1*k0 + p2*k1;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
- }
-
- pk += kw;
- }
- }
-
- /* last pixels */
- for (; i < wid; i++) {
- FTYPE *pk = k, s = 0;
- mlib_s32 x, d0;
-
- for (l = 0; l < n; l++) {
- FTYPE *buff = buffc[l] + i;
-
- for (x = 0; x < m; x++) s += buff[x] * (*pk++);
- }
-
- d0 = D2I(s);
- dp[0] = FROM_S32(d0);
-
- buffn[i + dx_l] = (FTYPE)sp[0];
-
- sp += chan1;
- dp += chan1;
- }
-
- for (; i < swid; i++) {
- buffn[i + dx_l] = (FTYPE)sp[0];
- sp += chan1;
- }
-
- for (i = 0; i < dx_l; i++) buffn[i] = buffn[dx_l];
- for (i = 0; i < dx_r; i++) buffn[swid + dx_l + i] = buffn[swid + dx_l - 1];
-
- /* next line */
-
- if (j < hgt - dy_b - 2) sl += sll;
- dl += dll;
-
- buff_ind++;
-
- if (buff_ind >= n + 1) buff_ind = 0;
- }
- }
-
- FREE_AND_RETURN_STATUS;
-}
-
-/***************************************************************/
-/* for x86, using integer multiplies is faster */
-
-#define STORE_RES(res, x) \
- x >>= shift2; \
- CLAMP_STORE(res, x)
-
-mlib_status CONV_FUNC_MxN_I
-{
- DTYPE *adr_src, *sl, *sp = NULL;
- DTYPE *adr_dst, *dl, *dp = NULL;
- mlib_s32 buff[BUFF_SIZE], *buffs_arr[2*(MAX_N + 1)];
- mlib_s32 *pbuff = buff;
- mlib_s32 **buffs = buffs_arr, *buffd;
- mlib_s32 l, off, kw, bsize, buff_ind;
- mlib_s32 d0, d1, shift1, shift2;
- mlib_s32 k0, k1, k2, k3, k4, k5, k6;
- mlib_s32 p0, p1, p2, p3, p4, p5, p6, p7;
- mlib_s32 wid, hgt, sll, dll;
- mlib_s32 nchannel, chan1;
- mlib_s32 i, j, c, swid;
- mlib_s32 chan2;
- mlib_s32 k_locl[MAX_N*MAX_N], *k = k_locl;
- GET_SRC_DST_PARAMETERS(DTYPE);
-
-#if IMG_TYPE != 1
- shift1 = 16;
-#else
- shift1 = 8;
-#endif /* IMG_TYPE != 1 */
- shift2 = scale - shift1;
-
- chan1 = nchannel;
- chan2 = chan1 + chan1;
-
- if (!SAFE_TO_ADD(wid, (m - 1))) {
- return MLIB_FAILURE;
- }
- swid = wid + (m - 1);
-
- if (!SAFE_TO_MULT((n + 2), swid)) {
- return MLIB_FAILURE;
- }
- bsize = (n + 2)*swid;
-
- if ((bsize > BUFF_SIZE) || (n > MAX_N)) {
- pbuff = mlib_malloc(sizeof(mlib_s32)*bsize + sizeof(mlib_s32 *)*2*(n + 1));
-
- if (pbuff == NULL) return MLIB_FAILURE;
- buffs = (mlib_s32 **)(pbuff + bsize);
- }
-
- for (l = 0; l < (n + 1); l++) buffs[l] = pbuff + l*swid;
- for (l = 0; l < (n + 1); l++) buffs[l + (n + 1)] = buffs[l];
- buffd = buffs[n] + swid;
-
- if (m*n > MAX_N*MAX_N) {
- k = mlib_malloc(sizeof(mlib_s32)*(m*n));
-
- if (k == NULL) {
- if (pbuff != buff) mlib_free(pbuff);
- return MLIB_FAILURE;
- }
- }
-
- for (i = 0; i < m*n; i++) {
- k[i] = kernel[i] >> shift1;
- }
-
- swid -= (dx_l + dx_r);
-
- for (c = 0; c < nchannel; c++) {
- if (!(cmask & (1 << (nchannel - 1 - c)))) continue;
-
- sl = adr_src + c;
- dl = adr_dst + c;
-
- for (l = 0; l < n; l++) {
- mlib_s32 *buff = buffs[l];
-
- for (i = 0; i < dx_l; i++) {
- buff[i] = (mlib_s32)sl[0];
- }
-
- for (i = 0; i < swid; i++) {
- buff[i + dx_l] = (mlib_s32)sl[i*chan1];
- }
-
- for (i = 0; i < dx_r; i++) {
- buff[swid + dx_l + i] = buff[swid + dx_l - 1];
- }
-
- if ((l >= dy_t) && (l < hgt + n - dy_b - 2)) sl += sll;
- }
-
- buff_ind = 0;
-
- for (i = 0; i < wid; i++) buffd[i] = 0;
-
- for (j = 0; j < hgt; j++) {
- mlib_s32 **buffc = buffs + buff_ind;
- mlib_s32 *buffn = buffc[n];
- mlib_s32 *pk = k;
-
- for (l = 0; l < n; l++) {
- mlib_s32 *buff_l = buffc[l];
-
- for (off = 0; off < m;) {
- mlib_s32 *buff = buff_l + off;
-
- sp = sl;
- dp = dl;
-
- kw = m - off;
-
- if (kw > 2*MAX_KER) kw = MAX_KER; else
- if (kw > MAX_KER) kw = kw/2;
- off += kw;
-
- if (kw == 7) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4]; p7 = buff[5];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5]; k6 = pk[6];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 6) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 5) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 4) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 3) {
-
- p2 = buff[0]; p3 = buff[1];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 2) {
-
- p2 = buff[0];
- k0 = pk[0]; k1 = pk[1];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- buffd[i ] += p0*k0 + p1*k1;
- buffd[i + 1] += p1*k0 + p2*k1;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else /* kw == 1 */{
-
- k0 = pk[0];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = buff[i]; p1 = buff[i + 1];
-
- buffd[i ] += p0*k0;
- buffd[i + 1] += p1*k0;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = buff[i]; p1 = buff[i + 1];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + buffd[i ]);
- d1 = (p1*k0 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
- }
-
- pk += kw;
- }
- }
-
- /* last pixels */
- for (; i < wid; i++) {
- mlib_s32 *pk = k, x, s = 0;
-
- for (l = 0; l < n; l++) {
- mlib_s32 *buff = buffc[l] + i;
-
- for (x = 0; x < m; x++) s += buff[x] * (*pk++);
- }
-
- STORE_RES(dp[0], s);
-
- buffn[i + dx_l] = (mlib_s32)sp[0];
-
- sp += chan1;
- dp += chan1;
- }
-
- for (; i < swid; i++) {
- buffn[i + dx_l] = (mlib_s32)sp[0];
- sp += chan1;
- }
-
- for (i = 0; i < dx_l; i++) buffn[i] = buffn[dx_l];
- for (i = 0; i < dx_r; i++) buffn[swid + dx_l + i] = buffn[swid + dx_l - 1];
-
- /* next line */
-
- if (j < hgt - dy_b - 2) sl += sll;
- dl += dll;
-
- buff_ind++;
-
- if (buff_ind >= n + 1) buff_ind = 0;
- }
- }
-
- if (pbuff != buff) mlib_free(pbuff);
- if (k != k_locl) mlib_free(k);
-
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8ext.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8ext.c
deleted file mode 100644
index 136d5a2b814..00000000000
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_8ext.c
+++ /dev/null
@@ -1,1325 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-
-/*
- * FUNCTION
- * Internal functions for mlib_ImageConv* on U8/S16/U16 type and
- * MLIB_EDGE_SRC_EXTEND mask
- */
-
-#include "mlib_image.h"
-#include "mlib_ImageConv.h"
-#include "mlib_c_ImageConv.h"
-#include "safe_math.h"
-
-/*
- * This define switches between functions of different data types
- */
-
-#define IMG_TYPE 1
-
-/***************************************************************/
-#if IMG_TYPE == 1
-
-#define DTYPE mlib_u8
-#define CONV_FUNC(KERN) mlib_c_conv##KERN##ext_u8(PARAM)
-#define CONV_FUNC_MxN mlib_c_convMxNext_u8(PARAM_MxN)
-#define CONV_FUNC_I(KERN) mlib_i_conv##KERN##ext_u8(PARAM)
-#define CONV_FUNC_MxN_I mlib_i_convMxNext_u8(PARAM_MxN)
-#define DSCALE (1 << 24)
-#define FROM_S32(x) (((x) >> 24) ^ 128)
-#define S64TOS32(x) (x)
-#define SAT_OFF -(1u << 31)
-
-#elif IMG_TYPE == 2
-
-#define DTYPE mlib_s16
-#define CONV_FUNC(KERN) mlib_conv##KERN##ext_s16(PARAM)
-#define CONV_FUNC_MxN mlib_convMxNext_s16(PARAM_MxN)
-#define CONV_FUNC_I(KERN) mlib_i_conv##KERN##ext_s16(PARAM)
-#define CONV_FUNC_MxN_I mlib_i_convMxNext_s16(PARAM_MxN)
-#define DSCALE 65536.0
-#define FROM_S32(x) ((x) >> 16)
-#define S64TOS32(x) ((x) & 0xffffffff)
-#define SAT_OFF
-
-#elif IMG_TYPE == 3
-
-#define DTYPE mlib_u16
-#define CONV_FUNC(KERN) mlib_conv##KERN##ext_u16(PARAM)
-#define CONV_FUNC_MxN mlib_convMxNext_u16(PARAM_MxN)
-#define CONV_FUNC_I(KERN) mlib_i_conv##KERN##ext_u16(PARAM)
-#define CONV_FUNC_MxN_I mlib_i_convMxNext_u16(PARAM_MxN)
-#define DSCALE 65536.0
-#define FROM_S32(x) (((x) >> 16) ^ 0x8000)
-#define S64TOS32(x) (x)
-#define SAT_OFF -(1u << 31)
-
-#endif /* IMG_TYPE == 1 */
-
-/***************************************************************/
-#define PARAM \
- mlib_image *dst, \
- const mlib_image *src, \
- mlib_s32 dx_l, \
- mlib_s32 dx_r, \
- mlib_s32 dy_t, \
- mlib_s32 dy_b, \
- const mlib_s32 *kern, \
- mlib_s32 scalef_expon, \
- mlib_s32 cmask
-
-/***************************************************************/
-#define PARAM_MxN \
- mlib_image *dst, \
- const mlib_image *src, \
- const mlib_s32 *kernel, \
- mlib_s32 m, \
- mlib_s32 n, \
- mlib_s32 dx_l, \
- mlib_s32 dx_r, \
- mlib_s32 dy_t, \
- mlib_s32 dy_b, \
- mlib_s32 scale, \
- mlib_s32 cmask
-
-/***************************************************************/
-#define FTYPE mlib_d64
-
-#ifndef MLIB_USE_FTOI_CLAMPING
-
-#define CLAMP_S32(x) \
- (((x) <= MLIB_S32_MIN) ? MLIB_S32_MIN : (((x) >= MLIB_S32_MAX) ? MLIB_S32_MAX : (mlib_s32)(x)))
-
-#else
-
-#define CLAMP_S32(x) ((mlib_s32)(x))
-
-#endif /* MLIB_USE_FTOI_CLAMPING */
-
-/***************************************************************/
-#define D2I(x) CLAMP_S32((x) SAT_OFF)
-
-/***************************************************************/
-#ifdef _NO_LONGLONG
-
-#define LOAD_BUFF(buff) \
- buff[i ] = sp[0]; \
- buff[i + 1] = sp[chan1]
-
-#else /* _NO_LONGLONG */
-
-#ifdef _LITTLE_ENDIAN
-
-#define LOAD_BUFF(buff) \
- *(mlib_s64*)(buff + i) = (((mlib_s64)sp[chan1]) << 32) | S64TOS32((mlib_s64)sp[0])
-
-#else /* _LITTLE_ENDIAN */
-
-#define LOAD_BUFF(buff) \
- *(mlib_s64*)(buff + i) = (((mlib_s64)sp[0]) << 32) | S64TOS32((mlib_s64)sp[chan1])
-
-#endif /* _LITTLE_ENDIAN */
-#endif /* _NO_LONGLONG */
-
-/***************************************************************/
-typedef union {
- mlib_d64 d64;
- struct {
- mlib_s32 i0;
- mlib_s32 i1;
- } i32s;
-} d64_2x32;
-
-/***************************************************************/
-#define GET_SRC_DST_PARAMETERS(type) \
- hgt = mlib_ImageGetHeight(src); \
- wid = mlib_ImageGetWidth(src); \
- nchannel = mlib_ImageGetChannels(src); \
- sll = mlib_ImageGetStride(src) / sizeof(type); \
- dll = mlib_ImageGetStride(dst) / sizeof(type); \
- adr_src = (type *)mlib_ImageGetData(src); \
- adr_dst = (type *)mlib_ImageGetData(dst)
-
-/***************************************************************/
-#if IMG_TYPE == 1
-
-/*
- * Test for the presence of any "1" bit in bits
- 8 to 31 of val. If present, then val is either
- negative or >255. If over/underflows of 8 bits
- are uncommon, then this technique can be a win,
- since only a single test, rather than two, is
- necessary to determine if clamping is needed.
- On the other hand, if over/underflows are common,
- it adds an extra test.
-*/
-#define CLAMP_STORE(dst, val) \
- if (val & 0xffffff00) { \
- if (val < MLIB_U8_MIN) \
- dst = MLIB_U8_MIN; \
- else \
- dst = MLIB_U8_MAX; \
- } else { \
- dst = (mlib_u8)val; \
- }
-
-#elif IMG_TYPE == 2
-
-#define CLAMP_STORE(dst, val) \
- if (val >= MLIB_S16_MAX) \
- dst = MLIB_S16_MAX; \
- else if (val <= MLIB_S16_MIN) \
- dst = MLIB_S16_MIN; \
- else \
- dst = (mlib_s16)val
-
-#elif IMG_TYPE == 3
-
-#define CLAMP_STORE(dst, val) \
- if (val >= MLIB_U16_MAX) \
- dst = MLIB_U16_MAX; \
- else if (val <= MLIB_U16_MIN) \
- dst = MLIB_U16_MIN; \
- else \
- dst = (mlib_u16)val
-
-#endif /* IMG_TYPE == 1 */
-
-/***************************************************************/
-#define MAX_KER 7
-#define MAX_N 15
-#define BUFF_SIZE 1600
-#define CACHE_SIZE (64*1024)
-
-static mlib_status mlib_ImageConv1xN_ext(mlib_image *dst,
- const mlib_image *src,
- const mlib_d64 *k,
- mlib_s32 n,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask)
-{
- DTYPE *adr_src, *sl;
- DTYPE *adr_dst, *dl, *dp;
- FTYPE buff[BUFF_SIZE];
- FTYPE *buffd;
- FTYPE *pbuff = buff;
- const FTYPE *pk;
- FTYPE k0, k1, k2, k3;
- FTYPE p0, p1, p2, p3, p4;
- FTYPE *sbuff;
- mlib_s32 l, k_off, off, bsize;
- mlib_s32 max_hsize, smax_hsize, shgt, hsize, kh;
- mlib_s32 d0, d1, ii;
- mlib_s32 wid, hgt, sll, dll;
- mlib_s32 nchannel;
- mlib_s32 i, j, c;
- GET_SRC_DST_PARAMETERS(DTYPE);
-
- max_hsize = ((CACHE_SIZE/sizeof(DTYPE))/sll) - (n - 1);
-
- if (max_hsize < 1) max_hsize = 1;
- if (max_hsize > hgt) max_hsize = hgt;
-
- shgt = hgt + (n - 1);
- if (!SAFE_TO_ADD(max_hsize, (n - 1))) {
- return MLIB_FAILURE;
- }
- smax_hsize = max_hsize + (n - 1);
-
- if (!SAFE_TO_ADD(smax_hsize, 1) || !SAFE_TO_MULT(2, (smax_hsize + 1))) {
- return MLIB_FAILURE;
- }
- bsize = 2 * (smax_hsize + 1);
-
- if (bsize > BUFF_SIZE) {
- pbuff = mlib_malloc(sizeof(FTYPE)*bsize);
-
- if (pbuff == NULL) return MLIB_FAILURE;
- }
-
- sbuff = pbuff;
- buffd = sbuff + smax_hsize;
-
- shgt -= (dy_t + dy_b);
- k_off = 0;
-
- for (l = 0; l < hgt; l += hsize) {
- hsize = hgt - l;
-
- if (hsize > max_hsize) hsize = max_hsize;
-
- smax_hsize = hsize + (n - 1);
-
- for (c = 0; c < nchannel; c++) {
- if (!(cmask & (1 << (nchannel - 1 - c)))) continue;
-
- sl = adr_src + c;
- dl = adr_dst + c;
-
- for (i = 0; i < hsize; i++) buffd[i] = 0.0;
-
- for (j = 0; j < wid; j++) {
- FTYPE *buff = sbuff;
-
- for (i = k_off, ii = 0; (i < dy_t) && (ii < smax_hsize); i++, ii++) {
- sbuff[i - k_off] = (FTYPE)sl[0];
- }
-
- for (; (i < shgt + dy_t) && (ii < smax_hsize); i++, ii++) {
- sbuff[i - k_off] = (FTYPE)sl[(i - dy_t)*sll];
- }
-
- for (; (i < shgt + dy_t + dy_b) && (ii < smax_hsize); i++, ii++) {
- sbuff[i - k_off] = (FTYPE)sl[(shgt - 1)*sll];
- }
-
- pk = k;
-
- for (off = 0; off < (n - 4); off += 4) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- for (i = 0; i < hsize; i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3;
- }
-
- pk += 4;
- buff += 4;
- }
-
- dp = dl;
- kh = n - off;
-
- if (kh == 4) {
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = p2; p1 = p3; p2 = p4;
- p3 = buff[i + 3];
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i]);
- dp[0] = FROM_S32(d0);
- buffd[i] = 0.0;
- }
-
- } else if (kh == 3) {
-
- p2 = buff[0]; p3 = buff[1];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = p2; p1 = p3;
- p2 = buff[i + 2];
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + buffd[i]);
- dp[0] = FROM_S32(d0);
-
- buffd[i] = 0.0;
- }
-
- } else if (kh == 2) {
-
- p2 = buff[0];
- k0 = pk[0]; k1 = pk[1];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- d0 = D2I(p0*k0 + p1*k1 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = p2;
- p1 = buff[i + 1];
- d0 = D2I(p0*k0 + p1*k1 + buffd[i]);
- dp[0] = FROM_S32(d0);
-
- buffd[i] = 0.0;
- }
-
- } else /* kh == 1 */{
-
- k0 = pk[0];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = buff[i]; p1 = buff[i + 1];
-
- d0 = D2I(p0*k0 + buffd[i ]);
- d1 = D2I(p1*k0 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = buff[i];
- d0 = D2I(p0*k0 + buffd[i]);
- dp[0] = FROM_S32(d0);
-
- buffd[i] = 0.0;
- }
- }
-
- /* next line */
- sl += nchannel;
- dl += nchannel;
- }
- }
-
- k_off += max_hsize;
- adr_dst += max_hsize*dll;
- }
-
- if (pbuff != buff) mlib_free(pbuff);
-
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
-mlib_status CONV_FUNC_MxN
-{
- DTYPE *adr_src, *sl, *sp = NULL;
- DTYPE *adr_dst, *dl, *dp = NULL;
- FTYPE buff[BUFF_SIZE], *buffs_arr[2*(MAX_N + 1)];
- FTYPE **buffs = buffs_arr, *buffd;
- FTYPE akernel[256], *k = akernel, fscale = DSCALE;
- FTYPE *pbuff = buff;
- FTYPE k0, k1, k2, k3, k4, k5, k6;
- FTYPE p0, p1, p2, p3, p4, p5, p6, p7;
- mlib_s32 *buffi;
- mlib_s32 mn, l, off, kw, bsize, buff_ind;
- mlib_s32 d0, d1;
- mlib_s32 wid, hgt, sll, dll;
- mlib_s32 nchannel, chan1, chan2;
- mlib_s32 i, j, c, swid;
- d64_2x32 dd;
- mlib_status status = MLIB_SUCCESS;
-
- GET_SRC_DST_PARAMETERS(DTYPE);
-
- if (scale > 30) {
- fscale *= 1.0/(1 << 30);
- scale -= 30;
- }
-
- fscale /= (1 << scale);
-
- mn = m*n;
-
- if (mn > 256) {
- k = mlib_malloc(mn*sizeof(mlib_d64));
-
- if (k == NULL) return MLIB_FAILURE;
- }
-
- for (i = 0; i < mn; i++) {
- k[i] = kernel[i]*fscale;
- }
-
- if (m == 1) {
- status = mlib_ImageConv1xN_ext(dst, src, k, n, dy_t, dy_b, cmask);
- FREE_AND_RETURN_STATUS;
- }
-
- if (!SAFE_TO_ADD(wid, (m - 1))) {
- status = MLIB_FAILURE;
- FREE_AND_RETURN_STATUS;
- }
- swid = wid + (m - 1);
-
- if (!SAFE_TO_MULT((n + 3), swid)) {
- status = MLIB_FAILURE;
- FREE_AND_RETURN_STATUS;
- }
- bsize = (n + 3)*swid;
-
- if ((bsize > BUFF_SIZE) || (n > MAX_N)) {
- pbuff = mlib_malloc(sizeof(FTYPE)*bsize + sizeof(FTYPE *)*2*(n + 1));
-
- if (pbuff == NULL) {
- status = MLIB_FAILURE;
- FREE_AND_RETURN_STATUS;
- }
- buffs = (FTYPE **)(pbuff + bsize);
- }
-
- for (l = 0; l < (n + 1); l++) buffs[l] = pbuff + l*swid;
- for (l = 0; l < (n + 1); l++) buffs[l + (n + 1)] = buffs[l];
- buffd = buffs[n] + swid;
- buffi = (mlib_s32*)(buffd + swid);
-
- chan1 = nchannel;
- chan2 = chan1 + chan1;
-
- swid -= (dx_l + dx_r);
-
- for (c = 0; c < nchannel; c++) {
- if (!(cmask & (1 << (chan1 - 1 - c)))) continue;
-
- sl = adr_src + c;
- dl = adr_dst + c;
-
- for (l = 0; l < n; l++) {
- FTYPE *buff = buffs[l];
-
- for (i = 0; i < dx_l; i++) {
- buff[i] = (FTYPE)sl[0];
- }
-
- for (i = 0; i < swid; i++) {
- buff[i + dx_l] = (FTYPE)sl[i*chan1];
- }
-
- for (i = 0; i < dx_r; i++) {
- buff[swid + dx_l + i] = buff[swid + dx_l - 1];
- }
-
- if ((l >= dy_t) && (l < hgt + n - dy_b - 2)) sl += sll;
- }
-
- buff_ind = 0;
-
- for (i = 0; i < wid; i++) buffd[i] = 0.0;
-
- for (j = 0; j < hgt; j++) {
- FTYPE **buffc = buffs + buff_ind;
- FTYPE *buffn = buffc[n];
- FTYPE *pk = k;
-
- for (l = 0; l < n; l++) {
- FTYPE *buff_l = buffc[l];
-
- for (off = 0; off < m;) {
- FTYPE *buff = buff_l + off;
-
- kw = m - off;
-
- if (kw > 2*MAX_KER) kw = MAX_KER; else
- if (kw > MAX_KER) kw = kw/2;
- off += kw;
-
- sp = sl;
- dp = dl;
-
- if (kw == 7) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4]; p7 = buff[5];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5]; k6 = pk[6];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 6) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 5) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 4) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 3) {
-
- p2 = buff[0]; p3 = buff[1];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else /* if (kw == 2) */ {
-
- p2 = buff[0];
- k0 = pk[0]; k1 = pk[1];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- buffd[i ] += p0*k0 + p1*k1;
- buffd[i + 1] += p1*k0 + p2*k1;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
- }
-
- pk += kw;
- }
- }
-
- /* last pixels */
- for (; i < wid; i++) {
- FTYPE *pk = k, s = 0;
- mlib_s32 x, d0;
-
- for (l = 0; l < n; l++) {
- FTYPE *buff = buffc[l] + i;
-
- for (x = 0; x < m; x++) s += buff[x] * (*pk++);
- }
-
- d0 = D2I(s);
- dp[0] = FROM_S32(d0);
-
- buffn[i + dx_l] = (FTYPE)sp[0];
-
- sp += chan1;
- dp += chan1;
- }
-
- for (; i < swid; i++) {
- buffn[i + dx_l] = (FTYPE)sp[0];
- sp += chan1;
- }
-
- for (i = 0; i < dx_l; i++) buffn[i] = buffn[dx_l];
- for (i = 0; i < dx_r; i++) buffn[swid + dx_l + i] = buffn[swid + dx_l - 1];
-
- /* next line */
-
- if (j < hgt - dy_b - 2) sl += sll;
- dl += dll;
-
- buff_ind++;
-
- if (buff_ind >= n + 1) buff_ind = 0;
- }
- }
-
- FREE_AND_RETURN_STATUS;
-}
-
-/***************************************************************/
-/* for x86, using integer multiplies is faster */
-
-#define STORE_RES(res, x) \
- x >>= shift2; \
- CLAMP_STORE(res, x)
-
-mlib_status CONV_FUNC_MxN_I
-{
- DTYPE *adr_src, *sl, *sp = NULL;
- DTYPE *adr_dst, *dl, *dp = NULL;
- mlib_s32 buff[BUFF_SIZE], *buffs_arr[2*(MAX_N + 1)];
- mlib_s32 *pbuff = buff;
- mlib_s32 **buffs = buffs_arr, *buffd;
- mlib_s32 l, off, kw, bsize, buff_ind;
- mlib_s32 d0, d1, shift1, shift2;
- mlib_s32 k0, k1, k2, k3, k4, k5, k6;
- mlib_s32 p0, p1, p2, p3, p4, p5, p6, p7;
- mlib_s32 wid, hgt, sll, dll;
- mlib_s32 nchannel, chan1;
- mlib_s32 i, j, c, swid;
- mlib_s32 chan2;
- mlib_s32 k_locl[MAX_N*MAX_N], *k = k_locl;
- GET_SRC_DST_PARAMETERS(DTYPE);
-
-#if IMG_TYPE != 1
- shift1 = 16;
-#else
- shift1 = 8;
-#endif /* IMG_TYPE != 1 */
- shift2 = scale - shift1;
-
- chan1 = nchannel;
- chan2 = chan1 + chan1;
-
- if (!SAFE_TO_ADD(wid, (m - 1))) {
- return MLIB_FAILURE;
- }
- swid = wid + (m - 1);
-
- if (!SAFE_TO_MULT((n + 2), swid)) {
- return MLIB_FAILURE;
- }
- bsize = (n + 2)*swid;
-
- if ((bsize > BUFF_SIZE) || (n > MAX_N)) {
- pbuff = mlib_malloc(sizeof(mlib_s32)*bsize + sizeof(mlib_s32 *)*2*(n + 1));
-
- if (pbuff == NULL) return MLIB_FAILURE;
- buffs = (mlib_s32 **)(pbuff + bsize);
- }
-
- for (l = 0; l < (n + 1); l++) buffs[l] = pbuff + l*swid;
- for (l = 0; l < (n + 1); l++) buffs[l + (n + 1)] = buffs[l];
- buffd = buffs[n] + swid;
-
- if (m*n > MAX_N*MAX_N) {
- k = mlib_malloc(sizeof(mlib_s32)*(m*n));
-
- if (k == NULL) {
- if (pbuff != buff) mlib_free(pbuff);
- return MLIB_FAILURE;
- }
- }
-
- for (i = 0; i < m*n; i++) {
- k[i] = kernel[i] >> shift1;
- }
-
- swid -= (dx_l + dx_r);
-
- for (c = 0; c < nchannel; c++) {
- if (!(cmask & (1 << (nchannel - 1 - c)))) continue;
-
- sl = adr_src + c;
- dl = adr_dst + c;
-
- for (l = 0; l < n; l++) {
- mlib_s32 *buff = buffs[l];
-
- for (i = 0; i < dx_l; i++) {
- buff[i] = (mlib_s32)sl[0];
- }
-
- for (i = 0; i < swid; i++) {
- buff[i + dx_l] = (mlib_s32)sl[i*chan1];
- }
-
- for (i = 0; i < dx_r; i++) {
- buff[swid + dx_l + i] = buff[swid + dx_l - 1];
- }
-
- if ((l >= dy_t) && (l < hgt + n - dy_b - 2)) sl += sll;
- }
-
- buff_ind = 0;
-
- for (i = 0; i < wid; i++) buffd[i] = 0;
-
- for (j = 0; j < hgt; j++) {
- mlib_s32 **buffc = buffs + buff_ind;
- mlib_s32 *buffn = buffc[n];
- mlib_s32 *pk = k;
-
- for (l = 0; l < n; l++) {
- mlib_s32 *buff_l = buffc[l];
-
- for (off = 0; off < m;) {
- mlib_s32 *buff = buff_l + off;
-
- sp = sl;
- dp = dl;
-
- kw = m - off;
-
- if (kw > 2*MAX_KER) kw = MAX_KER; else
- if (kw > MAX_KER) kw = kw/2;
- off += kw;
-
- if (kw == 7) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4]; p7 = buff[5];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5]; k6 = pk[6];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 6) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 5) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 4) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 3) {
-
- p2 = buff[0]; p3 = buff[1];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 2) {
-
- p2 = buff[0];
- k0 = pk[0]; k1 = pk[1];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- buffd[i ] += p0*k0 + p1*k1;
- buffd[i + 1] += p1*k0 + p2*k1;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else /* kw == 1 */{
-
- k0 = pk[0];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = buff[i]; p1 = buff[i + 1];
-
- buffd[i ] += p0*k0;
- buffd[i + 1] += p1*k0;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = buff[i]; p1 = buff[i + 1];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + buffd[i ]);
- d1 = (p1*k0 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
- }
-
- pk += kw;
- }
- }
-
- /* last pixels */
- for (; i < wid; i++) {
- mlib_s32 *pk = k, x, s = 0;
-
- for (l = 0; l < n; l++) {
- mlib_s32 *buff = buffc[l] + i;
-
- for (x = 0; x < m; x++) s += buff[x] * (*pk++);
- }
-
- STORE_RES(dp[0], s);
-
- buffn[i + dx_l] = (mlib_s32)sp[0];
-
- sp += chan1;
- dp += chan1;
- }
-
- for (; i < swid; i++) {
- buffn[i + dx_l] = (mlib_s32)sp[0];
- sp += chan1;
- }
-
- for (i = 0; i < dx_l; i++) buffn[i] = buffn[dx_l];
- for (i = 0; i < dx_r; i++) buffn[swid + dx_l + i] = buffn[swid + dx_l - 1];
-
- /* next line */
-
- if (j < hgt - dy_b - 2) sl += sll;
- dl += dll;
-
- buff_ind++;
-
- if (buff_ind >= n + 1) buff_ind = 0;
- }
- }
-
- if (pbuff != buff) mlib_free(pbuff);
- if (k != k_locl) mlib_free(k);
-
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16ext.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16ext.c
deleted file mode 100644
index 81a06f2fc28..00000000000
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_u16ext.c
+++ /dev/null
@@ -1,1348 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-
-/*
- * FUNCTION
- * Internal functions for mlib_ImageConv* on U8/S16/U16 type and
- * MLIB_EDGE_SRC_EXTEND mask
- */
-
-#include "mlib_image.h"
-#include "mlib_ImageConv.h"
-#include "mlib_c_ImageConv.h"
-#include "safe_math.h"
-
-/*
- * This define switches between functions of different data types
- */
-
-#define IMG_TYPE 3
-
-/***************************************************************/
-#if IMG_TYPE == 1
-
-#define DTYPE mlib_u8
-#define CONV_FUNC(KERN) mlib_c_conv##KERN##ext_u8(PARAM)
-#define CONV_FUNC_MxN mlib_c_convMxNext_u8(PARAM_MxN)
-#define CONV_FUNC_I(KERN) mlib_i_conv##KERN##ext_u8(PARAM)
-#define CONV_FUNC_MxN_I mlib_i_convMxNext_u8(PARAM_MxN)
-#define DSCALE (1 << 24)
-#define FROM_S32(x) (((x) >> 24) ^ 128)
-#define S64TOS32(x) (x)
-#define SAT_OFF -(1u << 31)
-
-#elif IMG_TYPE == 2
-
-#define DTYPE mlib_s16
-#define CONV_FUNC(KERN) mlib_conv##KERN##ext_s16(PARAM)
-#define CONV_FUNC_MxN mlib_convMxNext_s16(PARAM_MxN)
-#define CONV_FUNC_I(KERN) mlib_i_conv##KERN##ext_s16(PARAM)
-#define CONV_FUNC_MxN_I mlib_i_convMxNext_s16(PARAM_MxN)
-#define DSCALE 65536.0
-#define FROM_S32(x) ((x) >> 16)
-#define S64TOS32(x) ((x) & 0xffffffff)
-#define SAT_OFF
-
-#elif IMG_TYPE == 3
-
-#define DTYPE mlib_u16
-#define CONV_FUNC(KERN) mlib_conv##KERN##ext_u16(PARAM)
-#define CONV_FUNC_MxN mlib_convMxNext_u16(PARAM_MxN)
-#define CONV_FUNC_I(KERN) mlib_i_conv##KERN##ext_u16(PARAM)
-#define CONV_FUNC_MxN_I mlib_i_convMxNext_u16(PARAM_MxN)
-#define DSCALE 65536.0
-#define FROM_S32(x) (((x) >> 16) ^ 0x8000)
-#define S64TOS32(x) (x)
-#define SAT_OFF -(1u << 31)
-
-#endif /* IMG_TYPE == 1 */
-
-/***************************************************************/
-#define PARAM \
- mlib_image *dst, \
- const mlib_image *src, \
- mlib_s32 dx_l, \
- mlib_s32 dx_r, \
- mlib_s32 dy_t, \
- mlib_s32 dy_b, \
- const mlib_s32 *kern, \
- mlib_s32 scalef_expon, \
- mlib_s32 cmask
-
-/***************************************************************/
-#define PARAM_MxN \
- mlib_image *dst, \
- const mlib_image *src, \
- const mlib_s32 *kernel, \
- mlib_s32 m, \
- mlib_s32 n, \
- mlib_s32 dx_l, \
- mlib_s32 dx_r, \
- mlib_s32 dy_t, \
- mlib_s32 dy_b, \
- mlib_s32 scale, \
- mlib_s32 cmask
-
-/***************************************************************/
-#define FTYPE mlib_d64
-
-#ifndef MLIB_USE_FTOI_CLAMPING
-
-#define CLAMP_S32(x) \
- (((x) <= MLIB_S32_MIN) ? MLIB_S32_MIN : (((x) >= MLIB_S32_MAX) ? MLIB_S32_MAX : (mlib_s32)(x)))
-
-#else
-
-#define CLAMP_S32(x) ((mlib_s32)(x))
-
-#endif /* MLIB_USE_FTOI_CLAMPING */
-
-/***************************************************************/
-#define D2I(x) CLAMP_S32((x) SAT_OFF)
-
-/***************************************************************/
-#ifdef _LITTLE_ENDIAN
-
-#define STORE2(res0, res1) \
- dp[0 ] = res1; \
- dp[chan1] = res0
-
-#else
-
-#define STORE2(res0, res1) \
- dp[0 ] = res0; \
- dp[chan1] = res1
-
-#endif /* _LITTLE_ENDIAN */
-
-/***************************************************************/
-#ifdef _NO_LONGLONG
-
-#define LOAD_BUFF(buff) \
- buff[i ] = sp[0]; \
- buff[i + 1] = sp[chan1]
-
-#else /* _NO_LONGLONG */
-
-#ifdef _LITTLE_ENDIAN
-
-#define LOAD_BUFF(buff) \
- *(mlib_s64*)(buff + i) = (((mlib_s64)sp[chan1]) << 32) | S64TOS32((mlib_s64)sp[0])
-
-#else /* _LITTLE_ENDIAN */
-
-#define LOAD_BUFF(buff) \
- *(mlib_s64*)(buff + i) = (((mlib_s64)sp[0]) << 32) | S64TOS32((mlib_s64)sp[chan1])
-
-#endif /* _LITTLE_ENDIAN */
-#endif /* _NO_LONGLONG */
-
-/***************************************************************/
-typedef union {
- mlib_d64 d64;
- struct {
- mlib_s32 i0;
- mlib_s32 i1;
- } i32s;
-} d64_2x32;
-
-/***************************************************************/
-#define DEF_VARS(type) \
- type *adr_src, *sl, *sp, *sl1; \
- type *adr_dst, *dl, *dp; \
- FTYPE *pbuff = buff; \
- mlib_s32 *buffi, *buffo; \
- mlib_s32 wid, hgt, sll, dll; \
- mlib_s32 nchannel, chan1, chan2; \
- mlib_s32 i, j, c, swid
-
-/***************************************************************/
-#define GET_SRC_DST_PARAMETERS(type) \
- hgt = mlib_ImageGetHeight(src); \
- wid = mlib_ImageGetWidth(src); \
- nchannel = mlib_ImageGetChannels(src); \
- sll = mlib_ImageGetStride(src) / sizeof(type); \
- dll = mlib_ImageGetStride(dst) / sizeof(type); \
- adr_src = (type *)mlib_ImageGetData(src); \
- adr_dst = (type *)mlib_ImageGetData(dst)
-
-/***************************************************************/
-#if IMG_TYPE == 1
-
-/*
- * Test for the presence of any "1" bit in bits
- 8 to 31 of val. If present, then val is either
- negative or >255. If over/underflows of 8 bits
- are uncommon, then this technique can be a win,
- since only a single test, rather than two, is
- necessary to determine if clamping is needed.
- On the other hand, if over/underflows are common,
- it adds an extra test.
-*/
-#define CLAMP_STORE(dst, val) \
- if (val & 0xffffff00) { \
- if (val < MLIB_U8_MIN) \
- dst = MLIB_U8_MIN; \
- else \
- dst = MLIB_U8_MAX; \
- } else { \
- dst = (mlib_u8)val; \
- }
-
-#elif IMG_TYPE == 2
-
-#define CLAMP_STORE(dst, val) \
- if (val >= MLIB_S16_MAX) \
- dst = MLIB_S16_MAX; \
- else if (val <= MLIB_S16_MIN) \
- dst = MLIB_S16_MIN; \
- else \
- dst = (mlib_s16)val
-
-#elif IMG_TYPE == 3
-
-#define CLAMP_STORE(dst, val) \
- if (val >= MLIB_U16_MAX) \
- dst = MLIB_U16_MAX; \
- else if (val <= MLIB_U16_MIN) \
- dst = MLIB_U16_MIN; \
- else \
- dst = (mlib_u16)val
-
-#endif /* IMG_TYPE == 1 */
-
-/***************************************************************/
-#define MAX_KER 7
-#define MAX_N 15
-#define BUFF_SIZE 1600
-#define CACHE_SIZE (64*1024)
-
-static mlib_status mlib_ImageConv1xN_ext(mlib_image *dst,
- const mlib_image *src,
- const mlib_d64 *k,
- mlib_s32 n,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask)
-{
- DTYPE *adr_src, *sl;
- DTYPE *adr_dst, *dl, *dp;
- FTYPE buff[BUFF_SIZE];
- FTYPE *buffd;
- FTYPE *pbuff = buff;
- const FTYPE *pk;
- FTYPE k0, k1, k2, k3;
- FTYPE p0, p1, p2, p3, p4;
- FTYPE *sbuff;
- mlib_s32 l, k_off, off, bsize;
- mlib_s32 max_hsize, smax_hsize, shgt, hsize, kh;
- mlib_s32 d0, d1, ii;
- mlib_s32 wid, hgt, sll, dll;
- mlib_s32 nchannel;
- mlib_s32 i, j, c;
- GET_SRC_DST_PARAMETERS(DTYPE);
-
- max_hsize = ((CACHE_SIZE/sizeof(DTYPE))/sll) - (n - 1);
-
- if (max_hsize < 1) max_hsize = 1;
- if (max_hsize > hgt) max_hsize = hgt;
-
- shgt = hgt + (n - 1);
- if (!SAFE_TO_ADD(max_hsize, (n - 1))) {
- return MLIB_FAILURE;
- }
- smax_hsize = max_hsize + (n - 1);
-
- if (!SAFE_TO_ADD(smax_hsize, 1) || !SAFE_TO_MULT(2, (smax_hsize + 1))) {
- return MLIB_FAILURE;
- }
- bsize = 2 * (smax_hsize + 1);
-
- if (bsize > BUFF_SIZE) {
- pbuff = mlib_malloc(sizeof(FTYPE)*bsize);
-
- if (pbuff == NULL) return MLIB_FAILURE;
- }
-
- sbuff = pbuff;
- buffd = sbuff + smax_hsize;
-
- shgt -= (dy_t + dy_b);
- k_off = 0;
-
- for (l = 0; l < hgt; l += hsize) {
- hsize = hgt - l;
-
- if (hsize > max_hsize) hsize = max_hsize;
-
- smax_hsize = hsize + (n - 1);
-
- for (c = 0; c < nchannel; c++) {
- if (!(cmask & (1 << (nchannel - 1 - c)))) continue;
-
- sl = adr_src + c;
- dl = adr_dst + c;
-
- for (i = 0; i < hsize; i++) buffd[i] = 0.0;
-
- for (j = 0; j < wid; j++) {
- FTYPE *buff = sbuff;
-
- for (i = k_off, ii = 0; (i < dy_t) && (ii < smax_hsize); i++, ii++) {
- sbuff[i - k_off] = (FTYPE)sl[0];
- }
-
- for (; (i < shgt + dy_t) && (ii < smax_hsize); i++, ii++) {
- sbuff[i - k_off] = (FTYPE)sl[(i - dy_t)*sll];
- }
-
- for (; (i < shgt + dy_t + dy_b) && (ii < smax_hsize); i++, ii++) {
- sbuff[i - k_off] = (FTYPE)sl[(shgt - 1)*sll];
- }
-
- pk = k;
-
- for (off = 0; off < (n - 4); off += 4) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- for (i = 0; i < hsize; i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3;
- }
-
- pk += 4;
- buff += 4;
- }
-
- dp = dl;
- kh = n - off;
-
- if (kh == 4) {
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = p2; p1 = p3; p2 = p4;
- p3 = buff[i + 3];
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i]);
- dp[0] = FROM_S32(d0);
- buffd[i] = 0.0;
- }
-
- } else if (kh == 3) {
-
- p2 = buff[0]; p3 = buff[1];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = p2; p1 = p3;
- p2 = buff[i + 2];
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + buffd[i]);
- dp[0] = FROM_S32(d0);
-
- buffd[i] = 0.0;
- }
-
- } else if (kh == 2) {
-
- p2 = buff[0];
- k0 = pk[0]; k1 = pk[1];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- d0 = D2I(p0*k0 + p1*k1 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = p2;
- p1 = buff[i + 1];
- d0 = D2I(p0*k0 + p1*k1 + buffd[i]);
- dp[0] = FROM_S32(d0);
-
- buffd[i] = 0.0;
- }
-
- } else /* kh == 1 */{
-
- k0 = pk[0];
-
- for (i = 0; i <= (hsize - 2); i += 2) {
- p0 = buff[i]; p1 = buff[i + 1];
-
- d0 = D2I(p0*k0 + buffd[i ]);
- d1 = D2I(p1*k0 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[dll] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- dp += 2*dll;
- }
-
- if (i < hsize) {
- p0 = buff[i];
- d0 = D2I(p0*k0 + buffd[i]);
- dp[0] = FROM_S32(d0);
-
- buffd[i] = 0.0;
- }
- }
-
- /* next line */
- sl += nchannel;
- dl += nchannel;
- }
- }
-
- k_off += max_hsize;
- adr_dst += max_hsize*dll;
- }
-
- if (pbuff != buff) mlib_free(pbuff);
-
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
-mlib_status CONV_FUNC_MxN
-{
- DTYPE *adr_src, *sl, *sp = NULL;
- DTYPE *adr_dst, *dl, *dp = NULL;
- FTYPE buff[BUFF_SIZE], *buffs_arr[2*(MAX_N + 1)];
- FTYPE **buffs = buffs_arr, *buffd;
- FTYPE akernel[256], *k = akernel, fscale = DSCALE;
- FTYPE *pbuff = buff;
- FTYPE k0, k1, k2, k3, k4, k5, k6;
- FTYPE p0, p1, p2, p3, p4, p5, p6, p7;
- mlib_s32 *buffi;
- mlib_s32 mn, l, off, kw, bsize, buff_ind;
- mlib_s32 d0, d1;
- mlib_s32 wid, hgt, sll, dll;
- mlib_s32 nchannel, chan1, chan2;
- mlib_s32 i, j, c, swid;
- d64_2x32 dd;
- mlib_status status = MLIB_SUCCESS;
-
- GET_SRC_DST_PARAMETERS(DTYPE);
-
- if (scale > 30) {
- fscale *= 1.0/(1 << 30);
- scale -= 30;
- }
-
- fscale /= (1 << scale);
-
- mn = m*n;
-
- if (mn > 256) {
- k = mlib_malloc(mn*sizeof(mlib_d64));
-
- if (k == NULL) return MLIB_FAILURE;
- }
-
- for (i = 0; i < mn; i++) {
- k[i] = kernel[i]*fscale;
- }
-
- if (m == 1) {
- status = mlib_ImageConv1xN_ext(dst, src, k, n, dy_t, dy_b, cmask);
- FREE_AND_RETURN_STATUS;
- }
-
- if (!SAFE_TO_ADD(wid, (m - 1))) {
- status = MLIB_FAILURE;
- FREE_AND_RETURN_STATUS;
- }
- swid = wid + (m - 1);
-
- if (!SAFE_TO_MULT((n + 3), swid)) {
- status = MLIB_FAILURE;
- FREE_AND_RETURN_STATUS;
- }
- bsize = (n + 3)*swid;
-
- if ((bsize > BUFF_SIZE) || (n > MAX_N)) {
- pbuff = mlib_malloc(sizeof(FTYPE)*bsize + sizeof(FTYPE *)*2*(n + 1));
-
- if (pbuff == NULL) {
- status = MLIB_FAILURE;
- FREE_AND_RETURN_STATUS;
- }
- buffs = (FTYPE **)(pbuff + bsize);
- }
-
- for (l = 0; l < (n + 1); l++) buffs[l] = pbuff + l*swid;
- for (l = 0; l < (n + 1); l++) buffs[l + (n + 1)] = buffs[l];
- buffd = buffs[n] + swid;
- buffi = (mlib_s32*)(buffd + swid);
-
- chan1 = nchannel;
- chan2 = chan1 + chan1;
-
- swid -= (dx_l + dx_r);
-
- for (c = 0; c < nchannel; c++) {
- if (!(cmask & (1 << (chan1 - 1 - c)))) continue;
-
- sl = adr_src + c;
- dl = adr_dst + c;
-
- for (l = 0; l < n; l++) {
- FTYPE *buff = buffs[l];
-
- for (i = 0; i < dx_l; i++) {
- buff[i] = (FTYPE)sl[0];
- }
-
- for (i = 0; i < swid; i++) {
- buff[i + dx_l] = (FTYPE)sl[i*chan1];
- }
-
- for (i = 0; i < dx_r; i++) {
- buff[swid + dx_l + i] = buff[swid + dx_l - 1];
- }
-
- if ((l >= dy_t) && (l < hgt + n - dy_b - 2)) sl += sll;
- }
-
- buff_ind = 0;
-
- for (i = 0; i < wid; i++) buffd[i] = 0.0;
-
- for (j = 0; j < hgt; j++) {
- FTYPE **buffc = buffs + buff_ind;
- FTYPE *buffn = buffc[n];
- FTYPE *pk = k;
-
- for (l = 0; l < n; l++) {
- FTYPE *buff_l = buffc[l];
-
- for (off = 0; off < m;) {
- FTYPE *buff = buff_l + off;
-
- kw = m - off;
-
- if (kw > 2*MAX_KER) kw = MAX_KER; else
- if (kw > MAX_KER) kw = kw/2;
- off += kw;
-
- sp = sl;
- dp = dl;
-
- if (kw == 7) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4]; p7 = buff[5];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5]; k6 = pk[6];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 6) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 5) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 4) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + p4*k3 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 3) {
-
- p2 = buff[0]; p3 = buff[1];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + p2*k2 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + p3*k2 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else /* if (kw == 2) */ {
-
- p2 = buff[0];
- k0 = pk[0]; k1 = pk[1];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- buffd[i ] += p0*k0 + p1*k1;
- buffd[i + 1] += p1*k0 + p2*k1;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- LOAD_BUFF(buffi);
-
- dd.d64 = *(FTYPE *)(buffi + i);
- buffn[i + dx_l ] = (FTYPE)dd.i32s.i0;
- buffn[i + dx_l + 1] = (FTYPE)dd.i32s.i1;
-
- d0 = D2I(p0*k0 + p1*k1 + buffd[i ]);
- d1 = D2I(p1*k0 + p2*k1 + buffd[i + 1]);
-
- dp[0 ] = FROM_S32(d0);
- dp[chan1] = FROM_S32(d1);
-
- buffd[i ] = 0.0;
- buffd[i + 1] = 0.0;
-
- sp += chan2;
- dp += chan2;
- }
- }
- }
-
- pk += kw;
- }
- }
-
- /* last pixels */
- for (; i < wid; i++) {
- FTYPE *pk = k, s = 0;
- mlib_s32 x, d0;
-
- for (l = 0; l < n; l++) {
- FTYPE *buff = buffc[l] + i;
-
- for (x = 0; x < m; x++) s += buff[x] * (*pk++);
- }
-
- d0 = D2I(s);
- dp[0] = FROM_S32(d0);
-
- buffn[i + dx_l] = (FTYPE)sp[0];
-
- sp += chan1;
- dp += chan1;
- }
-
- for (; i < swid; i++) {
- buffn[i + dx_l] = (FTYPE)sp[0];
- sp += chan1;
- }
-
- for (i = 0; i < dx_l; i++) buffn[i] = buffn[dx_l];
- for (i = 0; i < dx_r; i++) buffn[swid + dx_l + i] = buffn[swid + dx_l - 1];
-
- /* next line */
-
- if (j < hgt - dy_b - 2) sl += sll;
- dl += dll;
-
- buff_ind++;
-
- if (buff_ind >= n + 1) buff_ind = 0;
- }
- }
-
- FREE_AND_RETURN_STATUS;
-}
-
-/***************************************************************/
-#define STORE_RES(res, x) \
- x >>= shift2; \
- CLAMP_STORE(res, x)
-
-mlib_status CONV_FUNC_MxN_I
-{
- DTYPE *adr_src, *sl, *sp = NULL;
- DTYPE *adr_dst, *dl, *dp = NULL;
- mlib_s32 buff[BUFF_SIZE], *buffs_arr[2*(MAX_N + 1)];
- mlib_s32 *pbuff = buff;
- mlib_s32 **buffs = buffs_arr, *buffd;
- mlib_s32 l, off, kw, bsize, buff_ind;
- mlib_s32 d0, d1, shift1, shift2;
- mlib_s32 k0, k1, k2, k3, k4, k5, k6;
- mlib_s32 p0, p1, p2, p3, p4, p5, p6, p7;
- mlib_s32 wid, hgt, sll, dll;
- mlib_s32 nchannel, chan1;
- mlib_s32 i, j, c, swid;
- mlib_s32 chan2;
- mlib_s32 k_locl[MAX_N*MAX_N], *k = k_locl;
- GET_SRC_DST_PARAMETERS(DTYPE);
-
-#if IMG_TYPE != 1
- shift1 = 16;
-#else
- shift1 = 8;
-#endif /* IMG_TYPE != 1 */
- shift2 = scale - shift1;
-
- chan1 = nchannel;
- chan2 = chan1 + chan1;
-
- if (!SAFE_TO_ADD(wid, (m - 1))) {
- return MLIB_FAILURE;
- }
- swid = wid + (m - 1);
-
- if (!SAFE_TO_MULT((n + 2), swid)) {
- return MLIB_FAILURE;
- }
- bsize = (n + 2)*swid;
-
- if ((bsize > BUFF_SIZE) || (n > MAX_N)) {
- pbuff = mlib_malloc(sizeof(mlib_s32)*bsize + sizeof(mlib_s32 *)*2*(n + 1));
-
- if (pbuff == NULL) return MLIB_FAILURE;
- buffs = (mlib_s32 **)(pbuff + bsize);
- }
-
- for (l = 0; l < (n + 1); l++) buffs[l] = pbuff + l*swid;
- for (l = 0; l < (n + 1); l++) buffs[l + (n + 1)] = buffs[l];
- buffd = buffs[n] + swid;
-
- if (m*n > MAX_N*MAX_N) {
- k = mlib_malloc(sizeof(mlib_s32)*(m*n));
-
- if (k == NULL) {
- if (pbuff != buff) mlib_free(pbuff);
- return MLIB_FAILURE;
- }
- }
-
- for (i = 0; i < m*n; i++) {
- k[i] = kernel[i] >> shift1;
- }
-
- swid -= (dx_l + dx_r);
-
- for (c = 0; c < nchannel; c++) {
- if (!(cmask & (1 << (nchannel - 1 - c)))) continue;
-
- sl = adr_src + c;
- dl = adr_dst + c;
-
- for (l = 0; l < n; l++) {
- mlib_s32 *buff = buffs[l];
-
- for (i = 0; i < dx_l; i++) {
- buff[i] = (mlib_s32)sl[0];
- }
-
- for (i = 0; i < swid; i++) {
- buff[i + dx_l] = (mlib_s32)sl[i*chan1];
- }
-
- for (i = 0; i < dx_r; i++) {
- buff[swid + dx_l + i] = buff[swid + dx_l - 1];
- }
-
- if ((l >= dy_t) && (l < hgt + n - dy_b - 2)) sl += sll;
- }
-
- buff_ind = 0;
-
- for (i = 0; i < wid; i++) buffd[i] = 0;
-
- for (j = 0; j < hgt; j++) {
- mlib_s32 **buffc = buffs + buff_ind;
- mlib_s32 *buffn = buffc[n];
- mlib_s32 *pk = k;
-
- for (l = 0; l < n; l++) {
- mlib_s32 *buff_l = buffc[l];
-
- for (off = 0; off < m;) {
- mlib_s32 *buff = buff_l + off;
-
- sp = sl;
- dp = dl;
-
- kw = m - off;
-
- if (kw > 2*MAX_KER) kw = MAX_KER; else
- if (kw > MAX_KER) kw = kw/2;
- off += kw;
-
- if (kw == 7) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4]; p7 = buff[5];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5]; k6 = pk[6];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; p5 = p7;
-
- p6 = buff[i + 6]; p7 = buff[i + 7];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 6) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3]; p6 = buff[4];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4]; k5 = pk[5];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6;
-
- p5 = buff[i + 5]; p6 = buff[i + 6];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 5) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
- p5 = buff[3];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
- k4 = pk[4];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4; p3 = p5;
-
- p4 = buff[i + 4]; p5 = buff[i + 5];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 4) {
-
- p2 = buff[0]; p3 = buff[1]; p4 = buff[2];
-
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2 + p3*k3;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3; p2 = p4;
-
- p3 = buff[i + 3]; p4 = buff[i + 4];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + p3*k3 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + p4*k3 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 3) {
-
- p2 = buff[0]; p3 = buff[1];
- k0 = pk[0]; k1 = pk[1]; k2 = pk[2];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- buffd[i ] += p0*k0 + p1*k1 + p2*k2;
- buffd[i + 1] += p1*k0 + p2*k1 + p3*k2;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2; p1 = p3;
-
- p2 = buff[i + 2]; p3 = buff[i + 3];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + p2*k2 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + p3*k2 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else if (kw == 2) {
-
- p2 = buff[0];
- k0 = pk[0]; k1 = pk[1];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- buffd[i ] += p0*k0 + p1*k1;
- buffd[i + 1] += p1*k0 + p2*k1;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = p2;
-
- p1 = buff[i + 1]; p2 = buff[i + 2];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + p1*k1 + buffd[i ]);
- d1 = (p1*k0 + p2*k1 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
-
- } else /* kw == 1 */{
-
- k0 = pk[0];
-
- if (l < (n - 1) || off < m) {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = buff[i]; p1 = buff[i + 1];
-
- buffd[i ] += p0*k0;
- buffd[i + 1] += p1*k0;
- }
-
- } else {
- for (i = 0; i <= (wid - 2); i += 2) {
- p0 = buff[i]; p1 = buff[i + 1];
-
- buffn[i + dx_l ] = (mlib_s32)sp[0];
- buffn[i + dx_l + 1] = (mlib_s32)sp[chan1];
-
- d0 = (p0*k0 + buffd[i ]);
- d1 = (p1*k0 + buffd[i + 1]);
-
- STORE_RES(dp[0 ], d0);
- STORE_RES(dp[chan1], d1);
-
- buffd[i ] = 0;
- buffd[i + 1] = 0;
-
- sp += chan2;
- dp += chan2;
- }
- }
- }
-
- pk += kw;
- }
- }
-
- /* last pixels */
- for (; i < wid; i++) {
- mlib_s32 *pk = k, x, s = 0;
-
- for (l = 0; l < n; l++) {
- mlib_s32 *buff = buffc[l] + i;
-
- for (x = 0; x < m; x++) s += buff[x] * (*pk++);
- }
-
- STORE_RES(dp[0], s);
-
- buffn[i + dx_l] = (mlib_s32)sp[0];
-
- sp += chan1;
- dp += chan1;
- }
-
- for (; i < swid; i++) {
- buffn[i + dx_l] = (mlib_s32)sp[0];
- sp += chan1;
- }
-
- for (i = 0; i < dx_l; i++) buffn[i] = buffn[dx_l];
- for (i = 0; i < dx_r; i++) buffn[swid + dx_l + i] = buffn[swid + dx_l - 1];
-
- /* next line */
-
- if (j < hgt - dy_b - 2) sl += sll;
- dl += dll;
-
- buff_ind++;
-
- if (buff_ind >= n + 1) buff_ind = 0;
- }
- }
-
- if (pbuff != buff) mlib_free(pbuff);
- if (k != k_locl) mlib_free(k);
-
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConv.h b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConv.h
index 0f311a4d484..81a367578d2 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConv.h
+++ b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConv.h
@@ -49,18 +49,6 @@ mlib_status mlib_c_convMxNnw_u8(mlib_image *dst,
mlib_s32 scale,
mlib_s32 cmask);
-mlib_status mlib_c_convMxNext_u8(mlib_image *dst,
- const mlib_image *src,
- const mlib_s32 *kern,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 scale,
- mlib_s32 cmask);
-
/* for x86, using integer multiplies is faster */
mlib_status mlib_i_convMxNnw_s16(mlib_image *dst,
@@ -93,42 +81,6 @@ mlib_status mlib_i_convMxNnw_u8(mlib_image *dst,
mlib_s32 scale,
mlib_s32 cmask);
-mlib_status mlib_i_convMxNext_u8(mlib_image *dst,
- const mlib_image *src,
- const mlib_s32 *kern,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 scale,
- mlib_s32 cmask);
-
-mlib_status mlib_i_convMxNext_s16(mlib_image *dst,
- const mlib_image *src,
- const mlib_s32 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 scale,
- mlib_s32 cmask);
-
-mlib_status mlib_i_convMxNext_u16(mlib_image *dst,
- const mlib_image *src,
- const mlib_s32 *kernel,
- mlib_s32 m,
- mlib_s32 n,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 scale,
- mlib_s32 cmask);
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConvCopyEdge.c b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConvCopyEdge.c
deleted file mode 100644
index 7b463934fe5..00000000000
--- a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConvCopyEdge.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
- * 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.
- */
-
-
-/*
- * FUNCTIONS
- * mlib_ImageConvCopyEdge - Copy src edges to dst edges
- *
- *
- * SYNOPSIS
- * mlib_status mlib_ImageConvCopyEdge(mlib_image *dst,
- * const mlib_image *src,
- * mlib_s32 dx_l,
- * mlib_s32 dx_r,
- * mlib_s32 dy_t,
- * mlib_s32 dy_b,
- * mlib_s32 cmask)
- *
- * ARGUMENT
- * dst Pointer to an dst image.
- * src Pointer to an src image.
- * dx_l Number of columns on the left side of the
- * image to be copied.
- * dx_r Number of columns on the right side of the
- * image to be copied.
- * dy_t Number of rows on the top edge of the
- * image to be copied.
- * dy_b Number of rows on the top edge of the
- * image to be copied.
- * cmask Channel mask to indicate the channels to be convolved.
- * Each bit of which represents a channel in the image. The
- * channels corresponded to 1 bits are those to be processed.
- *
- * RESTRICTION
- * The src and the dst must be the same type, same width, same height and have same number
- * of channels (1, 2, 3, or 4). The unselected channels are not
- * overwritten. If both src and dst have just one channel,
- * cmask is ignored.
- *
- * DESCRIPTION
- * Copy src edges to dst edges.
- *
- * The unselected channels are not overwritten.
- * If src and dst have just one channel,
- * cmask is ignored.
- */
-
-#include "mlib_image.h"
-#include "mlib_ImageConvEdge.h"
-
-/***************************************************************/
-#define EDGES(chan, type, mask) \
- { \
- type *pdst = (type *) mlib_ImageGetData(dst); \
- type *psrc = (type *) mlib_ImageGetData(src); \
- mlib_s32 dst_stride = mlib_ImageGetStride(dst) / sizeof(type); \
- mlib_s32 src_stride = mlib_ImageGetStride(src) / sizeof(type); \
- mlib_s32 i, j, l; \
- mlib_s32 testchan; \
- \
- testchan = 1; \
- for (l = chan - 1; l >= 0; l--) { \
- if ((mask & testchan) == 0) { \
- testchan <<= 1; \
- continue; \
- } \
- testchan <<= 1; \
- for (j = 0; j < dx_l; j++) { \
- for (i = dy_t; i < (img_height - dy_b); i++) { \
- pdst[i*dst_stride + l + j*chan] = psrc[i*src_stride + l + j*chan]; \
- } \
- } \
- for (j = 0; j < dx_r; j++) { \
- for (i = dy_t; i < (img_height - dy_b); i++) { \
- pdst[i*dst_stride + l+(img_width-1 - j)*chan] = \
- psrc[i*src_stride + l+(img_width-1 - j)*chan]; \
- } \
- } \
- for (i = 0; i < dy_t; i++) { \
- for (j = 0; j < img_width; j++) { \
- pdst[i*dst_stride + l + j*chan] = psrc[i*src_stride + l + j*chan]; \
- } \
- } \
- for (i = 0; i < dy_b; i++) { \
- for (j = 0; j < img_width; j++) { \
- pdst[(img_height-1 - i)*dst_stride + l + j*chan] = \
- psrc[(img_height-1 - i)*src_stride + l + j*chan]; \
- } \
- } \
- } \
- }
-
-/***************************************************************/
-mlib_status mlib_ImageConvCopyEdge(mlib_image *dst,
- const mlib_image *src,
- mlib_s32 dx_l,
- mlib_s32 dx_r,
- mlib_s32 dy_t,
- mlib_s32 dy_b,
- mlib_s32 cmask)
-{
- mlib_s32 img_width = mlib_ImageGetWidth(dst);
- mlib_s32 img_height = mlib_ImageGetHeight(dst);
- mlib_s32 channel = mlib_ImageGetChannels(dst);
-
- if (dx_l + dx_r > img_width) {
- dx_l = img_width;
- dx_r = 0;
- }
-
- if (dy_t + dy_b > img_height) {
- dy_t = img_height;
- dy_b = 0;
- }
-
- if (channel == 1)
- cmask = 1;
-
- switch (mlib_ImageGetType(src)) {
- case MLIB_BIT:
- return mlib_ImageConvCopyEdge_Bit(dst, src, dx_l, dx_r, dy_t, dy_b, cmask);
- case MLIB_BYTE:
- EDGES(channel, mlib_u8, cmask)
- break;
- case MLIB_SHORT:
- case MLIB_USHORT:
- EDGES(channel, mlib_u16, cmask)
- break;
- case MLIB_INT:
- case MLIB_FLOAT:
- EDGES(channel, mlib_u32, cmask)
- break;
- case MLIB_DOUBLE:
- EDGES(channel, mlib_d64, cmask)
- break;
- default:
- return MLIB_FAILURE;
- }
-
- return MLIB_SUCCESS;
-}
-
-/***************************************************************/
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConv_f.c b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConv_f.c
index 5b65422c4c2..79c2b031da3 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConv_f.c
+++ b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConv_f.c
@@ -44,25 +44,6 @@
#define MLIB_CALL_PARAMS_CONV_MN_NW \
dst, src, kern, m, n, dm, dn, scale, cmask
-/***************************************************************/
-#define MLIB_PARAMS_CONV_MN_EXT \
- mlib_image *dst, \
- const mlib_image *src, \
- const mlib_s32 *kern, \
- mlib_s32 m, \
- mlib_s32 n, \
- mlib_s32 dx_l, \
- mlib_s32 dx_r, \
- mlib_s32 dy_t, \
- mlib_s32 dy_b, \
- mlib_s32 scale, \
- mlib_s32 cmask
-
-/***************************************************************/
-#define MLIB_CALL_PARAMS_CONV_MN_EXT \
- dst, src, kern, m, n, dx_l, dx_r, dy_t, dy_b, scale, cmask
-
-
/***************************************************************/
mlib_status mlib_convMxNnw_u8(MLIB_PARAMS_CONV_MN_NW)
{
@@ -73,12 +54,3 @@ mlib_status mlib_convMxNnw_u8(MLIB_PARAMS_CONV_MN_NW)
}
/***************************************************************/
-mlib_status mlib_convMxNext_u8(MLIB_PARAMS_CONV_MN_EXT)
-{
- if (mlib_ImageConvVersion(m, n, scale, MLIB_BYTE) == 0)
- return mlib_c_convMxNext_u8(MLIB_CALL_PARAMS_CONV_MN_EXT);
- else
- return mlib_i_convMxNext_u8(MLIB_CALL_PARAMS_CONV_MN_EXT);
-}
-
-/***************************************************************/
From b560c2024e834275a039324664f73a148184ebfd Mon Sep 17 00:00:00 2001
From: Phil Race
Date: Thu, 1 Oct 2026 20:39:01 +0000
Subject: [PATCH 14/98] 6986565: sun/java2d/SunGraphics2D/PolyVertTest.java
failed on Windows and Solaris
Reviewed-by: kizune, azvegint
---
test/jdk/ProblemList.txt | 3 +-
.../java2d/SunGraphics2D/PolyVertTest.java | 230 ++++++++++++------
2 files changed, 152 insertions(+), 81 deletions(-)
diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt
index 6d2b9a80d45..8d10abb2df5 100644
--- a/test/jdk/ProblemList.txt
+++ b/test/jdk/ProblemList.txt
@@ -210,7 +210,8 @@ sun/java2d/OpenGL/OpaqueDest.java#id1 8367574 macosx-all
sun/java2d/OpenGL/ScaleParamsOOB.java#id0 8377908 linux-all
sun/java2d/SunGraphics2D/EmptyClipRenderingTest.java 8144029 macosx-all,linux-all
sun/java2d/SunGraphics2D/DrawImageBilinear.java 8297175 linux-all
-sun/java2d/SunGraphics2D/PolyVertTest.java 6986565 generic-all
+sun/java2d/SunGraphics2D/PolyVertTest.java#default 8392800,8392802 macosx-all,windows-all
+sun/java2d/SunGraphics2D/PolyVertTest.java#opengl 8392801 linux-all
sun/java2d/SunGraphics2D/SimplePrimQuality.java#default 6322554,8392436 windows-all,macosx-all
sun/java2d/SunGraphics2D/SimplePrimQuality.java#nod3d 6322554 windows-all
sun/java2d/SunGraphics2D/SourceClippingBlitTest/SourceClippingBlitTest.java 8392471 linux-all
diff --git a/test/jdk/sun/java2d/SunGraphics2D/PolyVertTest.java b/test/jdk/sun/java2d/SunGraphics2D/PolyVertTest.java
index 9f9b9f610dd..e3daf0fbd2c 100644
--- a/test/jdk/sun/java2d/SunGraphics2D/PolyVertTest.java
+++ b/test/jdk/sun/java2d/SunGraphics2D/PolyVertTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,22 +22,74 @@
*/
/*
- * @test
+ * @test id=default
* @key headful
* @bug 4678208 4771101 6328481 6588884 8198613
* @summary verify the pixelization of degenerate polylines and polygons
- * @run main PolyVertTest
- * @run main/othervm -Dsun.java2d.d3d=True PolyVertTest -hwonly
+ * @run main/othervm -Dsun.java2d.uiScale=1 PolyVertTest
*/
-import java.awt.*;
-import java.awt.event.*;
-import java.awt.geom.*;
-import java.awt.image.*;
+/*
+ * @test id=noxrender
+ * @key headful
+ * @requires (os.family == "linux")
+ * @bug 4678208 4771101 6328481 6588884 8198613
+ * @summary verify the pixelization of degenerate polylines and polygons
+ * @run main/othervm -Dsun.java2d.uiScale=1 -Dsun.java2d.xrender=false PolyVertTest -hwonly
+ */
+
+/*
+ * @test id=dno3d
+ * @key headful
+ * @requires (os.family == "windows")
+ * @bug 4678208 4771101 6328481 6588884 8198613
+ * @summary verify the pixelization of degenerate polylines and polygons
+ * @run main/othervm -Dsun.java2d.uiScale=1 -Dsun.java2d.d3d=false PolyVertTest -hwonly
+ */
+
+/*
+ * @test id=opengl
+ * @key headful
+ * @bug 4678208 4771101 6328481 6588884 8198613
+ * @summary verify the pixelization of degenerate polylines and polygons
+ * @run main/othervm -Dsun.java2d.uiScale=1 -Dsun.java2d.opengl=True PolyVertTest -hwonly
+ */
+
+import java.awt.AWTException;
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Transparency;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import javax.imageio.ImageIO;
public class PolyVertTest {
- static int TESTWIDTH;
- static int TESTHEIGHT;
+
+ static volatile int TESTWIDTH;
+ static volatile int TESTHEIGHT;
static final int REG_TEST_WIDTH = 10;
static final int REG_TEST_HEIGHT = 10;
static final int FULL_TEST_WIDTH = 50;
@@ -47,29 +99,29 @@ public class PolyVertTest {
static final int GREEN = Color.green.getRGB();
static final int RED = Color.red.getRGB();
- static BufferedImage refImg;
- static BufferedImage errorImg;
- static Graphics errorG;
- static Component testCanvas;
-
- static int totalbadpixels;
- static int totalfuzzypixels;
- static int numbadtests;
- static int numfuzzytests;
- static int numframes;
- static int fuzzystarty;
-
- static boolean counting;
- static boolean showerrors;
- static boolean showresults;
- static boolean fringe;
- static boolean forceerror;
- static boolean fulltest = true;
- static boolean hwonly;
+ static volatile BufferedImage refImg;
+ static volatile BufferedImage errorImg;
+ static volatile Graphics errorG;
+ static volatile TestCanvas testCanvas;
+
+ static volatile int totalbadpixels;
+ static volatile int totalfuzzypixels;
+ static volatile int numbadtests;
+ static volatile int numfuzzytests;
+ static volatile int numframes;
+ static volatile int fuzzystarty;
+
+ static volatile boolean counting;
+ static volatile boolean showerrors;
+ static volatile boolean showresults;
+ static volatile boolean fringe;
+ static volatile boolean forceerror;
+ static volatile boolean fulltest = true;
+ static volatile boolean hwonly;
static WindowListener windowCloser = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
- e.getWindow().hide();
+ e.getWindow().setVisible(false);
if (--numframes <= 0) {
System.exit(0);
}
@@ -260,7 +312,7 @@ public static void usage(int exitcode) {
System.exit(exitcode);
}
- public static void main(String argv[]) {
+ public static void main(String argv[]) throws Exception {
for (int i = 0; i < argv.length; i++) {
String arg = argv[i];
if (arg.equalsIgnoreCase("-count")) {
@@ -300,14 +352,22 @@ public static void main(String argv[]) {
// finished our tests.
numframes++;
- makeReferenceImage();
- testScreen();
- testVolatileImage();
- if (!hwonly) {
- testBufferedImage();
- testOffscreen();
- testCompatibleImages();
+ try {
+ makeReferenceImage();
+ testCanvas = new TestCanvas();
+ testScreen();
+ testVolatileImage();
+ if (!hwonly) {
+ testBufferedImage();
+ testOffscreen();
+ testCompatibleImages();
+ }
+ } finally {
+ if (frame != null) {
+ EventQueue.invokeAndWait(frame::dispose);
+ }
}
+
if (totalfuzzypixels > 0) {
System.err.println(totalfuzzypixels+" fuzzy pixels found in "+
numfuzzytests+" tests");
@@ -466,6 +526,11 @@ public static void verify(BufferedImage bimg, String name) {
errorG.setColor(isfuzzy ? Color.blue : Color.red);
errorG.fillRect(x, y, 1, 1);
} else if (!counting && !isfuzzy) {
+ try {
+ ImageIO.write(refImg, "png", new File("refimg" + ".png"));
+ ImageIO.write(bimg, "png", new File(name+".png"));
+ } catch (Exception e) {
+ }
throw new RuntimeException("Error at "+x+", "+y+
" while testing: "+name);
}
@@ -520,7 +585,16 @@ public static void displaydiffs(BufferedImage bimg, String name) {
}
}
}
- Frame f = new Frame("Results for "+name);
+ try {
+ EventQueue.invokeAndWait(() -> createDiffsUI(bimg, name));
+ } catch (Exception e) {
+ System.err.println("error creating diffs UI for " + name);
+ }
+ }
+
+ static void createDiffsUI(BufferedImage bimg, String name) {
+
+ Frame f = new Frame("Results for " + name);
f.setLayout(new BorderLayout());
f.addWindowListener(windowCloser);
++numframes;
@@ -530,8 +604,9 @@ public static void displaydiffs(BufferedImage bimg, String name) {
p.add(new ImageCanvas(refImg));
f.add(p, "Center");
droperrorbuf();
- f.pack();
- f.show();
+ f.setSize(500, FULL_TEST_HEIGHT + 50);
+ f.setLocationRelativeTo(null);
+ f.setVisible(true);
}
public static void testBufferedImage() {
@@ -549,16 +624,35 @@ public static void testBufferedImage(int type, String name) {
test(bimg, name);
}
- public static void testScreen() {
- Frame f = new Frame("PolyVertTest");
- TestCanvas child = new TestCanvas();
- testCanvas = child;
- f.add(child);
- f.pack();
- f.show();
- BufferedImage bimg = child.getImage();
- f.hide();
- verify(bimg, "Screen");
+ static volatile Frame frame;
+
+ public static void testScreen() throws Exception {
+ EventQueue.invokeAndWait(PolyVertTest::createUI);
+ try {
+ Robot robot = new Robot();
+ robot.waitForIdle();
+ robot.delay(2000);
+ Point p = testCanvas.getLocationOnScreen();
+ Rectangle r = new Rectangle(p.x, p.y, TESTWIDTH, TESTHEIGHT);
+ BufferedImage bimg = robot.createScreenCapture(r);
+ verify(bimg, "Screen");
+ } catch (AWTException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void createUI() {
+ frame = new Frame("PolyVertTest");
+ frame.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(50, 50, 50, 50);
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1.0;
+ c.weighty = 1.0;
+ frame.add(testCanvas, c);
+ frame.pack();
+ frame.setLocationRelativeTo(null);
+ frame.setVisible(true);
}
public static void testOffscreen() {
@@ -600,6 +694,7 @@ public static void testCompatibleImages(GraphicsConfiguration gconfig) {
public static void testVolatileImage() {
Image img = testCanvas.createVolatileImage(TESTWIDTH, TESTHEIGHT);
+ System.err.println("img="+img);
test(img, "Volatile");
}
@@ -620,42 +715,17 @@ public void paint(Graphics g) {
}
public static class TestCanvas extends Canvas {
- BufferedImage bimg;
public Dimension getPreferredSize() {
return new Dimension(TESTWIDTH, TESTHEIGHT);
}
public void paint(Graphics g) {
- if (bimg != null ||
- getWidth() < TESTWIDTH ||
- getHeight() < TESTHEIGHT)
- {
+ if (getWidth() < TESTWIDTH ||
+ getHeight() < TESTHEIGHT) {
return;
}
render((Graphics2D) g);
- Toolkit.getDefaultToolkit().sync();
- Point p = getLocationOnScreen();
- Rectangle r = new Rectangle(p.x, p.y, TESTWIDTH, TESTHEIGHT);
- try {
- bimg = new Robot().createScreenCapture(r);
- } catch (AWTException e) {
- e.printStackTrace();
- }
- synchronized (this) {
- notifyAll();
- }
- }
-
- public synchronized BufferedImage getImage() {
- while (bimg == null) {
- try {
- wait();
- } catch (InterruptedException e) {
- return null;
- }
- }
- return bimg;
- }
- }
+ }
+ }
}
From 01b363841a39e858628201adfa601ec5c8ffbba6 Mon Sep 17 00:00:00 2001
From: Phil Race
Date: Thu, 1 Oct 2026 20:39:42 +0000
Subject: [PATCH 15/98] 8385017: Null pointer dereference in
java.desktop/share/classes/com/sun/media/sound/ModelByteBuffer.java:204
Reviewed-by: kizune, serb
---
.../com/sun/media/sound/ModelByteBuffer.java | 7 ++++++-
.../media/sound/ModelByteBufferWavetable.java | 17 +++++++++++++----
.../sun/media/sound/SoftAbstractResampler.java | 3 +++
.../classes/com/sun/media/sound/SoftVoice.java | 13 ++++++++++---
4 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBuffer.java b/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBuffer.java
index 2476ff09bbc..0437a9f9556 100644
--- a/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBuffer.java
+++ b/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBuffer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -201,6 +201,9 @@ public ModelByteBuffer(File file, long offset, long len) {
public void writeTo(OutputStream out) throws IOException {
if (root.file != null && root.buffer == null) {
try (InputStream is = getInputStream()) {
+ if (is == null) {
+ throw new IOException("null stream");
+ }
is.transferTo(out);
}
} else
@@ -321,6 +324,8 @@ public void load() throws IOException {
buffer = new byte[(int) capacity()];
offset = 0;
dis.readFully(buffer);
+ } catch (NullPointerException npe) {
+ throw new IOException("input stream is null", npe);
}
}
diff --git a/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java b/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java
index bc8829d288c..ab12dad7ca5 100644
--- a/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java
+++ b/src/java.desktop/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -195,10 +195,14 @@ public AudioFormat getFormat() {
@Override
public AudioFloatInputStream openStream() {
- if (buffer == null)
+ if (buffer == null) {
return null;
+ }
if (format == null) {
InputStream is = buffer.getInputStream();
+ if (is == null) {
+ return null;
+ }
AudioInputStream ais = null;
try {
ais = AudioSystem.getAudioInputStream(is);
@@ -209,8 +213,12 @@ public AudioFloatInputStream openStream() {
return AudioFloatInputStream.getInputStream(ais);
}
if (buffer.array() == null) {
+ InputStream is = buffer.getInputStream();
+ if (is == null) {
+ return null;
+ }
return AudioFloatInputStream.getInputStream(new AudioInputStream(
- buffer.getInputStream(), format,
+ is, format,
buffer.capacity() / format.getFrameSize()));
}
if (buffer8 != null) {
@@ -237,7 +245,8 @@ public AudioFloatInputStream openStream() {
@Override
public int getChannels() {
- return getFormat().getChannels();
+ AudioFormat format = getFormat();
+ return (format != null) ? format.getChannels() : 1;
}
@Override
diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SoftAbstractResampler.java b/src/java.desktop/share/classes/com/sun/media/sound/SoftAbstractResampler.java
index ef9eac6dd03..ce04ee1272a 100644
--- a/src/java.desktop/share/classes/com/sun/media/sound/SoftAbstractResampler.java
+++ b/src/java.desktop/share/classes/com/sun/media/sound/SoftAbstractResampler.java
@@ -96,6 +96,9 @@ public void open(ModelWavetable osc, float outputsamplerate)
}
stream = osc.openStream();
+ if (stream == null) {
+ throw new IOException("null stream");
+ }
streampos = 0;
stream_eof = false;
pitchcorrection = osc.getPitchcorrection();
diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SoftVoice.java b/src/java.desktop/share/classes/com/sun/media/sound/SoftVoice.java
index 3808b263c4b..7f7642d005c 100644
--- a/src/java.desktop/share/classes/com/sun/media/sound/SoftVoice.java
+++ b/src/java.desktop/share/classes/com/sun/media/sound/SoftVoice.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -590,6 +590,8 @@ void processControlLogic() {
osc_stream.close();
} catch (IOException e) {
//e.printStackTrace();
+ } finally {
+ osc_stream = null;
}
if (stealer_channel != null) {
@@ -662,7 +664,9 @@ void processControlLogic() {
for (int i = 0; i < performer.ctrl_connections.length; i++)
processConnection(performer.ctrl_connections[i]);
- osc_stream.setPitch((float)co_osc_pitch[0]);
+ if (osc_stream != null) {
+ osc_stream.setPitch((float)co_osc_pitch[0]);
+ }
int filter_type = (int)co_filter_type[0];
double filter_freq;
@@ -829,7 +833,10 @@ void processAudioLogic(SoftAudioBuffer[] buffer) {
osc_buff[0] = buffer[SoftMainMixer.CHANNEL_LEFT_DRY].array();
if (nrofchannels != 1)
osc_buff[1] = buffer[SoftMainMixer.CHANNEL_RIGHT_DRY].array();
- int ret = osc_stream.read(osc_buff, 0, bufferlen);
+ int ret = -1;
+ if (osc_stream != null) {
+ ret = osc_stream.read(osc_buff, 0, bufferlen);
+ }
if (ret == -1) {
stopping = true;
return;
From 8de3be8411997635a8e382ac74199b4a58b5bb13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Du=C5=A1an=20B=C3=A1lek?=
Date: Fri, 2 Oct 2026 06:41:34 +0000
Subject: [PATCH 16/98] 8393242: jlink fails with "Multiple modules contain
non-empty package" for a non-package resource directory in more than one
module
Reviewed-by: alanb
---
.../jlink/internal/ImageResourcesTree.java | 8 +-
.../jlink/NonPackageResourceDirTest.java | 114 ++++++++++++++++++
2 files changed, 119 insertions(+), 3 deletions(-)
create mode 100644 test/jdk/tools/jlink/NonPackageResourceDirTest.java
diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java
index ab0809348ca..d323cc8ed39 100644
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java
@@ -26,6 +26,7 @@
import jdk.internal.jimage.ImageLocation;
import jdk.internal.jimage.ModuleLink;
+import jdk.internal.module.Checks;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -204,9 +205,10 @@ private void buildTree() {
}
// We've collected information for all "packages", including the root
- // (empty) package and anything under "META-INF". However, these should
- // not have entries in the "/packages" directory.
- packageToModules.keySet().removeIf(p -> p.isEmpty() || p.equals("META-INF") || p.startsWith("META-INF."));
+ // (empty) package and anything under non-package resource directories
+ // (e.g. "META-INF"). However, these should not have entries in the
+ // "/packages" directory.
+ packageToModules.keySet().removeIf(p -> !Checks.isPackageName(p));
packageToModules.forEach((pkgName, modLinks) -> {
// Merge multiple links for the same module.
List pkgModules = modLinks.stream()
diff --git a/test/jdk/tools/jlink/NonPackageResourceDirTest.java b/test/jdk/tools/jlink/NonPackageResourceDirTest.java
new file mode 100644
index 00000000000..9e4e16f3fb0
--- /dev/null
+++ b/test/jdk/tools/jlink/NonPackageResourceDirTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8393242
+ * @summary Test jlink with a non-package resource directory in several modules
+ * @library /test/lib
+ * @modules java.base/jdk.internal.module
+ * jdk.jlink
+ * jdk.jartool
+ * @run junit/othervm NonPackageResourceDirTest
+ */
+
+import java.lang.module.ModuleDescriptor;
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.spi.ToolProvider;
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.util.ModuleInfoWriter;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeAll;
+import static org.junit.jupiter.api.Assertions.*;
+
+class NonPackageResourceDirTest {
+
+ @BeforeAll
+ static void setup() throws Exception {
+ Path src = Files.createDirectory(Path.of(".").resolve("src"));
+ // Create module a containing
+ // module-info.class
+ // a/C.class
+ // OSGI-INF/MANIFEST.MF
+ String moduleName = "a";
+ ModuleDescriptor descriptor = ModuleDescriptor.newModule(moduleName)
+ .exports("a")
+ .build();
+ byte[] moduleInfo = ModuleInfoWriter.toBytes(descriptor);
+ Path dir = Files.createDirectory(Path.of(".").resolve(moduleName));
+ Files.write(dir.resolve("module-info.class"), moduleInfo);
+ Path srcA = Files.writeString(Files.createDirectory(src.resolve("a")).resolve("C.java"),
+ """
+ package a;
+ public class C {}
+ """);
+ ToolProvider javac = ToolProvider.findFirst("javac").orElseThrow();
+ javac.run(System.out, System.err, "-d", dir.toString(), srcA.toString());
+ Files.createFile(Files.createDirectory(dir.resolve("OSGI-INF")).resolve("MANIFEST.MF"));
+
+ // Create modular jar of a
+ ToolProvider jar = ToolProvider.findFirst("jar").orElseThrow();
+ jar.run(System.out, System.err, "--create", "--file", moduleName + ".jar", "-C", moduleName, ".");
+
+ // Create module b containing
+ // module-info.class
+ // b/C.class
+ // OSGI-INF/MANIFEST.MF
+ moduleName = "b";
+ descriptor = ModuleDescriptor.newModule(moduleName)
+ .exports("b")
+ .build();
+ moduleInfo = ModuleInfoWriter.toBytes(descriptor);
+ dir = Files.createDirectory(Path.of(".").resolve(moduleName));
+ Files.write(dir.resolve("module-info.class"), moduleInfo);
+ Path srcB = Files.writeString(Files.createDirectory(src.resolve("b")).resolve("C.java"),
+ """
+ package b;
+ public class C {}
+ """);
+ javac.run(System.out, System.err, "-d", dir.toString(), srcB.toString());
+ Files.createFile(Files.createDirectory(dir.resolve("OSGI-INF")).resolve("MANIFEST.MF"));
+
+ // Create modular jar of b
+ jar.run(System.out, System.err, "--create", "--file", moduleName + ".jar", "-C", moduleName, ".");
+ }
+
+ @Test
+ void testJavaValidate() throws Exception {
+ ProcessTools.executeProcess(ProcessTools.createTestJavaProcessBuilder(
+ "--module-path", "a.jar" + File.pathSeparator + "b.jar",
+ "--validate-modules")).shouldHaveExitValue(0);
+ }
+
+ @Test
+ void testJlink() throws Exception {
+ ToolProvider jlink = ToolProvider.findFirst("jlink").orElseThrow();
+ int res = jlink.run(System.out, System.err, "--module-path", "a.jar" + File.pathSeparator + "b.jar",
+ "--add-modules", "a,b", "--output", "image");
+ assertEquals(0, res);
+ }
+}
From d2064c5923d0787ad39da0116f8c552e49ddd5f9 Mon Sep 17 00:00:00 2001
From: Quan Anh Mai
Date: Fri, 2 Oct 2026 07:07:02 +0000
Subject: [PATCH 17/98] 8393231: C2: assert(old_raw_mem_proj != nullptr)
failed: should have found raw mem Proj
Reviewed-by: chagedorn, thartmann
---
src/hotspot/share/opto/cfgnode.cpp | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
index 18f6e21671a..fe6ccd7f23b 100644
--- a/src/hotspot/share/opto/cfgnode.cpp
+++ b/src/hotspot/share/opto/cfgnode.cpp
@@ -30,6 +30,7 @@
#include "opto/addnode.hpp"
#include "opto/castnode.hpp"
#include "opto/cfgnode.hpp"
+#include "opto/compile.hpp"
#include "opto/connode.hpp"
#include "opto/convertnode.hpp"
#include "opto/loopnode.hpp"
@@ -1094,9 +1095,15 @@ uint PhiNode::hash() const {
const Type* at = _adr_type;
return TypeNode::hash() + (at ? at->hash() : 0);
}
-bool PhiNode::cmp( const Node &n ) const {
- return TypeNode::cmp(n) && _adr_type == ((PhiNode&)n)._adr_type;
+
+bool PhiNode::cmp(const Node& n) const {
+ const PhiNode& other = static_cast(n);
+ if (!TypeNode::cmp(other) || _adr_type != other._adr_type) {
+ return false;
+ }
+ return _adr_type != TypePtr::BOTTOM || _excluded_idx == other._excluded_idx;
}
+
static inline
const TypePtr* flatten_phi_adr_type(const TypePtr* at) {
if (at == nullptr || at == TypePtr::BOTTOM) return at;
@@ -3479,6 +3486,22 @@ void PhiNode::dump_spec(outputStream *st) const {
if (is_tripcount(T_INT) || is_tripcount(T_LONG)) {
st->print(" #tripcount");
}
+ if (type() == Type::MEMORY && adr_type() == TypePtr::BOTTOM && _excluded_idx != nullptr) {
+ st->print(" #excluded_alias_idx:{");
+ bool first = true;
+ for (int alias_idx = Compile::AliasIdxRaw; alias_idx < Compile::current()->num_alias_types(); alias_idx++) {
+ if (_excluded_idx->contains(alias_idx)) {
+ if (first) {
+ first = false;
+ } else {
+ st->print(",");
+ }
+
+ st->print("%d", alias_idx);
+ }
+ }
+ st->print("}");
+ }
}
#endif
From 740639a4981feb0f046058303567d204c154bb87 Mon Sep 17 00:00:00 2001
From: Roland Westrelin
Date: Fri, 2 Oct 2026 07:29:10 +0000
Subject: [PATCH 18/98] 8391971: C2 hits assert because split-If does not
correctly handle EncodeISOArray
Reviewed-by: qamai, thartmann
---
src/hotspot/share/opto/loopnode.hpp | 3 +
src/hotspot/share/opto/split_if.cpp | 38 ++++++++++
.../splitif/TestSplitIfSCMemProj.java | 73 +++++++++++++++++++
3 files changed, 114 insertions(+)
create mode 100644 test/hotspot/jtreg/compiler/splitif/TestSplitIfSCMemProj.java
diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp
index dc4383b6917..54ea9c75f3f 100644
--- a/src/hotspot/share/opto/loopnode.hpp
+++ b/src/hotspot/share/opto/loopnode.hpp
@@ -1792,6 +1792,9 @@ class PhaseIdealLoop : public PhaseTransform {
// Split Node 'n' through merge point
RegionNode* split_thru_region(Node* n, RegionNode* region);
+
+ static ProjNode* unique_scmem_proj_if_any(Node* n);
+
// Split Node 'n' through merge point if there is enough win.
Node *split_thru_phi( Node *n, Node *region, int policy );
// Found an If getting its condition-code input from a Phi in the
diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp
index 84a53211d09..284752b87af 100644
--- a/src/hotspot/share/opto/split_if.cpp
+++ b/src/hotspot/share/opto/split_if.cpp
@@ -69,6 +69,20 @@ RegionNode* PhaseIdealLoop::split_thru_region(Node* n, RegionNode* region) {
return r;
}
+ProjNode* PhaseIdealLoop::unique_scmem_proj_if_any(Node* n) {
+ ProjNode* proj = nullptr;
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ Node* u = n->fast_out(i);
+ if (u->Opcode() == Op_SCMemProj) {
+ assert(proj == nullptr, "only one SCMemProj");
+ proj = u->as_Proj();
+ } else {
+ assert(!u->is_Proj(), "we can't split nodes with Proj uses other than SCMemProj");
+ }
+ }
+ return proj;
+}
+
//------------------------------split_up---------------------------------------
// Split block-local op up through the phis to empty the current block
bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) {
@@ -155,6 +169,15 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) {
tty->print_cr(" Splitting up: %d %s", n->_idx, n->Name());
}
#endif
+ // If n has a SCMemProj use, pushing n through the Phi and then the SCMemProj (which has then a Phi input) through the
+ // Phi doesn't work as split if needs the adr_type of an SCMemProj to create its Phi which Proj::addr_type() gets from
+ // its input: that works as long as the input of the SCMemProj is n but not if it's a Phi. Prepare the Phi for the
+ // SCMemProj here before n is cloned.
+ ProjNode* mem_proj = unique_scmem_proj_if_any(n);
+ Node* phi_mem_proj = nullptr;
+ if (mem_proj != nullptr) {
+ phi_mem_proj = PhiNode::make_blank(blk1, mem_proj);
+ }
Node *phi = PhiNode::make_blank(blk1, n);
for( uint j = 1; j < blk1->req(); j++ ) {
Node *x = n->clone();
@@ -178,6 +201,21 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) {
// Remove cloned-up value from optimizer; use phi instead
_igvn.replace_node( n, phi );
+ if (mem_proj != nullptr) {
+ for (uint j = 1; j < blk1->req(); j++) {
+ Node* x = mem_proj->clone();
+ x->set_req(0, phi->in(j));
+ register_new_node(x, blk1->in(j));
+ phi_mem_proj->init_req(j, x);
+ }
+ // Announce phi to optimizer
+ register_new_node(phi_mem_proj, blk1);
+
+ // Remove cloned-up value from optimizer; use phi instead
+ _igvn.replace_node(mem_proj, phi_mem_proj);
+ }
+ assert(!phi->has_out_with(Op_SCMemProj), "only works with a single SCMemProj use");
+
// (There used to be a self-recursive call to split_up() here,
// but it is not needed. All necessary forward walking is done
// by do_split_if() below.)
diff --git a/test/hotspot/jtreg/compiler/splitif/TestSplitIfSCMemProj.java b/test/hotspot/jtreg/compiler/splitif/TestSplitIfSCMemProj.java
new file mode 100644
index 00000000000..a4d9bb4bc2e
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/splitif/TestSplitIfSCMemProj.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8391971
+ * @modules java.base/java.lang:+open
+ * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:CompileCommand=compileonly,${test.main.class}::test ${test.main.class}
+ * @run main ${test.main.class}
+ */
+
+import java.lang.invoke.*;
+
+public class TestSplitIfSCMemProj {
+ static final MethodHandle MH;
+ static int x = 0;
+
+ static {
+ try {
+ Class> c = Class.forName("java.lang.StringCoding");
+ MethodType mt = MethodType.methodType(int.class, byte[].class, int.class, byte[].class, int.class, int.class);
+ MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(c, MethodHandles.lookup());
+ MethodHandle mh;
+ try {
+ mh = lookup.findStatic(c, "encodeISOArray0", mt);
+ } catch (NoSuchMethodException exception) {
+ // Older JDKs
+ mh = lookup.findStatic(c, "implEncodeISOArray", mt);
+ }
+ MH = mh;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static void test(boolean b) throws Throwable {
+ byte[] src = new byte[2];
+ byte[] dst = new byte[1];
+ if (b) {
+ x = 42;
+ }
+ int res = (int)MH.invokeExact(src, 0, dst, 0, 1);
+ if (b) {
+ x = 43;
+ }
+ }
+
+ public static void main(String[] args) throws Throwable {
+ for (int i = 0; i < 50_000; i++) {
+ test((i % 2) == 0);
+ }
+ }
+}
From d6d6c8fc358a43ed58bc498d523eac7828f1dbff Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev
Date: Fri, 2 Oct 2026 08:48:15 +0000
Subject: [PATCH 19/98] 8392841: C1: Failed OSR compilation should not block
future normal compilation
Reviewed-by: mhaessig, thartmann, kvn
---
src/hotspot/share/oops/method.cpp | 1 +
src/hotspot/share/oops/method.hpp | 6 +-----
src/hotspot/share/oops/methodFlags.hpp | 13 +++++++------
src/hotspot/share/prims/whitebox.cpp | 1 +
4 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp
index dfbef61dd3f..ce76c1dd82f 100644
--- a/src/hotspot/share/oops/method.cpp
+++ b/src/hotspot/share/oops/method.cpp
@@ -1303,6 +1303,7 @@ void Method::remove_unshareable_flags() {
set_is_not_c2_compilable(false);
set_is_not_c1_compilable(false);
set_is_not_c2_osr_compilable(false);
+ set_is_not_c1_osr_compilable(false);
set_on_stack_flag(false);
set_has_scalarized_args(false);
}
diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp
index 8c0f9affa60..10a6fd9d8ac 100644
--- a/src/hotspot/share/oops/method.hpp
+++ b/src/hotspot/share/oops/method.hpp
@@ -837,13 +837,9 @@ class Method : public Metadata {
void clear_is_not_c1_compilable() { set_is_not_c1_compilable(false); }
void clear_is_not_c2_compilable() { set_is_not_c2_compilable(false); }
+ void clear_is_not_c1_osr_compilable() { set_is_not_c1_osr_compilable(false); }
void clear_is_not_c2_osr_compilable() { set_is_not_c2_osr_compilable(false); }
- // not_c1_osr_compilable == not_c1_compilable
- bool is_not_c1_osr_compilable() const { return is_not_c1_compilable(); }
- void set_is_not_c1_osr_compilable() { set_is_not_c1_compilable(); }
- void clear_is_not_c1_osr_compilable() { clear_is_not_c1_compilable(); }
-
// Background compilation support
void clear_queued_for_compilation() { set_queued_for_compilation(false); }
diff --git a/src/hotspot/share/oops/methodFlags.hpp b/src/hotspot/share/oops/methodFlags.hpp
index f023fa743bb..e8ed9853884 100644
--- a/src/hotspot/share/oops/methodFlags.hpp
+++ b/src/hotspot/share/oops/methodFlags.hpp
@@ -52,12 +52,13 @@ class MethodFlags {
status(is_not_c2_compilable , 1 << 8) \
status(is_not_c1_compilable , 1 << 9) \
status(is_not_c2_osr_compilable , 1 << 10) \
- status(force_inline , 1 << 11) /* Annotations but also set/reset at runtime */ \
- status(dont_inline , 1 << 12) \
- status(has_loops_flag , 1 << 13) /* Method has loops */ \
- status(has_loops_flag_init , 1 << 14) /* The loop flag has been initialized */ \
- status(on_stack_flag , 1 << 15) /* RedefineClasses support to keep Metadata from being cleaned */ \
- status(has_scalarized_args , 1 << 16) \
+ status(is_not_c1_osr_compilable , 1 << 11) \
+ status(force_inline , 1 << 12) /* Annotations but also set/reset at runtime */ \
+ status(dont_inline , 1 << 13) \
+ status(has_loops_flag , 1 << 14) /* Method has loops */ \
+ status(has_loops_flag_init , 1 << 15) /* The loop flag has been initialized */ \
+ status(on_stack_flag , 1 << 16) /* RedefineClasses support to keep Metadata from being cleaned */ \
+ status(has_scalarized_args , 1 << 17) \
/* end of list */
#define M_STATUS_ENUM_NAME(name, value) _misc_##name = value,
diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp
index c3d419c62d2..0963ba23bf7 100644
--- a/src/hotspot/share/prims/whitebox.cpp
+++ b/src/hotspot/share/prims/whitebox.cpp
@@ -1288,6 +1288,7 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
mh->clear_is_not_c1_compilable();
mh->clear_is_not_c2_compilable();
+ mh->clear_is_not_c1_osr_compilable();
mh->clear_is_not_c2_osr_compilable();
NOT_PRODUCT(mh->set_compiled_invocation_count(0));
if (mcs != nullptr) {
From 86e538937adbbcf8c61b1394ede022f5664426b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johan=20Sj=C3=B6len?=
Date: Fri, 2 Oct 2026 10:40:09 +0000
Subject: [PATCH 20/98] 8392815:
SystemDictionaryShared::check_linking_constraints can avoid more unnecessary
vtable/itable reinitializations
Reviewed-by: fbredberg, cnorrbin, iklam, matsaave
---
src/hotspot/share/classfile/systemDictionaryShared.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp
index ea9747f7240..67c64a5c9a2 100644
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
@@ -1272,8 +1272,8 @@ bool SystemDictionaryShared::check_linking_constraints(Thread* current, Instance
log.print(" succeeded]");
}
}
- return true; // for all recorded constraints added successfully.
}
+ return true; // Recorded constraints, if any, have all been added successfully.
}
if (log.is_enabled()) {
ResourceMark rm(current);
From bd9e82618c6415eaa16269e02a78741bb34d1566 Mon Sep 17 00:00:00 2001
From: Lee Jiwon
Date: Fri, 2 Oct 2026 11:20:43 +0000
Subject: [PATCH 21/98] 8392709: (fc) FileChannelImpl.write(ByteBuffer src,
long position) checks FileReadEvent.enabled()
Reviewed-by: vyazici
---
.../classes/sun/nio/ch/FileChannelImpl.java | 2 +-
.../jfr/event/io/TestFileChannelEvents.java | 83 ++++++++++++++++++-
2 files changed, 82 insertions(+), 3 deletions(-)
diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
index a440e646026..5d0dfd38757 100644
--- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
+++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
@@ -1214,7 +1214,7 @@ private int readInternal(ByteBuffer dst, long position) throws IOException {
@Override
public int write(ByteBuffer src, long position) throws IOException {
- if (jfrTracing && FileReadEvent.enabled()) {
+ if (jfrTracing && FileWriteEvent.enabled()) {
return traceImplWrite(src, position);
}
return implWrite(src, position);
diff --git a/test/jdk/jdk/jfr/event/io/TestFileChannelEvents.java b/test/jdk/jdk/jfr/event/io/TestFileChannelEvents.java
index 490e16d3e52..5907fc00d20 100644
--- a/test/jdk/jdk/jfr/event/io/TestFileChannelEvents.java
+++ b/test/jdk/jdk/jfr/event/io/TestFileChannelEvents.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@
/**
* @test
+ * @bug 8199712 8392709
* @requires vm.flagless
* @requires vm.hasJFR
* @library /test/lib /test/jdk
@@ -47,6 +48,11 @@
*/
public class TestFileChannelEvents {
public static void main(String[] args) throws Throwable {
+ testReadWriteAndForceEvents();
+ testNoInterference();
+ }
+
+ private static void testReadWriteAndForceEvents() throws Throwable {
File tmp = Utils.createTempFile("TestFileChannelEvents", ".tmp").toFile();
try (Recording recording = new Recording()) {
List expectedEvents = new ArrayList<>();
@@ -108,7 +114,7 @@ public static void main(String[] args) throws Throwable {
ch.position(ch.size());
bufA.clear();
size = ch.read(bufA);
- assertEquals(size, -1L, "Expected size -1 when read at EOF");
+ assertEquals(-1L, size, "Expected size -1 when read at EOF");
expectedEvents.add(IOEvent.createFileReadEvent(size, tmp));
ch.close();
@@ -118,4 +124,77 @@ public static void main(String[] args) throws Throwable {
}
}
}
+
+ // Tests that FileRead and FileWrite events are recorded independently
+ // when the other event type is disabled.
+ private static void testNoInterference() throws Throwable {
+ testNoInterferenceCase("positional write", IOEvent.EVENT_FILE_WRITE, IOEvent.EVENT_FILE_READ,
+ (file, ch, buffer, other) -> {
+ long size = ch.write(buffer, 0);
+ assertEquals(10L, size, "Unexpected size for positional write");
+ return IOEvent.createFileWriteEvent(size, file);
+ });
+
+ testNoInterferenceCase("current-position write", IOEvent.EVENT_FILE_WRITE, IOEvent.EVENT_FILE_READ,
+ (file, ch, buffer, other) -> {
+ long size = ch.write(buffer);
+ assertEquals(10L, size, "Unexpected size for current-position write");
+ return IOEvent.createFileWriteEvent(size, file);
+ });
+
+ testNoInterferenceCase("gathering write", IOEvent.EVENT_FILE_WRITE, IOEvent.EVENT_FILE_READ,
+ (file, ch, buffer, other) -> {
+ long size = ch.write(new ByteBuffer[] { buffer, other });
+ assertEquals(20L, size, "Unexpected size for gathering write");
+ return IOEvent.createFileWriteEvent(size, file);
+ });
+
+ testNoInterferenceCase("positional read", IOEvent.EVENT_FILE_READ, IOEvent.EVENT_FILE_WRITE,
+ (file, ch, buffer, other) -> {
+ long size = ch.read(buffer, 0);
+ assertEquals(10L, size, "Unexpected size for positional read");
+ return IOEvent.createFileReadEvent(size, file);
+ });
+
+ testNoInterferenceCase("current-position read", IOEvent.EVENT_FILE_READ, IOEvent.EVENT_FILE_WRITE,
+ (file, ch, buffer, other) -> {
+ long size = ch.read(buffer);
+ assertEquals(10L, size, "Unexpected size for current-position read");
+ return IOEvent.createFileReadEvent(size, file);
+ });
+
+ testNoInterferenceCase("scattering read", IOEvent.EVENT_FILE_READ, IOEvent.EVENT_FILE_WRITE,
+ (file, ch, buffer, other) -> {
+ long size = ch.read(new ByteBuffer[] { buffer, other });
+ assertEquals(20L, size, "Unexpected size for scattering read");
+ return IOEvent.createFileReadEvent(size, file);
+ });
+ }
+
+ private static void testNoInterferenceCase(String name, String enabledEvent, String disabledEvent,
+ FileChannelOperation operation) throws Throwable {
+ System.out.println("Testing " + name + " with " + enabledEvent
+ + " enabled and " + disabledEvent + " disabled");
+ File file = Utils.createTempFile("TestFileChannelEvents", ".tmp").toFile();
+ try (RandomAccessFile rf = new RandomAccessFile(file, "rw");
+ FileChannel ch = rf.getChannel();
+ Recording recording = new Recording()) {
+ rf.writeBytes("1234567890abcdefghij");
+ ch.position(0);
+ ByteBuffer buffer = ByteBuffer.allocateDirect(10);
+ ByteBuffer other = ByteBuffer.allocateDirect(10);
+
+ recording.disable(disabledEvent);
+ recording.enable(enabledEvent).withThreshold(Duration.ofMillis(0));
+ recording.start();
+ IOEvent expectedEvent = operation.execute(file, ch, buffer, other);
+ recording.stop();
+ IOHelper.verifyEquals(Events.fromRecording(recording), List.of(expectedEvent));
+ }
+ }
+
+ @FunctionalInterface
+ private interface FileChannelOperation {
+ IOEvent execute(File file, FileChannel ch, ByteBuffer buffer, ByteBuffer other) throws Exception;
+ }
}
From 4464e946a802eb83b54f9a97bbead0e769a7fff5 Mon Sep 17 00:00:00 2001
From: Erik Gahlin
Date: Fri, 2 Oct 2026 12:38:30 +0000
Subject: [PATCH 22/98] 8393377: JFR: Improve documentation for 'jfr query'
Reviewed-by: mgronlun
---
.../jdk/jfr/internal/query/QueryPrinter.java | 25 +++++++++++++------
.../classes/jdk/jfr/internal/tool/Query.java | 4 ++-
2 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java
index 9d0ce279abd..c60432ca4d6 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -245,13 +245,13 @@ public static String getGrammarText() {
column ::= "COLUMN" text ("," text)*
format ::= "FORMAT" formatter ("," formatter)*
formatter ::= property (";" property)*
- select ::= "SELECT" "*" | expression ("," expression)*
+ select ::= "SELECT" ("*" | expression ("," expression)*)
expression ::= (aggregator | field) [alias]
aggregator ::= function "(" (field | "*") ")"
alias ::= "AS" symbol
from ::= "FROM" source ("," source)*
source ::= type [alias]
- where ::= condition ("AND" condition)*
+ where ::= "WHERE" condition ("AND" condition)*
condition ::= field "=" text
groupBy ::= "GROUP BY" field ("," field)*
orderBy ::= "ORDER BY" orderField ("," orderField)*
@@ -263,10 +263,14 @@ public static String getGrammarText() {
- symbol, alphabetic characters
- type, the event type name, for example SystemGC. To avoid ambiguity,
the name may be qualified, for example jdk.SystemGC
- - field, the event field name, for example stackTrace.
+ - field, an event field name or a dot-separated name to a nested
+ field, for example, stackTrace or stackTrace.topFrame.method.type.
To avoid ambiguity, the name may be qualified, for example
jdk.SystemGC.stackTrace. A type alias declared in a FROM clause
- can be used instead of the type, for example S.eventThread
+ can be used instead of the type, for example S.eventThread.
+ To select the same field from a subset of event types, put
+ the event types or aliases in brackets and separate them by '|',
+ for example, [A|B].duration.
- function, determines how fields are aggregated when using GROUP BY.
Aggregate functions are:
AVG: The numeric average
@@ -289,14 +293,19 @@ public static String getGrammarText() {
- property, any of the following:
none No formatting for the column
cell-height: Maximum height of a table cell
- missing:whitespace Replace missing values (N/A) with blank space
+ missing: Replaces missing values (N/A) with the specified text,
+ for example "null-bootstrap". Use missing:whitespace to replace with
+ blank space.
normalized Normalize values between 0 and 1.0 for the column
truncate-beginning if value can't fit a table cell, remove the first characters
truncate-end if value can't fit a table cell, remove the last characters
If no value exist, or a numeric value can't be aggregated, the result is 'N/A',
- unless missing:whitespace is used. The top frame of a stack trace can be referred'
- to as stackTrace.topFrame. When multiple event types are specified in a FROM clause,
+ unless missing: is used. The top frame of a stack trace can be referred
+ to as stackTrace.topFrame, the name of an event type as eventType.name, and
+ its label as eventType.label.
+
+ When multiple event types are specified in a FROM clause,
the union of the event types are used (not the cartesian product)
To see all available events, use the query '"SHOW EVENTS"'. To see all fields for
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java
index 280bef55af4..c8cc0b5cec2 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -94,6 +94,8 @@ public void displayOptionUsage(PrintStream p) {
p.println(" GROUP BY gcId");
p.println(" ORDER BY gcId\" recording.jfr");
p.println();
+ p.println(" To see more queries and their output: $ jfr view --verbose all-views recording.jfr");
+ p.println();
p.println("************************************ WARNING ******************************************");
p.println("The query command is only available in debug builds and is targeted towards OpenJDK");
p.println("developers. The tool may be removed or its syntax changed at any time.");
From d13fcae6b732900ff444d1ae72a238f3c0140d8e Mon Sep 17 00:00:00 2001
From: Erik Gahlin
Date: Fri, 2 Oct 2026 12:45:54 +0000
Subject: [PATCH 23/98] 8393171: JFR: -XX:StartFlightRecording can't handle
leading space for jfc options
Reviewed-by: mgronlun
---
.../classes/jdk/jfr/internal/jfc/model/Utilities.java | 7 ++++---
test/jdk/jdk/jfr/tool/TestConfigure.java | 5 ++++-
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Utilities.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Utilities.java
index 281a0c57949..223c383aff5 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Utilities.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Utilities.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -100,6 +100,7 @@ static void checkValid(String value, Object... valid) {
}
static String parseTimespan(String s) {
+ s = s.strip();
StringBuilder sb = new StringBuilder();
try {
for (TimespanUnit timespan : TimespanUnit.values()) {
@@ -118,7 +119,7 @@ static String parseTimespan(String s) {
}
private static String parseForUnit(String s, String unit) {
- String number = s.trim().substring(0, s.length() - unit.length());
- return Long.parseLong(number.trim()) + " " + unit;
+ String number = s.substring(0, s.length() - unit.length());
+ return Long.parseLong(number.strip()) + " " + unit;
}
}
diff --git a/test/jdk/jdk/jfr/tool/TestConfigure.java b/test/jdk/jdk/jfr/tool/TestConfigure.java
index 404c657fd98..2171ea640ab 100644
--- a/test/jdk/jdk/jfr/tool/TestConfigure.java
+++ b/test/jdk/jdk/jfr/tool/TestConfigure.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -108,6 +108,9 @@ private static void testTimespan() throws Throwable {
expected.put("com.example.Lion#period", "3 s");
aseertEqual(outputSetting, expected);
+
+ OutputAnalyzer o = jfrConfigure("locking-threshold= 20ms ");
+ o.shouldHaveExitValue(0);
}
private static void testUnification() throws Throwable {
From b15e0c1d96d6645aa9e7ae221027b48f846e83e8 Mon Sep 17 00:00:00 2001
From: Gui Cao
Date: Fri, 2 Oct 2026 13:11:53 +0000
Subject: [PATCH 24/98] 8393184: RISC-V: Use compiler atomic memory ordering
for add and xchg
Reviewed-by: ayang, fyang, gli
---
.../linux_riscv/atomicAccess_linux_riscv.hpp | 82 +++++++++++--------
1 file changed, 47 insertions(+), 35 deletions(-)
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 81cd2c51c65..07caf1774d9 100644
--- a/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp
+++ b/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -30,8 +30,9 @@
// Implementation of class AtomicAccess
-// Note that memory_order_conservative requires a full barrier after atomic stores.
-// See https://patchwork.kernel.org/patch/3575821/
+// Note that memory_order_conservative requires a strong two-way barrier.
+// For 32- and 64-bit add and xchg that barrier is provided by an explicit
+// AMO with .aqrl. Cmpxchg still uses explicit full barriers.
#if defined(__clang_major__)
#define FULL_COMPILER_ATOMIC_SUPPORT
@@ -42,31 +43,41 @@
template
struct AtomicAccess::PlatformAdd {
template
- D add_then_fetch(D volatile* dest, I add_value, atomic_memory_order order) const {
-
-#ifndef FULL_COMPILER_ATOMIC_SUPPORT
- // If we add add and fetch for sub word and are using older compiler
- // it must be added here due to not using lib atomic.
- static_assert(byte_size >= 4);
-#endif
+ D fetch_then_add(D volatile* dest, I add_value, atomic_memory_order order) const;
- if (order != memory_order_relaxed) {
- FULL_MEM_BARRIER;
- }
+ template
+ D add_then_fetch(D volatile* dest, I add_value, atomic_memory_order order) const {
+ D value = fetch_then_add(dest, add_value, order) + add_value;
+ return value;
+ }
+};
- D res = __atomic_add_fetch(dest, add_value, __ATOMIC_RELAXED);
+template
+template
+inline D AtomicAccess::PlatformAdd::fetch_then_add(D volatile* dest, I add_value,
+ atomic_memory_order order) const {
+ static_assert(byte_size == sizeof(D));
+ static_assert(byte_size == sizeof(I));
+ static_assert(byte_size == 4 || byte_size == 8);
- if (order != memory_order_relaxed) {
- FULL_MEM_BARRIER;
- }
- return res;
+ if (order == memory_order_relaxed) {
+ return __atomic_fetch_add(dest, add_value, __ATOMIC_RELAXED);
}
- template
- D fetch_then_add(D volatile* dest, I add_value, atomic_memory_order order) const {
- return add_then_fetch(dest, add_value, order) - add_value;
+ D old_value;
+ if constexpr (byte_size == 4) {
+ __asm__ __volatile__ ("amoadd.w.aqrl %0, %2, %1"
+ : "=r" (old_value), "+A" (*dest)
+ : "r" (add_value)
+ : "memory");
+ } else {
+ __asm__ __volatile__ ("amoadd.d.aqrl %0, %2, %1"
+ : "=r" (old_value), "+A" (*dest)
+ : "r" (add_value)
+ : "memory");
}
-};
+ return old_value;
+}
#ifndef FULL_COMPILER_ATOMIC_SUPPORT
template<>
@@ -160,25 +171,26 @@ template
inline T AtomicAccess::PlatformXchg::operator()(T volatile* dest,
T exchange_value,
atomic_memory_order order) const {
-#ifndef FULL_COMPILER_ATOMIC_SUPPORT
- // If we add xchg for sub word and are using older compiler
- // it must be added here due to not using lib atomic.
- static_assert(byte_size >= 4);
-#endif
-
static_assert(byte_size == sizeof(T));
static_assert(byte_size == 4 || byte_size == 8);
- if (order != memory_order_relaxed) {
- FULL_MEM_BARRIER;
+ if (order == memory_order_relaxed) {
+ return __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELAXED);
}
- T res = __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELAXED);
-
- if (order != memory_order_relaxed) {
- FULL_MEM_BARRIER;
+ T old_value;
+ if constexpr (byte_size == 4) {
+ __asm__ __volatile__ ("amoswap.w.aqrl %0, %2, %1"
+ : "=r" (old_value), "+A" (*dest)
+ : "r" (exchange_value)
+ : "memory");
+ } else {
+ __asm__ __volatile__ ("amoswap.d.aqrl %0, %2, %1"
+ : "=r" (old_value), "+A" (*dest)
+ : "r" (exchange_value)
+ : "memory");
}
- return res;
+ return old_value;
}
// __attribute__((unused)) on dest is to get rid of spurious GCC warnings.
From 5c097cf61ef42078c04dc6e238c23459a41e111d Mon Sep 17 00:00:00 2001
From: Gui Cao
Date: Fri, 2 Oct 2026 13:47:44 +0000
Subject: [PATCH 25/98] 8392856: RISC-V: Remove redundant register copy in
narrow-value Zacas cmpxchg
Reviewed-by: gli, fyang, ayang
---
src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
index 8295f9f15a4..6e6ca69da08 100644
--- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
@@ -4643,7 +4643,7 @@ void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected,
// Or in the new value to create complete new value.
orr(scratch0, scratch0, new_val);
- mv(scratch1, result); // save our expected value
+ // scratch1 holds the expected word.
atomic_cas(result, scratch0, aligned_addr, operand_size::int32, acquire, release);
bne(scratch1, result, retry);
} else {
@@ -4726,7 +4726,7 @@ void MacroAssembler::weak_cmpxchg_narrow_value(Register addr, Register expected,
// Or in the new value to create complete new value.
orr(scratch0, scratch0, new_val);
- mv(scratch1, result); // save our expected value
+ // scratch1 holds the expected word.
atomic_cas(result, scratch0, aligned_addr, operand_size::int32, acquire, release);
bne(scratch1, result, fail); // This weak, so just bail-out.
} else {
From e90e46919999fb8e65140efe2d9bb2a870ec99a6 Mon Sep 17 00:00:00 2001
From: Vladimir Kozlov
Date: Fri, 2 Oct 2026 14:41:23 +0000
Subject: [PATCH 26/98] 8393446: [Valhalla] The assert added by JDK-8389623 is
too strong
Reviewed-by: thartmann, roland
---
src/hotspot/share/opto/cfgnode.cpp | 3 +-
.../valhalla/valuetypes/TestNullPtrPhi.java | 80 +++++++++++++++++++
2 files changed, 82 insertions(+), 1 deletion(-)
create mode 100644 test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullPtrPhi.java
diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
index fe6ccd7f23b..9fdbb72c131 100644
--- a/src/hotspot/share/opto/cfgnode.cpp
+++ b/src/hotspot/share/opto/cfgnode.cpp
@@ -2919,7 +2919,8 @@ class PushValueTypeDown {
for (int i = _nodes_from_phi.size() - 1; i >= 0; i--) {
Node* n = _nodes_from_phi.at(i);
if (!n->is_ValueType()) {
- assert(!n->is_Phi() || n->bottom_type()->make_oopptr() != nullptr, "broken graph");
+ assert(!n->is_Phi() || _phase->type(n)->is_zero_type() ||
+ n->bottom_type()->make_oopptr() != nullptr, "broken graph");
_nodes_from_phi.remove(i);
}
}
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullPtrPhi.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullPtrPhi.java
new file mode 100644
index 00000000000..b5cd14a061e
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullPtrPhi.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8393446
+ * @summary [Valhalla] The assert added by JDK-8389623 is too strong
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * @run main/othervm -XX:CompileCommand=compileonly,${test.main.class}::test -Xbatch
+ * ${test.main.class}
+ */
+
+package compiler.valhalla.valuetypes;
+
+public class TestNullPtrPhi {
+
+ static value class Val {}
+
+ interface SomeObject {
+ Object val();
+ }
+
+ // To avoid creating new exception on each call.
+ static final RuntimeException EXCEPTION = new RuntimeException();
+
+ static final class NotValue implements SomeObject {
+ public Object val() {
+ throw EXCEPTION;
+ }
+ }
+
+ static final class NotNullValue implements SomeObject {
+ public Object val() {
+ return new Val();
+ }
+ }
+
+ public static void main(String[] args) {
+ SomeObject notVal = new NotValue();
+ SomeObject notNullVal = new NotNullValue();
+ for (int i = 0; i < 20_000; i++) {
+ boolean notNull = (i & 1) == 0;
+ Object result = test(notNull ? notNullVal : notVal);
+ if (notNull != (result != null)) {
+ throw new RuntimeException("wrong result");
+ }
+ }
+ }
+
+ static Object test(SomeObject obj) {
+ Object result = null;
+ try {
+ result = obj.val();
+ } catch (Throwable t) {
+ // Keep result == null
+ }
+ return result;
+ }
+}
From ac4da2a1d77bba952b0066608b748c37a923a6e6 Mon Sep 17 00:00:00 2001
From: Erik Gahlin
Date: Fri, 2 Oct 2026 16:31:17 +0000
Subject: [PATCH 27/98] 8392198: JFR: JFR.stop again allows a missing recording
name
Reviewed-by: mgronlun
---
src/jdk.jcmd/share/man/jcmd.md | 5 +-
.../jdk/jfr/internal/dcmd/DCmdStop.java | 8 +++-
.../jdk/jfr/jcmd/TestJcmdStopMissingName.java | 47 +++++++++++++++++++
3 files changed, 56 insertions(+), 4 deletions(-)
create mode 100644 test/jdk/jdk/jfr/jcmd/TestJcmdStopMissingName.java
diff --git a/src/jdk.jcmd/share/man/jcmd.md b/src/jdk.jcmd/share/man/jcmd.md
index 97e7385138b..00813bad360 100644
--- a/src/jdk.jcmd/share/man/jcmd.md
+++ b/src/jdk.jcmd/share/man/jcmd.md
@@ -509,7 +509,7 @@ The following commands are available:
**Note:**
The *options* must be specified using either *key* or *key*`=`*value*
- syntax. If no parameters are entered, then no recording is stopped.
+ syntax.
*options*:
@@ -519,7 +519,8 @@ The following commands are available:
timestamp, respectively. If no path is provided, the data from the
recording is discarded. (FILE, no default value)
- - `name`: (Optional) Name of the recording (STRING, no default value)
+ - `name`: Name of the recording. Use `JFR.check` to list the names of
+ the running recordings. (STRING, no default value)
`JFR.view` \[*options*\]
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java
index cda6a03e596..5d00534e83d 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,9 @@ final class DCmdStop extends AbstractDCmd {
@Override
protected void execute(ArgumentParser parser) throws DCmdException {
parser.checkUnknownArguments();
+ if (!parser.checkMandatory()) {
+ throw new DCmdException("Missing mandatory argument 'name'. Use JFR.check to list recording names.");
+ }
String name = parser.getOption("name");
String filename = parser.getOption("filename");
try {
@@ -85,7 +88,8 @@ public String[] getHelp() {
Note: If a path is given, '%%p' in the path will be replaced by the PID,
and '%%t' will be replaced by the time in 'yyyy_MM_dd_HH_mm_ss' format.
- name Name of the recording (STRING, no default value)
+ name (Mandatory) Name of the recording. Use JFR.check to list the names of the
+ running recordings. (STRING, no default value)
Options must be specified using the or = syntax.
diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdStopMissingName.java b/test/jdk/jdk/jfr/jcmd/TestJcmdStopMissingName.java
new file mode 100644
index 00000000000..063dca7c433
--- /dev/null
+++ b/test/jdk/jdk/jfr/jcmd/TestJcmdStopMissingName.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jcmd;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+/**
+ * @test
+ * @summary Verify JFR.stop reports an error when the name parameter is missing
+ * @requires vm.flagless
+ * @requires vm.hasJFR
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.jfr.jcmd.TestJcmdStopMissingName
+ */
+public class TestJcmdStopMissingName {
+ public static void main(String[] args) throws Exception {
+ String name = "foo";
+ OutputAnalyzer output = JcmdHelper.jcmd("JFR.start", "name=" + name);
+ JcmdAsserts.assertRecordingHasStarted(output);
+ JcmdHelper.waitUntilRunning(name);
+ output = JcmdHelper.jcmd("JFR.stop");
+ output.shouldContain("Missing mandatory argument 'name'. Use JFR.check to list recording names.");
+ JcmdHelper.assertRecordingIsRunning(name);
+ JcmdHelper.stopAndCheck(name);
+ }
+}
From 59b2293abc5bb4db9ff0fe4958dd3e7c08911eab Mon Sep 17 00:00:00 2001
From: Patrick Fontanilla
Date: Fri, 2 Oct 2026 16:56:14 +0000
Subject: [PATCH 28/98] 8393152: Shenandoah: Further optimize HdrSeq memory
footprint
Reviewed-by: wkemper, xpeng, ruili
---
.../gc/shenandoah/shenandoahNumberSeq.cpp | 39 +++++++++++++------
.../gc/shenandoah/shenandoahNumberSeq.hpp | 6 ++-
.../shenandoah/shenandoahScanRemembered.hpp | 2 +-
.../shenandoah/test_shenandoahNumberSeq.cpp | 14 +++++++
4 files changed, 48 insertions(+), 13 deletions(-)
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp
index 381861cd4f7..1abac823bdc 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp
@@ -32,14 +32,16 @@
#include
#include
-HdrSeq::HdrSeq() : _minimum(DBL_MAX) {
- _hdr = NEW_C_HEAP_ARRAY(int*, MagBuckets, mtGC);
- for (int c = 0; c < MagBuckets; c++) {
- _hdr[c] = nullptr;
- }
+HdrSeq::HdrSeq() :
+ _hdr(nullptr),
+ _minimum(DBL_MAX) {
}
HdrSeq::~HdrSeq() {
+ if (_hdr == nullptr) {
+ return;
+ }
+
for (int c = 0; c < MagBuckets; c++) {
int* sub = _hdr[c];
if (sub != nullptr) {
@@ -49,7 +51,18 @@ HdrSeq::~HdrSeq() {
FREE_C_HEAP_ARRAY(_hdr);
}
+void HdrSeq::allocate_hdr() {
+ if (_hdr == nullptr) {
+ _hdr = NEW_C_HEAP_ARRAY(int*, MagBuckets, mtGC);
+ for (int c = 0; c < MagBuckets; c++) {
+ _hdr[c] = nullptr;
+ }
+ }
+}
+
void HdrSeq::add(double val) {
+ allocate_hdr();
+
if (val < 0) {
assert (false, "value (%8.2f) is not negative", val);
val = 0;
@@ -112,7 +125,7 @@ double HdrSeq::minimum() const {
}
double HdrSeq::percentile(double level) const {
- if (level == 0) {
+ if (level == 0 || num() == 0) {
return minimum();
}
@@ -145,6 +158,8 @@ void HdrSeq::add(const HdrSeq& other) {
return;
}
+ allocate_hdr();
+
for (int mag = 0; mag < MagBuckets; mag++) {
int* other_bucket = other._hdr[mag];
if (other_bucket == nullptr) {
@@ -185,11 +200,13 @@ void HdrSeq::add(const HdrSeq& other) {
void HdrSeq::clear() {
// Clear the storage
- for (int mag = 0; mag < MagBuckets; mag++) {
- int* bucket = _hdr[mag];
- if (bucket != nullptr) {
- for (int c = 0; c < ValBuckets; c++) {
- bucket[c] = 0;
+ if (_hdr != nullptr) {
+ for (int mag = 0; mag < MagBuckets; mag++) {
+ int* bucket = _hdr[mag];
+ if (bucket != nullptr) {
+ for (int c = 0; c < ValBuckets; c++) {
+ bucket[c] = 0;
+ }
}
}
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.hpp b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.hpp
index 0d3c515680a..02361f07fdb 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.hpp
@@ -27,6 +27,7 @@
#define SHARE_GC_SHENANDOAH_SHENANDOAHNUMBERSEQ_HPP
#include "runtime/atomic.hpp"
+#include "utilities/globalDefinitions.hpp"
#include "utilities/numberSeq.hpp"
// HDR sequence stores the low-resolution high-dynamic-range values.
@@ -46,8 +47,11 @@ class HdrSeq: public NumberSeq {
MagBuckets = 56,
MagMinimum = -32
};
- int** _hdr;
+ int** _hdr; // Lazily allocated on first add() and freed in the destructor.
double _minimum;
+ NONCOPYABLE(HdrSeq);
+
+ void allocate_hdr();
public:
HdrSeq();
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp
index 2c60d4340f5..e5ed4c056a2 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp
@@ -749,7 +749,7 @@ class ShenandoahScanRemembered: public CHeapObj {
delete _scc;
if (ShenandoahEnableCardStats) {
for (uint i = 0; i < ParallelGCThreads; i++) {
- delete _card_stats[i];
+ delete[] _card_stats[i];
}
FREE_C_HEAP_ARRAY(_card_stats);
_card_stats = nullptr;
diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp
index a7340040999..6b726d2b54c 100644
--- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp
+++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp
@@ -191,3 +191,17 @@ TEST_VM(ShenandoahNumberSeq, large_value) {
EXPECT_EQ(seq.maximum(), max_dirty_scan_obj_cnt);
EXPECT_EQ(seq.percentile(100), max_dirty_scan_obj_cnt);
}
+
+TEST_VM(ShenandoahNumberSeq, empty_hdr) {
+ HdrSeq empty;
+ EXPECT_EQ(empty.num(), 0);
+ for (int i = 0; i <= 100; i += 10) {
+ EXPECT_EQ(empty.percentile(i), 0);
+ }
+ empty.clear();
+ EXPECT_EQ(empty.num(), 0);
+
+ HdrSeq other;
+ empty.add(other);
+ EXPECT_EQ(empty.num(), 0);
+}
From b22ccb9af5fc7d097f5bf24e0e87a1c02c5810dd Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev
Date: Fri, 2 Oct 2026 18:13:02 +0000
Subject: [PATCH 29/98] 8393280: Shenandoah: Nested GC state resetter is stuck
in wrong state
Reviewed-by: wkemper, xpeng, ruili
---
.../gc/shenandoah/shenandoahRootVerifier.cpp | 42 ++++++++++---------
.../gc/shenandoah/shenandoahRootVerifier.hpp | 8 ++--
.../gc/shenandoah/shenandoahVerifier.cpp | 2 +
3 files changed, 28 insertions(+), 24 deletions(-)
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp
index eb4eb78fa6d..5a4be901cc0 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp
@@ -46,19 +46,23 @@
#include "utilities/debug.hpp"
#include "utilities/enumIterator.hpp"
-Atomic ShenandoahGCStateResetter::_active_count;
+Atomic ShenandoahGCStateResetter::_is_active;
ShenandoahGCStateResetter::ShenandoahGCStateResetter() :
- _heap(ShenandoahHeap::heap()),
- _saved_gc_state(_heap->gc_state()),
- _saved_gc_state_changed(_heap->_gc_state_changed) {
+ _heap(ShenandoahHeap::heap()) {
+
+ shenandoah_assert_safepoint();
+ assert(!_is_active.load_relaxed(), "No nested resets");
+
+ // Capture the GC state right away.
+ _saved_gc_state = _heap->gc_state();
+ _saved_gc_state_changed = _heap->_gc_state_changed;
// Need to complete GC processing before deactivating the barriers.
// Once the GC state is dropped, we cannot allow GC-state dependent fixups,
// that would patch barriers or process the oops incorrectly. Verifier code
// can enter stack watermark processing as part of regular thread root work.
// This pretends Java threads have fixed up all state before we go for verification.
- // Do this unconditionally in all callers to get to the same consensus point.
for (JavaThreadIteratorWithHandle jtiwh; JavaThread* jt = jtiwh.next();) {
StackWatermarkSet::finish_processing(jt, nullptr, StackWatermarkKind::gc);
}
@@ -68,29 +72,27 @@ ShenandoahGCStateResetter::ShenandoahGCStateResetter() :
ShenandoahSATBMarkQueueSet& satb_qs = ShenandoahBarrierSet::satb_mark_queue_set();
satb_qs.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(Thread::current()));
- // From this moment on, level-1 resetter is active.
- if (_active_count.compare_set(0, 1, memory_order_relaxed)) {
- // Clear state to deactivate barriers. Indicate that state has changed
- // so that verifier threads will use this value, rather than thread local
- // values (which we are _not_ changing here).
- _heap->_gc_state.clear();
- _heap->_gc_state_changed = true;
- }
+ // Flip the state to zero. Indicate that state has changed so that verifier threads
+ // will use this value, rather than thread local values (which we are _not_ changing here).
+ _heap->_gc_state.clear();
+ _heap->_gc_state_changed = true;
+
+ // GC state is now reset.
+ _is_active.store_relaxed(true);
+
+ assert(_heap->gc_state() == 0, "Should have been cleared");
}
ShenandoahGCStateResetter::~ShenandoahGCStateResetter() {
- if (_active_count.add_then_fetch(-1, memory_order_relaxed) > 0) {
- // Nested, nothing to do.
- return;
- }
-
_heap->_gc_state.set(_saved_gc_state);
_heap->_gc_state_changed = _saved_gc_state_changed;
assert(_heap->gc_state() == _saved_gc_state, "Should be restored");
+
+ _is_active.store_relaxed(false);
}
void ShenandoahRootVerifier::roots_do(OopIterateClosure* oops, ShenandoahGeneration* generation) {
- ShenandoahGCStateResetter resetter;
+ assert(ShenandoahGCStateResetter::is_active(), "Must be active");
shenandoah_assert_safepoint();
NMethodToOopClosure blobs(oops, !NMethodToOopClosure::FixRelocations);
@@ -116,7 +118,7 @@ void ShenandoahRootVerifier::roots_do(OopIterateClosure* oops, ShenandoahGenerat
}
void ShenandoahRootVerifier::strong_roots_do(OopIterateClosure* oops, ShenandoahGeneration* generation) {
- ShenandoahGCStateResetter resetter;
+ assert(ShenandoahGCStateResetter::is_active(), "Must be active");
shenandoah_assert_safepoint();
CLDToOopClosure clds(oops, ClassLoaderData::_claim_none);
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp
index a41249abb3c..a240be96c47 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp
@@ -32,17 +32,17 @@
class ShenandoahGCStateResetter : public StackObj {
private:
- static Atomic _active_count;
+ static Atomic _is_active;
+ char _saved_gc_state;
+ bool _saved_gc_state_changed;
ShenandoahHeap* const _heap;
- const char _saved_gc_state;
- const bool _saved_gc_state_changed;
public:
ShenandoahGCStateResetter();
~ShenandoahGCStateResetter();
- static bool is_active() { return _active_count.load_relaxed() > 0; }
+ static bool is_active() { return _is_active.load_relaxed(); }
};
class ShenandoahRootVerifier : public AllStatic {
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp
index be24582de91..43cc7b73792 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp
@@ -1318,11 +1318,13 @@ class ShenandoahVerifyInToSpaceClosure : public BasicOopIterateClosure {
void ShenandoahVerifier::verify_roots_in_to_space(ShenandoahGeneration* generation) {
ShenandoahVerifyInToSpaceClosure cl;
+ ShenandoahGCStateResetter resetter;
ShenandoahRootVerifier::roots_do(&cl, generation);
}
void ShenandoahVerifier::verify_roots_no_forwarded(ShenandoahGeneration* generation) {
ShenandoahVerifyNoForwarded cl;
+ ShenandoahGCStateResetter resetter;
ShenandoahRootVerifier::roots_do(&cl, generation);
}
From 661bd45630e169e44c89ca7c306b56c0c95ab247 Mon Sep 17 00:00:00 2001
From: Min Choi
Date: Sat, 3 Oct 2026 10:11:30 +0000
Subject: [PATCH 30/98] 8393337: (tz) Update Timezone Data to 2026e
Reviewed-by: naoto, andrew
---
src/java.base/share/data/tzdata/VERSION | 2 +-
src/java.base/share/data/tzdata/europe | 30 ++++-
src/java.base/share/data/tzdata/northamerica | 118 +++++++++++++++---
test/jdk/java/util/TimeZone/Bug6329116.java | 7 +-
.../java/util/TimeZone/TimeZoneData/VERSION | 2 +-
.../TimeZone/TimeZoneData/displaynames.txt | 2 +-
6 files changed, 132 insertions(+), 29 deletions(-)
diff --git a/src/java.base/share/data/tzdata/VERSION b/src/java.base/share/data/tzdata/VERSION
index 35a783728e8..3261b6ad2f3 100644
--- a/src/java.base/share/data/tzdata/VERSION
+++ b/src/java.base/share/data/tzdata/VERSION
@@ -21,4 +21,4 @@
# or visit www.oracle.com if you need additional information or have any
# questions.
#
-tzdata2026d
+tzdata2026e
diff --git a/src/java.base/share/data/tzdata/europe b/src/java.base/share/data/tzdata/europe
index ca09f4fa3ed..0634d475e3f 100644
--- a/src/java.base/share/data/tzdata/europe
+++ b/src/java.base/share/data/tzdata/europe
@@ -401,13 +401,33 @@
# as a negative daylight saving time in winter. So, in this database
# IST stands for Irish Summer Time for timestamps before 1968, and for
# Irish Standard Time after that. See:
-# http://www.irishstatutebook.ie/eli/1971/act/17/enacted/en/print
+# https://www.irishstatutebook.ie/eli/1971/act/17/enacted/en/print
# Michael Deckers (2017-06-01) gave the following URLs for Ireland's
# Summer Time Act, 1925 and Summer Time Orders, 1926 and 1947:
-# http://www.irishstatutebook.ie/eli/1925/act/8/enacted/en/print
-# http://www.irishstatutebook.ie/eli/1926/sro/919/made/en/print
-# http://www.irishstatutebook.ie/eli/1947/sro/71/made/en/print
+# https://www.irishstatutebook.ie/eli/1925/act/8/enacted/en/print
+# https://www.irishstatutebook.ie/eli/1926/sro/919/made/en/print
+# https://www.irishstatutebook.ie/eli/1947/sro/71/made/en/print
+
+# From Stan Ulbrych (2026-09-12):
+# Ireland's Summer Time Act, 1925 (No. 8 of 1925, see above)
+# ended summer time at 02:00 GMT on the day after the third Saturday in
+# September, that is, 1925-09-20. The UK's Summer Time Act, 1925, however,
+# moved the UK's end date to the day after the first Saturday in October with
+# immediate effect, but it did not apply to the Irish Free State.
+# Ireland matched the October date only from 1926, via the Summer Time Order,
+# 1926, whose recital replaces the period fixed by section 2 of the 1925 Act
+# and mentions no earlier order. Moving approval of that order in the
+# Dáil on 1926-03-24, Minister Kevin O'Higgins said:
+#
+# Deputies will remember that last year there was a discrepancy of a
+# fortnight between the termination of Summer Time in the Saorstát and
+# in Great Britain and Northern Ireland. As a result of that, serious
+# inconvenience was caused to railway companies, and there was a certain
+# amount of dislocation of postal services in the country.
+#
+# (See: https://www.oireachtas.ie/en/debates/debate/dail/1926-03-24/18/)
+# So Dublin fell back on 1925-09-20, two weeks before London.
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
# Summer Time Act, 1916
@@ -560,6 +580,8 @@ Zone Europe/Dublin -0:25:21 - LMT 1880 Aug 2
-0:25:21 - DMT 1916 May 21 2:00s
-0:25:21 1:00 IST 1916 Oct 1 2:00s
0:00 GB-Eire %s 1921 Dec 6 # independence
+ 0:00 GB-Eire GMT/IST 1925 Sep Sun>=16 2:00s
+ 0:00 - GMT 1926
0:00 GB-Eire GMT/IST 1940 Feb 25 2:00s
0:00 1:00 IST 1946 Oct 6 2:00s
0:00 - GMT 1947 Mar 16 2:00s
diff --git a/src/java.base/share/data/tzdata/northamerica b/src/java.base/share/data/tzdata/northamerica
index 8be797d61d9..0b053aaefc2 100644
--- a/src/java.base/share/data/tzdata/northamerica
+++ b/src/java.base/share/data/tzdata/northamerica
@@ -1769,7 +1769,36 @@ Zone America/Toronto -5:17:32 - LMT 1895
-5:00 Canada E%sT 1946
-5:00 Toronto E%sT 1974
-5:00 Canada E%sT
-# For Atikokan see America/Panama.
+# From Tim Parenti (2026-09-21), per Paul Eggert (2000-10-02, 2006-07-17):
+# In the northwest of the province, most portions of Kenora, Rainy River, and
+# Thunder Bay Districts lying broadly west of 90°W longitude have historically
+# been aligned with neighboring Manitoba and use America/Winnipeg, in
+# accordance with section 2(2) of Ontario's Time Act, RSO 1990 chapter T.9:
+# https://www.ontario.ca/laws/statute/90t09
+# With Manitoba now opting to stay on -05 year-round, if any of these areas do
+# not follow, it would require a new zone; however, given the short leadtime
+# ahead of a potential divergence on 2026-11-01 and in the interest of not
+# creating zones that may not be needed, assume for the time being that they
+# will.
+#
+# In practice, there are several exceptions to the 90°W dividing line set by
+# the province, all of which technically contravene the official Ontario rules:
+# - An area around Big Trout Lake in Kenora District observes Central Time
+# (-06/-05) despite extending east of 90°W.
+# - An area around Upsala in the southwest of Thunder Bay District observes
+# Eastern Time (-05/-04) like America/Toronto despite extending west of
+# 90°W.
+# - Atikokan in the east of Rainy River District has observed year-round -05
+# (EST) since at least 1952; this matches America/Panama since our 1970
+# cutoff.
+# - Pickle Lake and the Mishkeegogamang First Nation (formerly New Osnaburgh)
+# in Kenora District have also observed year-round -05 (EST) since at least
+# 1998, though it is less clear how far back that arrangement goes; assume
+# the area is covered in the same way as Atikokan.
+# See the 'backzone' file for further commentary.
+# At time of writing, it is not yet known to what extent Manitoba's 2026-09-17
+# announcement may spur further adaptations in northwestern Ontario; see
+# Manitoba, below.
# Manitoba
@@ -1804,6 +1833,40 @@ Zone America/Toronto -5:17:32 - LMT 1895
# the 1987 version would apply - the changeover was at 2:00 Central
# Standard Time (i.e. not until 3:00 Central Daylight Time).
+# From Tim Parenti (2026-09-29):
+# As much of western Canada began announcing year-round DST in early 2026,
+# Manitoba Premier Wab Kinew publicly mused on forming a "Prairie time zone" by
+# joining Saskatchewan and Alberta on year-round -06, while committing to
+# conducting a public engagement survey on the matter. The results, however,
+# showed that while "[a] total of 92 per cent of Manitobans surveyed wanted to
+# see an end to seasonal time changes", "[a] majority of Manitobans (58 per
+# cent) preferred to stay on permanent DST, while 34 per cent voted to
+# eliminate the time change but stay on standard time."
+#
+# The survey results were published on Thursday 2026-09-17 alongside a policy
+# announcement adopting permanent DST, or year-round -05, just over 6 weeks
+# before clocks would otherwise fall back on 2026-11-01.
+# https://news.gov.mb.ca/news/?item=75397
+# https://www.cbc.ca/news/canada/manitoba/daylight-time-manitoba-9.7347844
+#
+# While other potential options would have required further legislation, the
+# Official Time Amendment Act (Bill 2 of the 42nd Legislature's 5th Session),
+# assented to 2023-05-30, provides for year-round -05 upon proclamation.
+# https://web2.gov.mb.ca/laws/statutes/2023/pdf/c00423.pdf
+# Order in Council 221/2026, issued 2026-09-23, directed the proclamation
+# bringing the Act into force on 2026-10-31, 26 hours before clocks would
+# otherwise fall back.
+# https://oic.gov.mb.ca/OICDocs/2026/09/Municipal%20and%20Northern%20Relations.260923.%20Official%20Time%20Amendment%20Act.2212026.pdf
+# https://web2.gov.mb.ca/laws/statutes/proclamations/2023c4(2026-10-31).pdf
+#
+# The Act further allows for the Lieutenant Governor in Council to, on
+# recommendation of the relevant minister, "make regulations varying the
+# reckoning" of official time in Manitoba, provided the minister has "due
+# regard for the applicable time zone in neighbouring jurisdictions."
+#
+# Use a temporary hack like Alberta’s to work around potential CLDR
+# limitations.
+
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule Winn 1916 only - Apr 23 0:00 1:00 D
Rule Winn 1916 only - Sep 17 0:00 0 S
@@ -1832,7 +1895,11 @@ Rule Winn 1987 2005 - Apr Sun>=1 2:00s 1:00 D
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Winnipeg -6:28:36 - LMT 1887 Jul 16
-6:00 Winn C%sT 2006
- -6:00 Canada C%sT
+ -6:00 Canada C%sT 2026 Oct 31
+ # Temporary hack; see above.
+ -6:00 Canada CDT 2026 Nov 1 2:00
+ # End of temporary hack.
+ -5:00 - EST
# Saskatchewan
@@ -1910,6 +1977,12 @@ Zone America/Winnipeg -6:28:36 - LMT 1887 Jul 16
# for those areas to observe either "UTC-5, UTC-6 or UTC-7 for all or part of
# the year" on at least 30 days' notice.
# The new Act comes into force by order of the Lieutenant Governor in Council.
+# From Tim Parenti (2026-09-21):
+# With Manitoba now adopting year-round -05, the area around Creighton will
+# likely wish to follow. As the area doesn't have a special charter like
+# Lloydminster, the existing de facto arrangement technically violates
+# provincial law already, but once the new Act takes effect it will better
+# allow for continued alignment with Manitoba, per the above.
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule Regina 1918 only - Apr 14 2:00 1:00 D
@@ -2068,13 +2141,13 @@ Zone America/Edmonton -7:33:52 - LMT 1906 Sep
# on March 8 will be the last time change, ending twice-yearly clock changes.”
# https://news.gov.bc.ca/releases/2026AG0013-000209
#
-# From Paul Eggert (2026-07-02):
+# From Paul Eggert (2026-09-23):
# The law says that 21 hours after the usual 2026-03-08 02:00 switch from
-# PST to PDT, the next day inaugurates the new standard time Pacific Time,
+# PST to PDT, the next day inaugurated the new standard time Pacific Time,
# i.e., just one clock change but two name changes separated by 21 hours.
# PT, the obvious abbreviation for Pacific Time, is one letter too short
# to conform to TZDB’s (and POSIX’s) [-+[:alnum:]]{3,6} requirements.
-# I asked the BC government for advice, with no response. For now, do this:
+# For now, do this:
# 1. As a temporary hack, pretend that the BC law takes effect
# not on 2026-03-09 at 00:00, but on 2026-11-01 at 02:00.
# This pretense works around a limitation in CLDR 48.1 (2026-01-08),
@@ -2092,10 +2165,10 @@ Zone America/Edmonton -7:33:52 - LMT 1906 Sep
# and already used in parts of BC and in Yukon
# PDT - almost as software-friendly, but confusing because it implies
# it is DST and is paired with PST, whereas PT is standard time
-# PST - straightforward but even more confusing,
-# and will likely break much software that assumes PST is -08
# -07 - accurate and clear in itself, but makes BC look odd vs neighbors
-# PacT - straightforward but novel abbreviation for Pacific Time
+# PCT - as I understand it, inspired by the phrase “Pacific Coast Time”
+# though legally it’s “Pacific Time”; suggested by the BC government
+#
# From Tim Parenti (2026-08-21):
# In the southeast of the province, the Regional District of East Kootenay
@@ -2121,18 +2194,23 @@ Zone America/Edmonton -7:33:52 - LMT 1906 Sep
# 2026-08-14 meeting.
# https://www.cbc.ca/news/canada/british-columbia/east-kootenay-stops-changing-clocks-9.7308201
#
-# From Tim Parenti (2026-09-10):
-# Although on 2026-09-01 the Town of Golden voted instead to split its
-# timekeeping practice from RDEK and rejoin BC on year-round -07, this was met
-# with significant pushback from residents in Golden and CSRD Area A. In light
-# of these public comments, CSRD voted on 2026-09-10 to defer its decision on
-# timekeeping in Area A “to gather and assess further information before a
-# decision is implemented”. As such, at time of writing, it seems likely that
-# Golden may soon revisit its decision as well.
-#
-# For now, these areas remain aligned with America/Edmonton, but if they
-# diverge, a new zone with a name like 'America/Brit_Columbia/Golden' would be
-# needed.
+# From Tim Parenti (2026-09-24):
+# Echoing RDEK’s earlier false step, the Town of Golden initially opted for
+# year-round -07 by a 4–2 Council vote on 2026-09-01. This was met with
+# significant pushback from residents preferring to maintain the existing
+# alignment with RDEK and Alberta, with a formal petition swiftly gathering
+# 2,395 signatures in two weeks from the town of 3,986 and some smaller
+# neighboring communities. In response, Council unanimously rescinded the
+# resolution at the following meeting on 2026-09-22, and unanimously replaced
+# it with year-round -06 to keep the regional alignment.
+# Acknowledging that “its initial move was driven in part by concerns about
+# dark winter mornings and pedestrian safety for children travelling to
+# school”, the new resolution directs town staff to partner on safety supports
+# and commits to reviewing the decision and its impacts in October 2027.
+# https://www.ctvnews.ca/calgary/article/golden-bc-council-reverses-course-on-time-zone-opts-for-mountain-daylight-time/
+# At time of writing, the surrounding CSRD Area A is yet to formalize its own
+# decision following a 2026-09-10 deferral “to gather and assess further
+# information”, but is expected to follow.
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule Vanc 1918 only - Apr 14 2:00 1:00 D
diff --git a/test/jdk/java/util/TimeZone/Bug6329116.java b/test/jdk/java/util/TimeZone/Bug6329116.java
index e23d9f44fd4..7ed0c555a2f 100644
--- a/test/jdk/java/util/TimeZone/Bug6329116.java
+++ b/test/jdk/java/util/TimeZone/Bug6329116.java
@@ -26,7 +26,7 @@
* @bug 6329116 6756569 6757131 6758988 6764308 6796489 6834474 6609737 6507067
* 7039469 7090843 7103108 7103405 7158483 8008577 8059206 8064560 8072042
* 8077685 8151876 8166875 8169191 8170316 8176044 8174269 8347841 8347955
- * 8388214 8392377
+ * 8388214 8392377 8393337
* @summary Make sure that timezone short display names are identical to Olson's data.
* @run junit Bug6329116
*/
@@ -49,7 +49,10 @@ public class Bug6329116 {
"Canada/Mountain", "MST",
"America/Yellowknife", "MST",
"America/Vancouver", "PST",
- "Canada/Pacific", "PST");
+ "Canada/Pacific", "PST",
+ "America/Winnipeg", "CST",
+ "Canada/Central", "CST",
+ "America/Rainy_River", "CST");
// Do not test all locales, as some locales have localized
// short names in CLDR. Test only for the US locale
diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION
index a19030a9b59..376af12e303 100644
--- a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION
+++ b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION
@@ -1 +1 @@
-tzdata2026d
+tzdata2026e
diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt b/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt
index 889d1dfc4b7..3236241bf2b 100644
--- a/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt
+++ b/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt
@@ -88,7 +88,7 @@ America/Tijuana PST PDT
America/Toronto EST EDT
America/Vancouver MST
America/Whitehorse MST
-America/Winnipeg CST CDT
+America/Winnipeg EST
America/Yakutat AKST AKDT
Antarctica/Macquarie AEST AEDT
Asia/Beirut EET EEST
From f3701c80216900f3ded26f9de1befe43813be95c Mon Sep 17 00:00:00 2001
From: Erik Gahlin
Date: Sat, 3 Oct 2026 14:25:23 +0000
Subject: [PATCH 31/98] 8255404:
jdk/jfr/api/consumer/recordingstream/TestOnEvent.java timed out
Reviewed-by: mgronlun
---
.../share/jfr/support/jfrJdkJfrEvent.cpp | 8 ++-
test/jdk/jdk/jfr/jvm/TestClinitStart.java | 69 +++++++++++++++++++
2 files changed, 75 insertions(+), 2 deletions(-)
create mode 100644 test/jdk/jdk/jfr/jvm/TestClinitStart.java
diff --git a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp
index 0e7f706b210..5370938d192 100644
--- a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp
+++ b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp
@@ -62,7 +62,7 @@ static bool initialize(TRAPS) {
/*
* Abstract klasses are filtered out unconditionally.
- * If a klass is not yet initialized, i.e yet to run its
+ * If a klass is not initialized and is not running,
* it is also filtered out so we don't accidentally
* trigger initialization.
*/
@@ -72,7 +72,11 @@ static bool is_allowed(const Klass* k) {
// Was excluded during initial class load.
return false;
}
- return !(k->is_abstract() || k->should_be_initialized());
+ if (k->is_abstract()) {
+ return false;
+ }
+ const InstanceKlass* ik = InstanceKlass::cast(k);
+ return ik->is_initialized() || ik->is_being_initialized();
}
static void fill_klasses(GrowableArray& event_subklasses, const InstanceKlass* event_klass, JavaThread* thread) {
diff --git a/test/jdk/jdk/jfr/jvm/TestClinitStart.java b/test/jdk/jdk/jfr/jvm/TestClinitStart.java
new file mode 100644
index 00000000000..fae8cdd1cd0
--- /dev/null
+++ b/test/jdk/jdk/jfr/jvm/TestClinitStart.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.jvm;
+
+import java.util.concurrent.CountDownLatch;
+
+import jdk.jfr.Event;
+import jdk.jfr.Name;
+import jdk.jfr.consumer.RecordingStream;
+
+/**
+ * @test TestClinitStart
+ * @requires vm.flagless
+ * @requires vm.hasJFR
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.jvm.TestClinitStart
+ */
+public class TestClinitStart {
+ private static final String EVENT_NAME = "ClinitStart";
+ private static final CountDownLatch registration = new CountDownLatch(1);
+ private static final CountDownLatch recordingStart = new CountDownLatch(1);
+
+ @Name(EVENT_NAME)
+ private static class ClinitEvent extends Event {
+ static {
+ // FlightRecorder.register(ClinitEvent.class) instrumentation
+ // is added here by the JVM
+ registration.countDown();
+ try {
+ recordingStart.await();
+ } catch (InterruptedException e) {
+ throw new InternalError(e);
+ }
+ }
+ }
+
+ public static void main(String... args) throws Exception {
+ Thread.ofPlatform().start(() -> new ClinitEvent().commit());
+ registration.await();
+ try (RecordingStream rs = new RecordingStream()) {
+ rs.enable(EVENT_NAME);
+ rs.onEvent(EVENT_NAME, e -> rs.close());
+ rs.startAsync();
+ recordingStart.countDown();
+ rs.awaitTermination();
+ }
+ }
+}
From 0f0b3678b0d9f631b999ec8861329b1fdd048f12 Mon Sep 17 00:00:00 2001
From: Gui Cao
Date: Sun, 4 Oct 2026 10:39:32 +0000
Subject: [PATCH 32/98] 8393488: RISC-V: Make float16ToFloat ignore upper
argument bits
Reviewed-by: fyang, dzhang
---
.../cpu/riscv/c2_MacroAssembler_riscv.cpp | 9 +-
src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 7 +-
.../TestFloat16ToFloatUnnormalized.java | 83 +++++++++++++++++++
3 files changed, 94 insertions(+), 5 deletions(-)
create mode 100644 test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16ToFloatUnnormalized.java
diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
index 440ad6f5483..99898e251ee 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
@@ -2380,8 +2380,11 @@ static void float16_to_float_slow_path(C2_MacroAssembler& masm, C2GeneralStub(dst, src, tmp, 20, float16_to_float_slow_path);
+ auto stub = C2CodeStub::make(dst, src, tmp, 28, float16_to_float_slow_path);
// On riscv, NaN needs a special process as fcvt does not work in that case.
// On riscv, Inf does not need a special process as fcvt can handle it correctly.
diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
index 0265f98a733..074f80297aa 100644
--- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
@@ -7473,8 +7473,11 @@ class StubGenerator: public StubCodeGenerator {
// construct a NaN in 32 bits from the NaN in 16 bits,
// we need the payloads of non-canonical NaNs to be preserved.
__ mv(t1, 0x7f800000);
- // sign-bit was already set via sign-extension if necessary.
- __ slli(t0, src, 13);
+ // The upper 16 bits of a short argument are unspecified. Sign-extend the
+ // low 16 bits before shifting so that the float sign bit comes from the
+ // float16 sign bit.
+ __ sext(t0, src, 16);
+ __ slli(t0, t0, 13);
__ orr(t1, t0, t1);
__ fmv_w_x(dst, t1);
diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16ToFloatUnnormalized.java b/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16ToFloatUnnormalized.java
new file mode 100644
index 00000000000..075dd13fc58
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16ToFloatUnnormalized.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2026, Alibaba Group Holding Limited. All Rights Reserved.
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 8393488
+ * @summary Verify float16ToFloat ignores bits above the low 16 bits of its argument
+ * @requires vm.compiler1.enabled & vm.compiler2.enabled
+ * @run main/othervm -Xverify:all -Xint -XX:+UnlockDiagnosticVMOptions
+ * -XX:DisableIntrinsic=_float16ToFloat TestFloat16ToFloatUnnormalized
+ * @run main/othervm -Xverify:all -Xint TestFloat16ToFloatUnnormalized
+ * @run main/othervm -Xverify:all -Xcomp -Xbatch -XX:TieredStopAtLevel=1
+ * -XX:CompileCommand=compileonly,UnnormalizedFloat16::convert TestFloat16ToFloatUnnormalized
+ * @run main/othervm -Xverify:all -Xcomp -Xbatch -XX:-TieredCompilation
+ * -XX:CompileCommand=compileonly,UnnormalizedFloat16::convert TestFloat16ToFloatUnnormalized
+ */
+
+import java.lang.classfile.ClassFile;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.MethodTypeDesc;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import static java.lang.constant.ConstantDescs.CD_float;
+import static java.lang.constant.ConstantDescs.CD_int;
+import static java.lang.constant.ConstantDescs.CD_short;
+
+public class TestFloat16ToFloatUnnormalized {
+ private static final int[] HIGH_BITS = {
+ 0x0000_0000, 0xffff_0000, 0x8000_0000,
+ 0x0004_0000, 0x5555_0000, 0xaaaa_0000
+ };
+
+ public static void main(String[] args) throws Throwable {
+ byte[] bytes = ClassFile.of().build(ClassDesc.of("UnnormalizedFloat16"), cb ->
+ cb.withMethodBody("convert", MethodTypeDesc.of(CD_float, CD_int),
+ ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC, code -> {
+ // Unlike Java source, bytecode accepts int for short parameters; omit i2s to keep upper bits.
+ code.iload(0)
+ .invokestatic(ClassDesc.of("java.lang.Float"), "float16ToFloat",
+ MethodTypeDesc.of(CD_float, CD_short))
+ .freturn();
+ }));
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ Class> generatedClass = lookup.defineClass(bytes);
+ MethodHandle convert = lookup.findStatic(generatedClass, "convert",
+ MethodType.methodType(float.class, int.class));
+
+ for (int lowBits = 0; lowBits <= 0xffff; lowBits++) {
+ int expected = Float.floatToIntBits(Float.float16ToFloat((short) lowBits));
+ for (int highBits : HIGH_BITS) {
+ int input = highBits | lowBits;
+ int actual = Float.floatToIntBits((float) convert.invokeExact(input));
+ if (actual != expected) {
+ throw new AssertionError("input=0x%08x: expected=0x%08x, actual=0x%08x"
+ .formatted(input, expected, actual));
+ }
+ }
+ }
+ }
+}
From 97865d54376df612d3ff876c54cfff055ff0a800 Mon Sep 17 00:00:00 2001
From: Frederic Thevenet
Date: Mon, 5 Oct 2026 05:15:46 +0000
Subject: [PATCH 33/98] 8392770: [test] VM properties that checks for the
presence of CDS archives do not work on Windows
Reviewed-by: iklam, dholmes, adinn
---
test/jtreg-ext/requires/VMProps.java | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java
index a3ce27f484b..185d967487c 100644
--- a/test/jtreg-ext/requires/VMProps.java
+++ b/test/jtreg-ext/requires/VMProps.java
@@ -403,14 +403,24 @@ protected String vmCDS() {
return "" + (noJvmtiAdded && WB.isCDSIncluded());
}
+ // Returns a platform-aware path for the specified archive file.
+ private Path archivePath(String archiveName) {
+ String archiveSubdir = (Platform.isWindows() ? "bin" : "lib");
+ return Paths.get(System.getProperty("java.home"), archiveSubdir, "server", archiveName);
+ }
+
+ // Returns true if a CDS archive file with specified name exists.
+ private boolean archivePathExists(String archiveName) {
+ return Files.exists(archivePath(archiveName));
+ }
+
/**
* Check for CDS default archive existence.
*
* @return true if CDS default archive classes.jsa exists in the JDK to be tested.
*/
protected String vmCDSDefaultArchiveAvailable() {
- Path archive = Paths.get(System.getProperty("java.home"), "lib", "server", "classes.jsa");
- return "" + ("true".equals(vmCDS()) && Files.exists(archive));
+ return "" + ("true".equals(vmCDS()) && archivePathExists("classes.jsa"));
}
/**
@@ -419,8 +429,7 @@ protected String vmCDSDefaultArchiveAvailable() {
* @return true if CDS archive classes_nocoops.jsa exists in the JDK to be tested.
*/
protected String vmCDSNocoopsArchiveAvailable() {
- Path archive = Paths.get(System.getProperty("java.home"), "lib", "server", "classes_nocoops.jsa");
- return "" + ("true".equals(vmCDS()) && Files.exists(archive));
+ return "" + ("true".equals(vmCDS()) && archivePathExists("classes_nocoops.jsa"));
}
/**
@@ -429,8 +438,7 @@ protected String vmCDSNocoopsArchiveAvailable() {
* @return true if CDS archive classes_nocoh.jsa exists in the JDK to be tested.
*/
protected String vmCDSNocohArchiveAvailable() {
- Path archive = Paths.get(System.getProperty("java.home"), "lib", "server", "classes_nocoh.jsa");
- return "" + ("true".equals(vmCDS()) && Files.exists(archive));
+ return "" + ("true".equals(vmCDS()) && archivePathExists("classes_nocoh.jsa"));
}
/**
From 5d8b5a11260fbcfb7a5bd52222047fc7c138d06d Mon Sep 17 00:00:00 2001
From: Gui Cao
Date: Mon, 5 Oct 2026 05:31:52 +0000
Subject: [PATCH 34/98] 8388474: RISC-V: Relax satp mode check for sv57
Co-authored-by: April Ivy
Reviewed-by: fyang, dzhang
---
src/hotspot/cpu/riscv/vm_version_riscv.cpp | 8 -------
.../linux_riscv/vm_version_linux_riscv.cpp | 23 +++++++++++++++++++
2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
index 7f6fd0d1513..fbf61492d4c 100644
--- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp
+++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
@@ -104,14 +104,6 @@ void VM_Version::common_initialize() {
setup_cpu_available_features();
- // check if satp.mode is supported, currently supports up to SV48(RV64)
- if (satp_mode.value() > VM_SV48 || satp_mode.value() < VM_MBARE) {
- vm_exit_during_initialization(
- err_msg(
- "Unsupported satp mode: SV%d. Only satp modes up to sv48 are supported for now.",
- (int)satp_mode.value()));
- }
-
if (UseRVA20U64) {
useRVA20U64Profile();
}
diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
index 934f272036c..4c154f3ea40 100644
--- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
+++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
@@ -26,10 +26,13 @@
#include "asm/register.hpp"
#include "logging/log.hpp"
+#include "os_linux.hpp"
#include "riscv_hwprobe.hpp"
+#include "runtime/java.hpp"
#include "runtime/os.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/vm_version.hpp"
+#include "utilities/formatBuffer.hpp"
#include
#include
@@ -275,6 +278,26 @@ char* VM_Version::os_uarch_additional_features() {
mode = VM_MBARE;
}
fclose(f);
+
+ // The code generator assumes that every address it embeds in an instruction
+ // sequence fits in 48 bits, see movptr() and mov_metadata(). On SV57 hardware
+ // that only holds because the kernel clamps the window it allocates from by
+ // default to the SV48 range: MMAP_VA_BITS_64 is MIN(VA_BITS, VA_BITS_SV48),
+ // so DEFAULT_MAP_WINDOW and STACK_TOP stay at 2^47 on SV48 and SV57 alike.
+ // SV57 kernels before Linux v6.6 lack that clamp, allocate from the full SV57
+ // range and cannot be supported.
+ if (mode >= VM_SV57) {
+ long major, minor, patch;
+ os::Linux::kernel_version(&major, &minor, &patch);
+ if (os::Linux::kernel_version_compare(major, minor, patch, 6, 6, 0) == -1) {
+ vm_exit_during_initialization(
+ err_msg(
+ "Satp mode SV%d requires a Linux kernel of 6.6 or later, which restricts "
+ "the default address space to the sv48 range (current kernel is %ld.%ld.%ld).",
+ (int)mode, major, minor, patch));
+ }
+ }
+
satp_mode.enable_feature(mode);
return ret;
}
From 344a6d2b2c947f0d851531a2e2d3e9d519de8f27 Mon Sep 17 00:00:00 2001
From: Arno Zeller
Date: Mon, 5 Oct 2026 06:00:42 +0000
Subject: [PATCH 35/98] 8393375: Several CDS tests fail in cross-build
configurations due to missing classes.jsa
Reviewed-by: iklam, sspitsyn, mbaesken
---
.../ErrorHandling/AccessZeroNKlassHitsProtectionZone.java | 2 ++
test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java | 1 +
.../hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java | 1 +
.../jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java | 3 ++-
.../jvmti/RedefineClasses/RedefineLeakThrowable.java | 3 ++-
.../jvmti/RedefineClasses/RedefineSharedClass.java | 3 ++-
6 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java b/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java
index 061361de794..c3f6ece3d3b 100644
--- a/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java
+++ b/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java
@@ -41,6 +41,7 @@
* @test id=no_coh_cds
* @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone
* @requires vm.cds & vm.bits == 64 & vm.debug == true & vm.flagless
+ * @requires vm.cds.default.archive.available
* @requires os.family != "aix"
* @comment This test relies on crashing which conflicts with ASAN checks
* @requires !vm.asan
@@ -71,6 +72,7 @@
* @test id=coh_cds
* @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone
* @requires vm.cds & vm.bits == 64 & vm.debug == true & vm.flagless
+ * @requires vm.cds.default.archive.available
* @requires os.family != "aix"
* @comment This test relies on crashing which conflicts with ASAN checks
* @requires !vm.asan
diff --git a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java
index 2c796243cbf..82c89f5ddfa 100644
--- a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java
+++ b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java
@@ -25,6 +25,7 @@
* @test TestCDSVMCrash
* @summary Verify that an exception is thrown when the VM crashes during executeAndLog
* @requires vm.cds
+ * @requires vm.cds.default.archive.available
* @requires vm.flagless
* @modules java.base/jdk.internal.misc
* @library /test/lib
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java
index 2dd9725295a..48b70972851 100644
--- a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java
+++ b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java
@@ -30,6 +30,7 @@
* via the -vmoptions command line option of JTREG. vm.gc==null will help the test case to discard the explicitly passed
* vm options.
* @requires (vm.gc=="null")
+ * @requires vm.cds.default.archive.available
* @summary Test command line flag combinations that
* could likely affect the behaviour of AppCDS
* @library /test/lib
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java
index 409e37e10a1..4a7e09af98b 100644
--- a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java
+++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java
@@ -1,4 +1,4 @@
-/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -28,6 +28,7 @@
* @bug 8339460
* @requires vm.cds
* @requires vm.cds.custom.loaders
+ * @requires vm.cds.default.archive.available
* @requires vm.flagless
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @compile mypackage/Main.java mypackage/Another.java
diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineLeakThrowable.java b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineLeakThrowable.java
index 11aabb2952a..838924cef99 100644
--- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineLeakThrowable.java
+++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineLeakThrowable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,6 +50,7 @@
* @requires vm.jvmti
* @requires vm.flagless
* @requires vm.cds
+ * @requires vm.cds.default.archive.available
* @modules java.base/jdk.internal.misc
* @modules java.instrument
* java.compiler
diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineSharedClass.java b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineSharedClass.java
index 3ff063833c3..73f3e680eac 100644
--- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineSharedClass.java
+++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineSharedClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
* @summary Verify should_clean_previous_versions when run with retransformation and CDS
* @requires vm.jvmti
* @requires vm.cds
+ * @requires vm.cds.default.archive.available
* @requires vm.opt.final.ClassUnloading
* @requires vm.flagless
* @library /test/lib
From 782aefe8f7718004343dacfd4492a9d4ca6ee09e Mon Sep 17 00:00:00 2001
From: Ioi Lam
Date: Mon, 5 Oct 2026 06:05:38 +0000
Subject: [PATCH 36/98] 8393447: Do not limit heap size when creating AOT cache
Reviewed-by: kvn, asmehra
---
src/hotspot/share/cds/aotMetaspace.cpp | 16 ----------------
src/hotspot/share/cds/heapShared.cpp | 15 ++++++++++++---
src/hotspot/share/cds/heapShared.hpp | 4 ++--
3 files changed, 14 insertions(+), 21 deletions(-)
diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp
index 69eb6a56f6a..11ad8820984 100644
--- a/src/hotspot/share/cds/aotMetaspace.cpp
+++ b/src/hotspot/share/cds/aotMetaspace.cpp
@@ -1033,22 +1033,6 @@ void AOTMetaspace::init_heap_settings() {
if (!CDSConfig::is_dumping_heap() || UseCompressedOops) {
return;
}
- // CDS heap dumping requires all string oops to have an offset
- // from the heap bottom that can be encoded in 32-bit.
- julong max_heap_size = (julong)(4 * G);
-
- if (MinHeapSize > max_heap_size) {
- log_debug(aot)("Setting MinHeapSize to 4G for CDS dumping, original size = %zuM", MinHeapSize/M);
- FLAG_SET_ERGO(MinHeapSize, max_heap_size);
- }
- if (InitialHeapSize > max_heap_size) {
- log_debug(aot)("Setting InitialHeapSize to 4G for CDS dumping, original size = %zuM", InitialHeapSize/M);
- FLAG_SET_ERGO(InitialHeapSize, max_heap_size);
- }
- if (MaxHeapSize > max_heap_size) {
- log_debug(aot)("Setting MaxHeapSize to 4G for CDS dumping, original size = %zuM", MaxHeapSize/M);
- FLAG_SET_ERGO(MaxHeapSize, max_heap_size);
- }
}
#endif // INCLUDE_CDS_JAVA_HEAP && _LP64
diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp
index 31b3481421c..bb0d1abc3d6 100644
--- a/src/hotspot/share/cds/heapShared.cpp
+++ b/src/hotspot/share/cds/heapShared.cpp
@@ -518,15 +518,24 @@ int HeapShared::append_root(oop obj) {
return obj_info->root_index();
} else {
assert(obj_info->root_index() < 0, "must not be zero");
- int i = _pending_roots->append(obj);
+ int i = add_to_pending_roots(obj);
obj_info->set_root_index(i);
return i;
}
} else {
- return _pending_roots->append(obj);
+ return add_to_pending_roots(obj);
}
}
+int HeapShared::add_to_pending_roots(oop obj) {
+ if (_pending_roots->length() == (int)max_jint) {
+ // This should never happen, but just in case we have HUGE caches ...
+ AOTMetaspace::unrecoverable_writing_error("too many pending roots");
+ ShouldNotReachHere();
+ }
+ return _pending_roots->append(obj);
+}
+
int HeapShared::get_root_index(oop obj) {
if (java_lang_Class::is_instance(obj)) {
obj = scratch_java_mirror(obj);
@@ -736,7 +745,7 @@ void HeapShared::init_dumping() {
_scratch_objects_table = new (mtClass)MetaspaceObjToOopHandleTable();
_dumptime_resolved_methods = new (mtClassShared) GrowableArray(100, mtClassShared);
_pending_roots = new GrowableArrayCHeap(500);
- _pending_roots->append(nullptr); // root index 0 represents a null oop
+ add_to_pending_roots(nullptr); // root index 0 represents a null oop
DEBUG_ONLY(_dumptime_classes_with_cached_oops = new (mtClassShared)ArchivableKlassTable());
}
diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp
index 0ac4758d6ee..afdd819f612 100644
--- a/src/hotspot/share/cds/heapShared.hpp
+++ b/src/hotspot/share/cds/heapShared.hpp
@@ -334,7 +334,7 @@ class HeapShared: AllStatic {
static bool has_been_seen_during_subgraph_recording(oop obj);
static void set_has_been_seen_during_subgraph_recording(oop obj);
static bool archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgraph_info);
-
+ static int add_to_pending_roots(oop obj);
static void resolve_classes_for_subgraphs(JavaThread* current, ArchivableStaticFieldInfo fields[]);
static void resolve_classes_for_subgraph_of(JavaThread* current, Klass* k);
static void clear_archived_roots_of(Klass* k);
@@ -438,7 +438,7 @@ class HeapShared: AllStatic {
// Returns -1 if obj is not in the heap root set.
static int get_root_index(oop obj) NOT_CDS_JAVA_HEAP_RETURN_(-1);
- static GrowableArrayCHeap* pending_roots() { return _pending_roots; }
+ static GrowableArrayCHeap const* pending_roots() { return _pending_roots; }
// Dump-time and runtime
static objArrayOop root_segment(int segment_idx);
From 183311f937d5dcf69423f12135da8421869488da Mon Sep 17 00:00:00 2001
From: Arno Zeller
Date: Mon, 5 Oct 2026 06:10:31 +0000
Subject: [PATCH 37/98] 8393374:
java/nio/file/WatchService/DeleteInterference.java fails sometimes on AIX
Reviewed-by: mbaesken
---
test/jdk/java/nio/file/WatchService/DeleteInterference.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/test/jdk/java/nio/file/WatchService/DeleteInterference.java b/test/jdk/java/nio/file/WatchService/DeleteInterference.java
index fc889ad873e..9dc620e5d51 100644
--- a/test/jdk/java/nio/file/WatchService/DeleteInterference.java
+++ b/test/jdk/java/nio/file/WatchService/DeleteInterference.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Red Hat, Inc. and/or its affiliates.
+ * Copyright (c) 2016, 2026, Red Hat, Inc. and/or its affiliates.
* 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 @@
*/
import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
@@ -107,7 +108,7 @@ private static void deleteFileTree(Path file) {
}
}
Files.delete(file);
- } catch (IOException ioe) {
+ } catch (IOException | DirectoryIteratorException ioe) {
// ignore
}
}
From e25c346ae2685b6779328fa987e12f5fdc905daf Mon Sep 17 00:00:00 2001
From: Frederic Thevenet
Date: Mon, 5 Oct 2026 06:18:23 +0000
Subject: [PATCH 38/98] 8392661: [s390x] [riscv] Incorrectly attempt to reserve
address space for compressed classes using unscaled encoding instead of below
4GiB
Reviewed-by: stuefe, fyang
---
.../cpu/riscv/compressedKlass_riscv.cpp | 21 +++++++++++++------
src/hotspot/cpu/s390/compressedKlass_s390.cpp | 2 +-
...essedCPUSpecificClassSpaceReservation.java | 4 ++--
3 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/src/hotspot/cpu/riscv/compressedKlass_riscv.cpp b/src/hotspot/cpu/riscv/compressedKlass_riscv.cpp
index a2e732025d5..5881b378d60 100644
--- a/src/hotspot/cpu/riscv/compressedKlass_riscv.cpp
+++ b/src/hotspot/cpu/riscv/compressedKlass_riscv.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2023, Red Hat, Inc. All rights reserved.
- * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2026, IBM Corp. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,11 +45,19 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size
// 3) only bits in C: a 4GB-aligned address that is lower than 16TB.
// 4) only bits in D: a 16TB-aligned address.
- // First, attempt to allocate < 4GB. We do this unconditionally:
- // - if can_optimize_for_zero_base, a <4GB mapping start would allow us to run unscaled (base = 0, shift = 0)
- // - if !can_optimize_for_zero_base, a <4GB mapping start is still good, the resulting immediate can be encoded
- // with one instruction (2)
- result = reserve_address_space_for_unscaled_encoding(size, aslr);
+ // First, attempt to reserve below 4GB, regardless of CDS or COH:
+ // - With neither CDS nor COH, this permits unscaled encoding (base = 0, shift = 0).
+ // - With CDS, when the VM includes archived-heap support or COH is enabled,
+ // the base must match the archive mapping start (including the protection zone),
+ // and the shift must preserve the precomputed narrow Klass IDs.
+ // - With COH, unscaled encoding spans only 4MB (22-bit narrowKlass).
+ // Without CDS, we choose the klass range start as the base to avoid
+ // unnecessarily large shifts, rather than attempting zero-based encoding.
+ // In the nonzero-base cases, low addresses keep base materialization cheap,
+ // though not necessarily a single instruction: on RV64, a nonzero page-aligned
+ // base below 2GB needs only LUI, while bases in [2GB, 4GB) require additional
+ // instructions because LUI sign-extends its result.
+ result = reserve_address_space_below_4G(size, aslr);
// Failing that, optimize for case (3) - a base with only bits set between [32-44)
if (result == nullptr) {
diff --git a/src/hotspot/cpu/s390/compressedKlass_s390.cpp b/src/hotspot/cpu/s390/compressedKlass_s390.cpp
index 1fa2c47ad21..2b86334aece 100644
--- a/src/hotspot/cpu/s390/compressedKlass_s390.cpp
+++ b/src/hotspot/cpu/s390/compressedKlass_s390.cpp
@@ -35,7 +35,7 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size
// First, attempt to allocate < 4GB. We do this unconditionally:
// - if optimize_for_zero_base, a <4GB mapping start allows us to use base=0 shift=0
// - if !optimize_for_zero_base, a <4GB mapping start allows us to use algfi
- result = reserve_address_space_for_unscaled_encoding(size, aslr);
+ result = reserve_address_space_below_4G(size, aslr);
// Failing that, try optimized for base=0 shift>0
if (result == nullptr && optimize_for_zero_base) {
diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java
index d4287d34294..89c39b57435 100644
--- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java
+++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java
@@ -94,13 +94,13 @@ private static void do_test(boolean CDS) throws IOException {
}
output.shouldMatch(tryReserveFor16bitMoveIntoQ3Regex);
} else if (Platform.isRISCV64()) {
- output.shouldContain(tryReserveForUnscaled); // unconditionally
+ output.shouldContain(tryReserveBelow4G); // unconditionally
// bits 32..44
output.shouldContain("reserve_between (range [0x0000000100000000-0x0000100000000000)");
// bits 44..64
output.shouldContain("reserve_between (range [0x0000100000000000-0xffffffffffffffff)");
} else if (Platform.isS390x()) {
- output.shouldContain(tryReserveForUnscaled); // unconditionally
+ output.shouldContain(tryReserveBelow4G); // unconditionally
if (CDS) {
output.shouldNotContain(tryReserveForZeroBased);
} else {
From 97d3a6a2628f8e1589b962b7cc02c7fc1f9d1b6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?=
Date: Mon, 5 Oct 2026 07:07:37 +0000
Subject: [PATCH 39/98] 8392949:
compiler/valhalla/valuetypes/TestValueArgEscapeState.java fails in
valhalla-comp-stress
Co-authored-by: Quan Anh Mai
Reviewed-by: thartmann, qamai
---
.../valhalla/valuetypes/TestValueArgEscapeState.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueArgEscapeState.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueArgEscapeState.java
index 09dedf5c1a6..3df4cd930a7 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueArgEscapeState.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueArgEscapeState.java
@@ -68,6 +68,11 @@ static value class ValueHolderHolder {
}
}
+ // Just to force initialization of ValueHolder and ValueHolderHolder before
+ // the tests are compiled, in case they are run with warm-up disabled.
+ static final ValueHolderHolder LOAD_VALUE_HOLDERS =
+ new ValueHolderHolder(new ValueHolder(null));
+
static IdentityObject globalObj = null;
static ValueHolder globalHolder = null;
From 51a9c010c95ba4f36bf04f496e8ab49d8773d2a8 Mon Sep 17 00:00:00 2001
From: Quan Anh Mai
Date: Mon, 5 Oct 2026 07:20:24 +0000
Subject: [PATCH 40/98] 8390511: [Valhalla] Problems with array access using
VarHandle
Reviewed-by: thartmann, chagedorn
---
src/hotspot/share/opto/library_call.cpp | 19 +++++++
.../TestArrayVarHandleDifferentLayouts.java | 57 +++++++++++++++++++
2 files changed, 76 insertions(+)
create mode 100644 test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayVarHandleDifferentLayouts.java
diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
index 5bcd29695e9..72043317b37 100644
--- a/src/hotspot/share/opto/library_call.cpp
+++ b/src/hotspot/share/opto/library_call.cpp
@@ -2507,6 +2507,25 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
// Save state and restore on bailout
SavedState old_state(this);
+ if (const TypeAryPtr* base_ary_type = _gvn.type(base)->isa_aryptr(); type == T_OBJECT && base_ary_type != nullptr) {
+ // Read an object from a primitive array, or a Phi some of whose inputs are primitive arrays
+ if (base_ary_type->elem()->make_ptr() == nullptr) {
+ return false;
+ }
+
+ // Must not be a flat array
+ if (base_ary_type->is_flat()) {
+ return false;
+ }
+
+ // Refine the base so alias analysis can work properly
+ Node* refined_base = must_be_not_null(base, false);
+ base_ary_type = base_ary_type->cast_to_not_flat();
+ refined_base = _gvn.transform(new CheckCastPPNode(control(), base, base_ary_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing));
+ replace_in_map(base, refined_base);
+ base = refined_base;
+ }
+
Node* adr = make_unsafe_address(base, offset, type, kind == Relaxed);
assert(!stopped(), "Inlining of unsafe access failed: address construction stopped unexpectedly");
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayVarHandleDifferentLayouts.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayVarHandleDifferentLayouts.java
new file mode 100644
index 00000000000..0eea7257244
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayVarHandleDifferentLayouts.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package compiler.valhalla.valuetypes;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import jdk.internal.value.ValueClass;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @bug 8390511
+ * @summary Test VarHandle access on an array that is a merge of different layouts.
+ * @library /test/lib /
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * @run main ${test.main.class}
+ * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:CompileThreshold=1
+ * -XX:CompileOnly=${test.main.class}::* ${test.main.class}
+ */
+public class TestArrayVarHandleDifferentLayouts {
+ private static final int INDEX = 8;
+ private static final VarHandle HANDLE = MethodHandles.arrayElementVarHandle(Integer[].class);
+ private static final Integer[] FLAT = new Integer[64];
+ private static final Integer[] REFERENCE = (Integer[]) ValueClass.newReferenceArray(Integer.class, 64);
+
+ public static void main(String[] args) {
+ for (int i = 0; i < 20_000; i++) {
+ testGet((i & 1) == 0);
+ }
+ }
+
+ static Integer testGet(boolean useFlat) {
+ Integer[] array = useFlat ? FLAT : REFERENCE;
+ return (Integer)HANDLE.getVolatile(array, INDEX);
+ }
+}
From 505226bde4b8a30a5e6282164441c9afcd978bb6 Mon Sep 17 00:00:00 2001
From: Vladimir Yaroslavskiy
Date: Mon, 5 Oct 2026 07:43:41 +0000
Subject: [PATCH 41/98] 8393047: Arrays.parallelSort sorting of objects is not
stable
Reviewed-by: dl
---
.../java/util/ArraysParallelSortHelpers.java | 4 +-
test/jdk/java/util/Arrays/Sorting.java | 76 +++++++++++++------
2 files changed, 56 insertions(+), 24 deletions(-)
diff --git a/src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java b/src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java
index 5fca0cd41d6..c040bca7656 100644
--- a/src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java
+++ b/src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -201,7 +201,7 @@ public final void compute() {
T split = a[(rh = rn >>> 1) + rb];
for (int lo = 0; lo < lh; ) {
int lm = (lo + lh) >>> 1;
- if (c.compare(split, a[lm + lb]) <= 0)
+ if (c.compare(split, a[lm + lb]) < 0)
lh = lm;
else
lo = lm + 1;
diff --git a/test/jdk/java/util/Arrays/Sorting.java b/test/jdk/java/util/Arrays/Sorting.java
index 3e2ab741e31..3c1e8ed50ea 100644
--- a/test/jdk/java/util/Arrays/Sorting.java
+++ b/test/jdk/java/util/Arrays/Sorting.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,11 +50,11 @@ public class Sorting {
// Array lengths used in a long run (default)
private static final int[] LONG_RUN_LENGTHS = {
- 1, 3, 8, 21, 55, 100, 1_000, 10_000, 100_000 };
+ 1, 3, 8, 21, 55, 100, 1_000, 17_000, 100_000 };
// Array lengths used in a short run
private static final int[] SHORT_RUN_LENGTHS = {
- 1, 8, 55, 100, 10_000 };
+ 1, 8, 55, 100, 17_000 };
// Random initial values used in a long run (default)
private static final TestRandom[] LONG_RUN_RANDOMS = {
@@ -185,14 +185,32 @@ private void testEmptyArray() {
}
private void testStability(int length, TestRandom random) {
- printTestName("Test stability", random, length);
+ for (int m = 1; m <= 2 * length; m <<= 1) {
+ testStability(length, m, random);
+ }
+ }
+
+ private void testStability(int length, int m, TestRandom random) {
+ printTestName("Test stability [" + m + "]", random, length);
+
+ Pair[] a = buildRandom(length, m, random);
+ sortingHelper.sort(a);
+ checkSorted(a);
+ checkStable(a);
+ checkStableRandom(a);
+
+ a = buildRandom(length, m, random);
+ sortingHelper.sort(a, pairComparator);
+ checkSorted(a);
+ checkStable(a);
+ checkStableRandom(a);
- Pair[] a = build(length, random);
+ a = buildEqual(length, m, random);
sortingHelper.sort(a);
checkSorted(a);
checkStable(a);
- a = build(length, random);
+ a = buildEqual(length, m, random);
sortingHelper.sort(a, pairComparator);
checkSorted(a);
checkStable(a);
@@ -391,38 +409,52 @@ private void checkSorted(Point[] a, Comparator c) {
}
}
- private void checkStable(Pair[] a) {
- for (int i = 0; i < a.length / 4; ) {
+ private void checkStableRandom(Pair[] a) {
+ for (int i = 0; i < a.length / 3; ) {
int key1 = a[i].getKey();
int value1 = a[i++].getValue();
int key2 = a[i].getKey();
int value2 = a[i++].getValue();
int key3 = a[i].getKey();
int value3 = a[i++].getValue();
- int key4 = a[i].getKey();
- int value4 = a[i++].getValue();
- if (!(key1 == key2 && key2 == key3 && key3 == key4)) {
+ if (!(key1 == key2 && key2 == key3)) {
fail("Keys are different " + key1 + ", " + key2 + ", " +
- key3 + ", " + key4 + " at position " + i);
+ key3 + " at position " + i);
}
- if (!(value1 < value2 && value2 < value3 && value3 < value4)) {
+ if (!(value1 < value2 && value2 < value3)) {
fail("Sorting is not stable at position " + i +
". Second values have been changed: " + value1 + ", " +
- value2 + ", " + value3 + ", " + value4);
+ value2 + ", " + value3);
+ }
+ }
+ }
+
+ private void checkStable(Pair[] a) {
+ for (int i = 1; i < a.length; ++i) {
+ if (a[i - 1].getKey() == a[i].getKey() && a[i - 1].getValue() > a[i].getValue()) {
+ fail("Sorting is not stable at position " + i + ": " + a[i - 1] + " and " + a[i]);
}
}
}
- private Pair[] build(int length, Random random) {
- Pair[] a = new Pair[length * 4];
+ private Pair[] buildRandom(int length, int m, Random random) {
+ Pair[] a = new Pair[3 * length];
+
+ for (int i = 0, k = 0; i < a.length; ) {
+ int key = random.nextInt(m);
+ a[i++] = new Pair(key, ++k);
+ a[i++] = new Pair(key, ++k);
+ a[i++] = new Pair(key, ++k);
+ }
+ return a;
+ }
+
+ private Pair[] buildEqual(int length, int m, Random random) {
+ Pair[] a = new Pair[length];
- for (int i = 0; i < a.length; ) {
- int key = random.nextInt();
- a[i++] = new Pair(key, 1);
- a[i++] = new Pair(key, 2);
- a[i++] = new Pair(key, 3);
- a[i++] = new Pair(key, 4);
+ for (int i = 0; i < a.length; ++i) {
+ a[i] = new Pair(random.nextInt(m), i);
}
return a;
}
From fa3fee257b1e0ad5bcb8d21fcaa6a27758c62589 Mon Sep 17 00:00:00 2001
From: Tobias Hartmann
Date: Mon, 5 Oct 2026 07:51:56 +0000
Subject: [PATCH 42/98] 8393508: Disable StressCallingConvention in
TestC2CCalls.java until JDK-8393507 is fixed
Reviewed-by: chagedorn
---
.../jtreg/compiler/valhalla/valuetypes/TestC2CCalls.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC2CCalls.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC2CCalls.java
index 3cefa700e11..9ce6f5050db 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC2CCalls.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC2CCalls.java
@@ -26,6 +26,7 @@
* @key randomness
* @summary Test value class calling convention with compiled to compiled calls.
* @library /test/lib /compiler/whitebox /
+ * @requires (vm.opt.StressCallingConvention == null | !vm.opt.StressCallingConvention)
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
@@ -38,6 +39,7 @@
* @key randomness
* @summary Test value class calling convention with compiled to compiled calls.
* @library /test/lib /compiler/whitebox /
+ * @requires (vm.opt.StressCallingConvention == null | !vm.opt.StressCallingConvention)
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
@@ -53,6 +55,7 @@
* @key randomness
* @summary Test value class calling convention with compiled to compiled calls.
* @library /test/lib /compiler/whitebox /
+ * @requires (vm.opt.StressCallingConvention == null | !vm.opt.StressCallingConvention)
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
@@ -68,6 +71,7 @@
* @key randomness
* @summary Test value class calling convention with compiled to compiled calls.
* @library /test/lib /compiler/whitebox /
+ * @requires (vm.opt.StressCallingConvention == null | !vm.opt.StressCallingConvention)
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
@@ -83,6 +87,7 @@
* @key randomness
* @summary Test value class calling convention with compiled to compiled calls.
* @library /test/lib /compiler/whitebox /
+ * @requires (vm.opt.StressCallingConvention == null | !vm.opt.StressCallingConvention)
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
From 8b60fd1c9c9cfffe45a5497675b62457cc92f5b9 Mon Sep 17 00:00:00 2001
From: Tobias Hartmann
Date: Mon, 5 Oct 2026 08:05:49 +0000
Subject: [PATCH 43/98] 8393182: Improve compiler stress testing
Reviewed-by: rcastanedalo, qamai, mchevalier
---
.../arguments/TestMethodArguments.java | 19 ++--
.../compiler/c1/TestConcurrentPatching.java | 5 +-
.../c2/irTests/TestPrunedExHandler.java | 6 +-
.../TestOverloadCompileQueues.java | 5 +-
.../hotcode/StressHotCodeCollector.java | 4 +-
.../compiler/intrinsics/sha/TestDigest.java | 96 ++++++++-----------
.../sha/sanity/DigestSanityTestBase.java | 6 +-
.../lib/ir_framework/test/TestVM.java | 2 -
.../superword/TestEquivalentInvariants.java | 6 +-
.../tiered/Level2RecompilationTest.java | 5 +-
.../valuetypes/CorrectlyRestoreRfp.java | 2 +-
...PutFlatValueWithoutUseArrayFlattening.java | 11 ++-
.../valuetypes/TestArrayCopyWithOops.java | 21 ++--
.../valuetypes/TestArrayNullMarkers.java | 35 ++++---
.../compiler/valhalla/valuetypes/TestC1.java | 89 ++++++++++++++---
.../valuetypes/TestCallingConvention.java | 3 -
.../valuetypes/TestCallingConventionC1.java | 77 +++++++++++++--
.../valuetypes/TestGetfieldChains.java | 6 +-
.../valuetypes/TestMergeMemCleanup.java | 12 ++-
.../valuetypes/TestMismatchHandling.java | 20 ++--
.../valhalla/valuetypes/TestNewAcmp.java | 3 +-
.../valuetypes/TestNullableValueTypes.java | 50 +++++++---
.../TestReturnBufferClassInitialization.java | 13 ++-
.../valuetypes/TestSpeculateArrayAccess.java | 20 ++--
.../valhalla/valuetypes/TestTearing.java | 46 ++++-----
.../valuetypes/TestTrivialMethods.java | 5 +-
.../valhalla/valuetypes/TestValueClasses.java | 3 -
.../valuetypes/TestVirtualThreads.java | 81 ++++++++--------
.../TestFloat16VectorOperations.java | 20 ++--
.../VectorUnsignedMinMaxOperationsTest.java | 19 +---
.../valhalla/valuetypes/AnnotationsTests.java | 13 +--
.../valuetypes/FlatArrayCopyingTest.java | 14 ++-
.../FlatArrayLargeOverlapCopyTest.java | 5 +-
.../valuetypes/FlatFieldAccessorMethods.java | 4 +-
.../valuetypes/FlattenableSemanticTest.java | 5 +-
.../valhalla/valuetypes/ObjectMethods.java | 17 +---
.../valuetypes/TestFieldNullability.java | 3 +-
.../valuetypes/TestFlatteningBudget.java | 7 +-
.../valhalla/valuetypes/VolatileTest.java | 3 +-
.../ConcurrentClassLoadingTest.java | 5 +-
...oadFailuresDoNotImpactApplicationTest.java | 13 +--
.../AdaptiveBlocking001.java | 7 +-
42 files changed, 467 insertions(+), 319 deletions(-)
diff --git a/test/hotspot/jtreg/compiler/arguments/TestMethodArguments.java b/test/hotspot/jtreg/compiler/arguments/TestMethodArguments.java
index 306d0176aad..b29f393c30c 100644
--- a/test/hotspot/jtreg/compiler/arguments/TestMethodArguments.java
+++ b/test/hotspot/jtreg/compiler/arguments/TestMethodArguments.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
* number of parameters (according to the JVM spec).
* @library /test/lib /
* @requires vm.compMode != "Xcomp"
- * @run driver/timeout=1000 compiler.arguments.TestMethodArguments
+ * @run driver/timeout=1000 ${test.main.class}
*/
package compiler.arguments;
@@ -48,6 +48,7 @@ public class TestMethodArguments {
static final int MIN = 0;
static final int MAX = 255;
static final int INPUT_SIZE = 100;
+ static final int WARMUP_ITERATIONS = 100;
public static Template.ZeroArgs generateTest(PrimitiveType type, int numberOfArguments) {
String arguments = IntStream.range(0, numberOfArguments)
@@ -109,14 +110,17 @@ public static String generate(CompileFramework comp) {
for (int i = MIN; i <= MAX; ++i) {
tests.add(generateTest(CodeGenerationDataNameType.ints(), i).asToken());
tests.add(generateTest(CodeGenerationDataNameType.floats(), i).asToken());
- // Longs and doubles take up double as much space in the parameter list as other
- // primitive types (e.g., int). We therefore have to divide by two to fill up
- // the same amount of space as for ints and floats.
- tests.add(generateTest(CodeGenerationDataNameType.longs(), i / 2).asToken());
- tests.add(generateTest(CodeGenerationDataNameType.doubles(), i / 2).asToken());
+ }
+ // Longs and doubles take up twice as much space in the parameter list as other
+ // primitive types (e.g., int). We therefore have to divide by two to fill up
+ // the same amount of space as for ints and floats.
+ for (int i = MIN; i <= MAX / 2; ++i) {
+ tests.add(generateTest(CodeGenerationDataNameType.longs(), i).asToken());
+ tests.add(generateTest(CodeGenerationDataNameType.doubles(), i).asToken());
}
return Template.make(() -> Template.scope(
Template.let("classpath", comp.getEscapedClassPathOfCompiledClasses()),
+ Template.let("warmupIterations", WARMUP_ITERATIONS),
"""
import java.util.Arrays;
import java.util.stream.*;
@@ -133,6 +137,7 @@ public class InnerTest {
public static void main() {
TestFramework framework = new TestFramework(InnerTest.class);
+ framework.setDefaultWarmup(#warmupIterations);
framework.addFlags("-classpath", "#classpath");
framework.start();
}
diff --git a/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java
index dfd719f3a3b..147d2e2487a 100644
--- a/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java
+++ b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,8 +29,9 @@
/**
* @test
* @bug 8340313
+ * @key stress
* @summary Test that concurrent patching of oop immediates is thread-safe in C1.
- * @run main/othervm/timeout=1920 -Xcomp -XX:CompileCommand=compileonly,TestConcurrentPatching::* -XX:TieredStopAtLevel=1 TestConcurrentPatching
+ * @run main/othervm/timeout=1920 -Xcomp -XX:CompileCommand=compileonly,${test.main.class}::* -XX:TieredStopAtLevel=1 ${test.main.class}
*/
class MyClass { }
diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java
index b5a27f3f714..1c0c44aba41 100644
--- a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java
+++ b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,13 +32,13 @@
* @requires vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps
* @library /test/lib /
* @requires vm.opt.DeoptimizeALot != true
- * @run driver compiler.c2.irTests.TestPrunedExHandler
+ * @requires vm.opt.final.TieredCompilation
+ * @run driver ${test.main.class}
*/
public class TestPrunedExHandler {
public static void main(String[] args) {
TestFramework.runWithFlags(
- "-XX:+TieredCompilation", // we only profile in tier 3
"-XX:CompileCommand=inline,compiler.c2.irTests.TestPrunedExHandler::inlinee",
"-XX:CompileCommand=dontinline,compiler.c2.irTests.TestPrunedExHandler::outOfLine");
}
diff --git a/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java b/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java
index 417a6bbc00f..d3b704d2f66 100644
--- a/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java
+++ b/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java
@@ -24,11 +24,12 @@
/*
* @test TestOverloadCompileQueues
* @bug 8163511 8230402
+ * @key stress
* @summary Test overloading the C1 and C2 compile queues with tasks.
* @run main/othervm/timeout=1200 -XX:-TieredCompilation -XX:CompileThreshold=2 -XX:CICompilerCount=1
- * compiler.classUnloading.methodUnloading.TestOverloadCompileQueues
+ * ${test.main.class}
* @run main/othervm/timeout=1200 -XX:TieredCompileTaskTimeout=1000 -XX:CompileThresholdScaling=0.001 -XX:CICompilerCount=2
- * compiler.classUnloading.methodUnloading.TestOverloadCompileQueues
+ * ${test.main.class}
*/
package compiler.classUnloading.methodUnloading;
diff --git a/test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java b/test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java
index 551b9ea2fca..b6fa714d3e0 100644
--- a/test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java
+++ b/test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java
@@ -25,7 +25,7 @@
/*
* @test
- * @key randomness
+ * @key stress randomness
* @requires vm.compiler2.enabled & vm.opt.SegmentedCodeCache != false
* @library /test/lib /
* @build jdk.test.whitebox.WhiteBox
@@ -33,7 +33,7 @@
* @run main/othervm -Xbootclasspath/a:. -Xcomp -XX:-TieredCompilation -XX:+SegmentedCodeCache -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap
* -XX:+NMethodRelocation -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:HotCodeIntervalSeconds=0 -XX:HotCodeSampleSeconds=10
* -XX:HotCodeStablePercent=-1 -XX:HotCodeSamplePercent=100 -XX:HotCodeStartupDelaySeconds=0
- * compiler.hotcode.StressHotCodeCollector
+ * ${test.main.class}
*/
package compiler.hotcode;
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/TestDigest.java b/test/hotspot/jtreg/compiler/intrinsics/sha/TestDigest.java
index 286f076175e..f543fc2b5c1 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/TestDigest.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/TestDigest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,107 +28,107 @@
*
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=MD5
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-224
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-256
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-384
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-512
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-224
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-256
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-384
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-512
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
*
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=MD5 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-1 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-224 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-256 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-384 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-512 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-224 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-256 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-384 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-512 -Doffset=1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
*
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-1 -Dalgorithm2=SHA-256
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-1 -Dalgorithm2=SHA-512
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-256 -Dalgorithm2=SHA-512
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
*
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-1 -Dalgorithm2=MD5
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=MD5 -Dalgorithm2=SHA-1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
*
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-1 -Dalgorithm2=SHA3-224
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-1 -Dalgorithm2=SHA3-256
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-1 -Dalgorithm2=SHA3-384
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA-1 -Dalgorithm2=SHA3-512
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-224 -Dalgorithm2=SHA-1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-256 -Dalgorithm2=SHA-1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-384 -Dalgorithm2=SHA-1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
* @run main/othervm/timeout=600 -Xbatch
* -Dalgorithm=SHA3-512 -Dalgorithm2=SHA-1
- * compiler.intrinsics.sha.TestDigest
+ * ${test.main.class}
*/
package compiler.intrinsics.sha;
@@ -146,23 +146,21 @@ public static void main(String[] args) throws Exception {
String algorithm2 = System.getProperty("algorithm2", "");
int msgSize = Integer.getInteger("msgSize", 1024);
int offset = Integer.getInteger("offset", 0) % ALIGN;
- int iters = (args.length > 0 ? Integer.valueOf(args[0]) : 100000);
- int warmupIters = (args.length > 1 ? Integer.valueOf(args[1]) : 20000);
+ int iters = 20000;
- testDigest(provider, algorithm, msgSize, offset, iters, warmupIters);
+ testDigest(provider, algorithm, msgSize, offset, iters);
if (algorithm2.equals("") == false) {
- testDigest(provider, algorithm2, msgSize, offset, iters, warmupIters);
+ testDigest(provider, algorithm2, msgSize, offset, iters);
}
}
public static void testDigest(String provider, String algorithm, int msgSize,
- int offset, int iters, int warmupIters) throws Exception {
+ int offset, int iters) throws Exception {
System.out.println("provider = " + provider);
System.out.println("algorithm = " + algorithm);
System.out.println("msgSize = " + msgSize + " bytes");
System.out.println("offset = " + offset);
- System.out.println("iters = " + iters);
byte[] expectedHash = new byte[HASH_LEN];
byte[] hash = new byte[HASH_LEN];
@@ -179,8 +177,8 @@ public static void testDigest(String provider, String algorithm, int msgSize,
digest.update(data, offset, msgSize);
expectedHash = digest.digest();
- /* warm up */
- for (int i = 0; i < warmupIters; i++) {
+ /* trigger compilation to use intrinsics */
+ for (int i = 0; i < iters; i++) {
digest.reset();
digest.update(data, offset, msgSize);
hash = digest.digest();
@@ -196,20 +194,6 @@ public static void testDigest(String provider, String algorithm, int msgSize,
} else {
showArray(hash, "hash");
}
-
- /* measure performance */
- long start = System.nanoTime();
- for (int i = 0; i < iters; i++) {
- digest.reset();
- digest.update(data, offset, msgSize);
- hash = digest.digest();
- }
- long end = System.nanoTime();
- double total = (double)(end - start)/1e9; /* in seconds */
- double thruput = (double)msgSize*iters/1e6/total; /* in MB/s */
- System.out.println("TestDigest runtime = " + total + " seconds");
- System.out.println("TestDigest throughput = " + thruput + " MB/s");
- System.out.println();
} catch (Exception e) {
System.out.println("Exception: " + e);
//System.exit(1);
diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/DigestSanityTestBase.java b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/DigestSanityTestBase.java
index c5826479024..ba77a9b0916 100644
--- a/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/DigestSanityTestBase.java
+++ b/test/hotspot/jtreg/compiler/intrinsics/sha/sanity/DigestSanityTestBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -53,8 +53,7 @@ public class DigestSanityTestBase {
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
private static final int MSG_SIZE = 1024;
private static final int OFFSET = 0;
- private static final int ITERATIONS = 10000;
- private static final int WARMUP_ITERATIONS = WHITE_BOX.getIntxVMFlag("Tier4InvocationThreshold").intValue() + 50;
+ private static final int WARMUP_ITERATIONS = WHITE_BOX.getIntxVMFlag("Tier4InvocationThreshold").intValue() + 10_000;
private static final String PROVIDER = "SUN";
private final BooleanSupplier predicate;
@@ -88,7 +87,6 @@ public final void test() throws Exception {
TestDigest.testDigest(DigestSanityTestBase.PROVIDER, algorithm,
DigestSanityTestBase.MSG_SIZE, DigestSanityTestBase.OFFSET,
- DigestSanityTestBase.ITERATIONS,
DigestSanityTestBase.WARMUP_ITERATIONS);
}
diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java
index a8d6fbcb4e9..be189cd6f24 100644
--- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java
+++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java
@@ -492,7 +492,6 @@ private void applyForceCompileCommand(Executable ex) {
"Cannot define compilation level SKIP or WAIT_FOR_COMPILATION in @ForceCompile at " + ex);
compLevel = restrictCompLevel(forceCompileAnno.value());
if (FLIP_C1_C2) {
- compLevel = compLevel.flipCompLevel();
compLevel = restrictCompLevel(compLevel.flipCompLevel());
}
if (EXCLUDE_RANDOM) {
@@ -585,7 +584,6 @@ private void addDeclaredTest(Method m) {
}
CompLevel compLevel = restrictCompLevel(testAnno.compLevel());
if (FLIP_C1_C2) {
- compLevel = compLevel.flipCompLevel();
compLevel = restrictCompLevel(compLevel.flipCompLevel());
}
if (EXCLUDE_RANDOM) {
diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java
index 8677ae851cf..268ba59521b 100644
--- a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java
+++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@
* i.e. where the invariants have the same summands, but in a different order.
* @modules java.base/jdk.internal.misc
* @library /test/lib /
- * @run driver/timeout=4800 compiler.loopopts.superword.TestEquivalentInvariants
+ * @run driver/timeout=4800 ${test.main.class}
*/
public class TestEquivalentInvariants {
@@ -226,7 +226,7 @@ public TestEquivalentInvariants() {
}
}
- @Warmup(100)
+ @Warmup(10)
@Run(test = {"testArrayBB",
"testArrayBBInvar3",
"testMemorySegmentB",
diff --git a/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java b/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java
index 5bf031b7c4a..360120c4706 100644
--- a/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java
+++ b/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/**
* @test Level2RecompilationTest
+ * @key stress
* @summary Test downgrading mechanism from level 3 to level 2 for those profiled methods.
* @library /test/lib /
* @modules java.base/jdk.internal.misc
@@ -37,7 +38,7 @@
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCaseHelper::*
* -XX:CompileCommand=print,compiler.whitebox.SimpleTestCaseHelper::*
- * compiler.tiered.Level2RecompilationTest
+ * ${test.main.class}
*/
package compiler.tiered;
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/CorrectlyRestoreRfp.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/CorrectlyRestoreRfp.java
index e3c4957c6be..3e775ae7b26 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/CorrectlyRestoreRfp.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/CorrectlyRestoreRfp.java
@@ -23,7 +23,7 @@
/**
* @test
- * @key randomness
+ * @key stress randomness
* @summary When needing some stack extension for unpacking arguments from the non-scalarized entry point,
* on Aarch64, LR (x30) and RFP (x29) are duplicated on the stack. But x29 can be used as an ordinary
* register, and hold an oop whose value can be updated by the GC, which is aware of only one copy
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/PutFlatValueWithoutUseArrayFlattening.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/PutFlatValueWithoutUseArrayFlattening.java
index 3ef0c0f60c1..0ee5a25f6c0 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/PutFlatValueWithoutUseArrayFlattening.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/PutFlatValueWithoutUseArrayFlattening.java
@@ -26,15 +26,16 @@
* @bug 8365978
* @summary Unsafe::compareAndSetFlatValue crashes with -XX:-UseArrayFlattening
* @enablePreview
+ * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
* @library /test/lib
* @modules java.base/jdk.internal.misc
- * @run main/othervm -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.PutFlatValueWithoutUseArrayFlattening::test
+ * @run main/othervm -XX:CompileCommand=compileonly,${test.main.class}::test
* -XX:-TieredCompilation -Xcomp
* -XX:+UnlockDiagnosticVMOptions
- * -XX:-UseArrayFlattening -XX:+UseFieldFlattening -XX:+IgnoreUnrecognizedVMOptions -XX:+PreloadClasses
- * compiler.valhalla.valuetypes.PutFlatValueWithoutUseArrayFlattening
- * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:+IgnoreUnrecognizedVMOptions -XX:+PreloadClasses
- * compiler.valhalla.valuetypes.PutFlatValueWithoutUseArrayFlattening
+ * -XX:-UseArrayFlattening -XX:+UseFieldFlattening -XX:+IgnoreUnrecognizedVMOptions
+ * ${test.main.class}
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:+IgnoreUnrecognizedVMOptions
+ * ${test.main.class}
*/
package compiler.valhalla.valuetypes;
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopyWithOops.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopyWithOops.java
index b4ffb21b72d..034cb6ae5b0 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopyWithOops.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopyWithOops.java
@@ -29,35 +29,37 @@
* @enablePreview
* @modules java.base/jdk.internal.value
* java.base/jdk.internal.vm.annotation
- * @run main/timeout=240 compiler.valhalla.valuetypes.TestArrayCopyWithOops
+ * @run main/timeout=240 ${test.main.class}
*/
/*
* @test id=do
+ * @key stress
* @bug 8252506
* @summary Verify that arraycopy intrinsics properly handle flat value class arrays with oop fields.
* @library /test/lib
* @enablePreview
* @modules java.base/jdk.internal.value
* java.base/jdk.internal.vm.annotation
- * @run main/othervm/timeout=240 -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestArrayCopyWithOops::test*
- * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestArrayCopyWithOops::create*
+ * @run main/othervm/timeout=240 -XX:CompileCommand=dontinline,${test.main.class}::test*
+ * -XX:CompileCommand=dontinline,${test.main.class}::create*
* -Xbatch
- * compiler.valhalla.valuetypes.TestArrayCopyWithOops
+ * ${test.main.class}
*/
/*
* @test id=do-no-flattening
+ * @key stress
* @bug 8252506
* @summary Verify that arraycopy intrinsics properly handle flat value class arrays with oop fields.
* @library /test/lib
* @enablePreview
* @modules java.base/jdk.internal.value
* java.base/jdk.internal.vm.annotation
- * @run main/othervm/timeout=240 -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestArrayCopyWithOops::test*
- * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestArrayCopyWithOops::create*
+ * @run main/othervm/timeout=240 -XX:CompileCommand=dontinline,${test.main.class}::test*
+ * -XX:CompileCommand=dontinline,${test.main.class}::create*
* -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:-UseArrayFlattening
- * compiler.valhalla.valuetypes.TestArrayCopyWithOops
+ * ${test.main.class}
*/
package compiler.valhalla.valuetypes;
@@ -71,6 +73,7 @@
public class TestArrayCopyWithOops {
static final int LEN = 200;
+ static final int WARMUP_ITERATIONS = 20_000;
static class MyObject {
long val = Integer.MAX_VALUE;
@@ -188,7 +191,7 @@ public static void main(String[] args) {
ManyOops[] dst13 = createValueClassArray();
// Warmup runs to trigger compilation
- for (int i = 0; i < 50_000; ++i) {
+ for (int i = 0; i < WARMUP_ITERATIONS; ++i) {
test1(dst1);
test2(dst2);
test3(dst3);
@@ -234,9 +237,9 @@ public static void main(String[] args) {
Asserts.assertEquals(dst3[i].hash(), expected);
Asserts.assertEquals(dst4[i].hash(), expected);
Asserts.assertEquals(((ManyOops)dst5[i]).hash(), expected);
+ Asserts.assertEquals(((ManyOops)dst6[i]).hash(), expected);
Asserts.assertEquals(((ManyOops)dst7[i]).hash(), expected);
Asserts.assertEquals(((ManyOops)dst8[i]).hash(), expected);
- Asserts.assertEquals(((ManyOops)dst8[i]).hash(), expected);
Asserts.assertEquals(((ManyOops)dst9[i]).hash(), expected);
Asserts.assertEquals(((ManyOops)dst10[i]).hash(), expected);
Asserts.assertEquals(((ManyOops)dst11[i]).hash(), expected);
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayNullMarkers.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayNullMarkers.java
index 4d0251b2b24..d065b59a459 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayNullMarkers.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayNullMarkers.java
@@ -40,11 +40,12 @@
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=no-flattening
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -55,11 +56,12 @@
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:-UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=nAVF
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -70,11 +72,12 @@
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:-UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=AVF
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -85,11 +88,12 @@
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:-UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=AVF-nAVF
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -100,11 +104,12 @@
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:-UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=NVF
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -115,11 +120,12 @@
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:+UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=NVF-nAVF
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -130,11 +136,12 @@
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:+UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=NVF-AVF
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -145,11 +152,12 @@
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=all-flattening
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -160,11 +168,12 @@
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=all-flattening-di
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -176,11 +185,12 @@
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening
* -XX:CompileCommand=dontinline,*::test* -XX:CompileCommand=dontinline,*::check*
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
/*
* @test id=all-flattening-restrict-profiling
+ * @key stress
* @summary Test support for null markers in (flat) arrays.
* @library /test/lib /
* @enablePreview
@@ -192,7 +202,7 @@
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch
* -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening
* -XX:+IgnoreUnrecognizedVMOptions -XX:-MonomorphicArrayCheck -XX:-UseArrayLoadStoreProfile
- * compiler.valhalla.valuetypes.TestArrayNullMarkers
+ * ${test.main.class}
*/
public class TestArrayNullMarkers {
@@ -209,7 +219,7 @@ public class TestArrayNullMarkers {
// The main is huge by-design (it has been made that way to make sure that C2 sees all the type info from the array factories)
// but its size causes compilation failures with tier 3 C1 because of it runs out of virtual registers in linear scan, which
// triggers a test failure when AbortVMOnCompilationFailure is set.
- // Because this method will bail out from C1 compilation anyway, let's exclude it to prevent noise when running valhalla-comp-stress.
+ // Because this method will bail out from C1 compilation anyway, let's exclude it to prevent noise during stress testing.
static {
if (AbortVMOnCompilationFailure) {
Class> c = TestArrayNullMarkers.class;
@@ -1431,4 +1441,3 @@ public static void main(String[] args) {
testScalarReplacement8(CANARY1, true);
}
}
-
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1.java
index 98fa9ac5b4f..0adeacf46e0 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1.java
@@ -27,6 +27,7 @@
import compiler.lib.ir_framework.Run;
import compiler.lib.ir_framework.Scenario;
import compiler.lib.ir_framework.Test;
+import compiler.lib.ir_framework.TestFramework;
import jdk.test.lib.Asserts;
import jdk.internal.value.ValueClass;
@@ -37,14 +38,74 @@
import static compiler.valhalla.valuetypes.ValueTypes.rL;
/*
- * @test
+ * @test id=vanilla
* @key randomness
* @summary Various tests that are specific to C1.
* @library /test/lib /
* @enablePreview
* @modules java.base/jdk.internal.value
* java.base/jdk.internal.vm.annotation
- * @run driver/timeout=300 ${test.main.class}
+ * @run main/timeout=300 ${test.main.class} vanilla
+ */
+
+/*
+ * @test id=c1
+ * @key stress randomness
+ * @summary Various tests that are specific to C1.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 0
+ */
+
+/*
+ * @test id=c2
+ * @key stress randomness
+ * @summary Various tests that are specific to C1.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 1
+ */
+
+/*
+ * @test id=interpreter
+ * @key stress randomness
+ * @summary Various tests that are specific to C1.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 2
+ */
+
+/*
+ * @test id=xcomp-c1
+ * @key stress randomness
+ * @summary Various tests that are specific to C1.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 3
+ */
+
+/*
+ * @test id=xcomp-c2
+ * @key stress randomness
+ * @summary Various tests that are specific to C1.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 4
*/
public class TestC1 {
@@ -62,17 +123,19 @@ public static void main(String[] args) {
new Scenario(4, "-XX:TieredStopAtLevel=4", "-XX:-TieredCompilation", "-Xcomp")
};
- ValueTypes.getFramework()
- .addScenarios(scenarios)
- .addFlags("--enable-preview",
- "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
- "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED")
- .addHelperClasses(MyValue1.class,
- MyValue2.class,
- MyValue2Inline.class,
- MyValue3.class,
- MyValue3Inline.class)
- .start();
+ TestFramework framework = ValueTypes.getFramework()
+ .addFlags("--enable-preview",
+ "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
+ "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED")
+ .addHelperClasses(MyValue1.class,
+ MyValue2.class,
+ MyValue2Inline.class,
+ MyValue3.class,
+ MyValue3Inline.class);
+ if (!args[0].equals("vanilla")) {
+ framework.addScenarios(scenarios[Integer.parseInt(args[0])]);
+ }
+ framework.start();
}
// JDK-8229799
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java
index 655793c1ba6..880a089a950 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java
@@ -171,9 +171,6 @@ public TestCallingConvention() {
public static void main(String[] args) {
Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS;
- // Don't generate bytecodes but call through runtime for reflective calls
- scenarios[0].addFlags("-Dsun.reflect.inflationThreshold=10000");
- scenarios[1].addFlags("-Dsun.reflect.inflationThreshold=10000");
scenarios[3].addFlags("-XX:-UseArrayFlattening");
scenarios[4].addFlags("-XX:-UseTLAB");
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java
index f9e3b05d771..a411ceea1f2 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java
@@ -34,14 +34,74 @@
import static compiler.valhalla.valuetypes.ValueTypes.rL;
/*
- * @test
+ * @test id=vanilla
* @key randomness
* @summary Test calls from {C1} to {C2, Interpreter}, and vice versa.
* @library /test/lib /
* @enablePreview
* @modules java.base/jdk.internal.value
* java.base/jdk.internal.vm.annotation
- * @run driver/timeout=300 ${test.main.class}
+ * @run main/timeout=300 ${test.main.class} vanilla
+ */
+
+/*
+ * @test id=default
+ * @key stress randomness
+ * @summary Test calls from {C1} to {C2, Interpreter}, and vice versa.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 0
+ */
+
+/*
+ * @test id=stress-calling-convention
+ * @key stress randomness
+ * @summary Test calls from {C1} to {C2, Interpreter}, and vice versa.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 1
+ */
+
+/*
+ * @test id=flip-c1-c2
+ * @key stress randomness
+ * @summary Test calls from {C1} to {C2, Interpreter}, and vice versa.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 2
+ */
+
+/*
+ * @test id=c1
+ * @key stress randomness
+ * @summary Test calls from {C1} to {C2, Interpreter}, and vice versa.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 3
+ */
+
+/*
+ * @test id=c2
+ * @key stress randomness
+ * @summary Test calls from {C1} to {C2, Interpreter}, and vice versa.
+ * @library /test/lib /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @run driver/timeout=300 ${test.main.class} 4
*/
@ForceCompileClassInitializer
@@ -51,13 +111,11 @@ public static void main(String[] args) {
final Scenario[] scenarios = {
// Default: both C1 and C2 are enabled, tiered compilation enabled
new Scenario(0,
- "--enable-preview",
"-XX:CICompilerCount=2",
"-XX:TieredStopAtLevel=4",
"-XX:+TieredCompilation"),
// Default: both C1 and C2 are enabled, tiered compilation enabled
new Scenario(1,
- "--enable-preview",
"-XX:CICompilerCount=2",
"-XX:TieredStopAtLevel=4",
"-XX:+TieredCompilation",
@@ -66,30 +124,29 @@ public static void main(String[] args) {
// Same as above, but flip all the compLevel=CompLevel.C1_SIMPLE and compLevel=CompLevel.C2, so we test
// the compliment of the above scenario.
new Scenario(2,
- "--enable-preview",
"-XX:CICompilerCount=2",
"-XX:TieredStopAtLevel=4",
"-XX:+TieredCompilation",
"-DFlipC1C2=true"),
// Only C1. Tiered compilation disabled.
new Scenario(3,
- "--enable-preview",
"-XX:TieredStopAtLevel=1",
"-XX:+TieredCompilation",
"-XX:+IgnoreUnrecognizedVMOptions",
"-XX:-PatchALot"),
// Only C2.
new Scenario(4,
- "--enable-preview",
"-XX:TieredStopAtLevel=4",
"-XX:-TieredCompilation")
};
System.gc(); // Resolve this call, to avoid C1 code patching in the test cases.
- ValueTypes.getFramework()
- .addScenarios(scenarios)
- .start();
+ TestFramework framework = ValueTypes.getFramework().addFlags("--enable-preview");
+ if (!args[0].equals("vanilla")) {
+ framework.addScenarios(scenarios[Integer.parseInt(args[0])]);
+ }
+ framework.start();
}
// Helper methods and classes
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetfieldChains.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetfieldChains.java
index 7b3b31dc87f..279d14240c0 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetfieldChains.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetfieldChains.java
@@ -94,8 +94,7 @@ public static void main(String[] args) {
new Scenario(1,
// C2 only. (Make sure the tests are correctly written)
"-XX:TieredStopAtLevel=4",
- "-XX:-TieredCompilation",
- "-XX:-OmitStackTraceInFastThrow"),
+ "-XX:-TieredCompilation"),
new Scenario(2,
// interpreter only
"-Xint"),
@@ -108,13 +107,12 @@ public static void main(String[] args) {
// Xcomp Only C2
"-XX:TieredStopAtLevel=4",
"-XX:-TieredCompilation",
- "-XX:-OmitStackTraceInFastThrow",
"-Xcomp")
};
ValueTypes.getFramework()
.addScenarios(scenarios)
- .addFlags("--enable-preview",
+ .addFlags("--enable-preview", "-XX:-OmitStackTraceInFastThrow",
"--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
"--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED")
.start();
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMergeMemCleanup.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMergeMemCleanup.java
index e3d48c50e68..79c58287f78 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMergeMemCleanup.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMergeMemCleanup.java
@@ -22,13 +22,21 @@
*/
/*
- * @test
+ * @test id=vanilla
* @bug 8391658
* @summary Test cleanup of nested MergeMems after incremental inlining.
- * @key stress randomness
* @requires vm.compiler2.enabled
* @enablePreview
* @run main ${test.main.class}
+ */
+
+/*
+ * @test id=stress
+ * @bug 8391658
+ * @summary Test cleanup of nested MergeMems after incremental inlining.
+ * @key stress randomness
+ * @requires vm.compiler2.enabled
+ * @enablePreview
* @run main/othervm -Xbatch -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions
* -XX:+StressIGVN -XX:+StressIncrementalInlining -XX:StressSeed=3860063970
* -XX:CompileCommand=compileonly,${test.main.class}::test
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.java
index 1a0a56e26e6..b64328548e1 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,7 @@
/**
* @test
* @bug 8301007
- * @key randomness
+ * @key stress randomness
* @summary Verify that mismatches of the preload attribute are properly handled in the calling convention.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -33,34 +33,34 @@
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch
* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile
- * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestMismatchHandling::test*
- * compiler.valhalla.valuetypes.TestMismatchHandling
+ * -XX:CompileCommand=compileonly,${test.main.class}::test*
+ * ${test.main.class}
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch
* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile
* -XX:CompileCommand=compileonly,*::method
- * compiler.valhalla.valuetypes.TestMismatchHandling
+ * ${test.main.class}
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch
* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile
- * compiler.valhalla.valuetypes.TestMismatchHandling
+ * ${test.main.class}
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch
* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile
* -XX:-ValueTypePassFieldsAsArgs
- * compiler.valhalla.valuetypes.TestMismatchHandling
+ * ${test.main.class}
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch
* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile
* -XX:-ValueTypeReturnedAsFields
- * compiler.valhalla.valuetypes.TestMismatchHandling
+ * ${test.main.class}
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch
* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:+DeoptimizeNMethodBarriersALot
- * compiler.valhalla.valuetypes.TestMismatchHandling
+ * ${test.main.class}
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch
* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- * compiler.valhalla.valuetypes.TestMismatchHandling
+ * ${test.main.class}
*/
// ##################################### WARNING ######################################
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java
index dad60af136d..6f0ee93f9f4 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java
@@ -23,13 +23,14 @@
/**
* @test TestNewAcmp
+ * @key stress
* @summary Verifies correctness of the acmp bytecode with value object operands.
* @library /testlibrary /test/lib /compiler/whitebox /
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- * compiler.valhalla.valuetypes.TestNewAcmp
+ * ${test.main.class}
*/
package compiler.valhalla.valuetypes;
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java
index 7948bac145e..61e168ae1cc 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java
@@ -50,7 +50,7 @@
import static compiler.lib.ir_framework.IRNode.UNSTABLE_IF_TRAP;
/*
- * @test
+ * @test id=vanilla
* @key randomness
* @summary Test correct handling of nullable value classes.
* @library /test/lib /test/jdk/java/lang/invoke/common /
@@ -59,12 +59,26 @@
* @modules java.base/jdk.internal.value
* java.base/jdk.internal.vm.annotation
* @build test.java.lang.invoke.lib.InstructionHelper
+ * @run main ${test.main.class} vanilla
+ */
+
+/*
+ * @test
+ * @key stress randomness
+ * @summary Test correct handling of nullable value classes.
+ * @library /test/lib /test/jdk/java/lang/invoke/common /
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64")
+ * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
+ * @enablePreview
+ * @modules java.base/jdk.internal.value
+ * java.base/jdk.internal.vm.annotation
+ * @build test.java.lang.invoke.lib.InstructionHelper
* @run driver ${test.main.class} 0
*/
/*
* @test
- * @key randomness
+ * @key stress randomness
* @summary Test correct handling of nullable value classes.
* @library /test/lib /test/jdk/java/lang/invoke/common /
* @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
@@ -77,7 +91,7 @@
/*
* @test
- * @key randomness
+ * @key stress randomness
* @summary Test correct handling of nullable value classes.
* @library /test/lib /test/jdk/java/lang/invoke/common /
* @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
@@ -90,7 +104,7 @@
/*
* @test
- * @key randomness
+ * @key stress randomness
* @summary Test correct handling of nullable value classes.
* @library /test/lib /test/jdk/java/lang/invoke/common /
* @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
@@ -103,7 +117,7 @@
/*
* @test
- * @key randomness
+ * @key stress randomness
* @summary Test correct handling of nullable value classes.
* @library /test/lib /test/jdk/java/lang/invoke/common /
* @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
@@ -116,7 +130,7 @@
/*
* @test
- * @key randomness
+ * @key stress randomness
* @summary Test correct handling of nullable value classes.
* @library /test/lib /test/jdk/java/lang/invoke/common /
* @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
@@ -129,7 +143,7 @@
/*
* @test
- * @key randomness
+ * @key stress randomness
* @summary Test correct handling of nullable value classes.
* @library /test/lib /test/jdk/java/lang/invoke/common /
* @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
@@ -155,19 +169,25 @@ public TestNullableValueTypes() {
}
public static void main(String[] args) {
+ TestFramework framework = ValueTypes.getFramework()
+ .addHelperClasses(MyValue1.class,
+ MyValue2.class,
+ MyValue2Inline.class,
+ MyValue3.class,
+ MyValue3Inline.class);
+
+ if (args.length > 0 && args[0].equals("vanilla")) {
+ framework.addFlags("--enable-preview",
+ "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED",
+ "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED").start();
+ return;
+ }
Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS;
scenarios[3].addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck");
scenarios[4].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck");
- ValueTypes.getFramework()
- .addScenarios(scenarios[Integer.parseInt(args[0])])
- .addHelperClasses(MyValue1.class,
- MyValue2.class,
- MyValue2Inline.class,
- MyValue3.class,
- MyValue3Inline.class)
- .start();
+ framework.addScenarios(scenarios[Integer.parseInt(args[0])]).start();
}
static {
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnBufferClassInitialization.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnBufferClassInitialization.java
index c05e863f16a..1cb61a6d953 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnBufferClassInitialization.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnBufferClassInitialization.java
@@ -22,14 +22,23 @@
*/
/**
- * @test
+ * @test id=vanilla
* @bug 8389391
- * @key stress randomness
* @summary Return buffer allocation for late-inlined MH calls should not initialize the class.
* @requires vm.compiler2.enabled
* @library /test/lib
* @enablePreview
* @run main ${test.main.class}
+ */
+
+/**
+ * @test id=stress
+ * @bug 8389391
+ * @key stress randomness
+ * @summary Return buffer allocation for late-inlined MH calls should not initialize the class.
+ * @requires vm.compiler2.enabled
+ * @library /test/lib
+ * @enablePreview
* @run main/othervm -Xbatch -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions
* -XX:+StressIncrementalInlining -XX:StressSeed=1
* -XX:CompileCommand=exclude,${test.main.class}::target
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSpeculateArrayAccess.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSpeculateArrayAccess.java
index 0fb7627e04e..757e30d723f 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSpeculateArrayAccess.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSpeculateArrayAccess.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,16 +22,23 @@
*/
/**
- * @test
+ * @test id=vanilla
+ * @bug 8333889
+ * @summary Test that speculative array access checks do not cause a load to be wrongly hoisted before its range check.
+ * @run main ${test.main.class}
+ */
+
+/**
+ * @test id=stress
* @key stress randomness
* @bug 8333889
* @summary Test that speculative array access checks do not cause a load to be wrongly hoisted before its range check.
- * @run main/othervm -XX:CompileCommand=dontinline,*::* -XX:CompileCommand=compileonly,*TestSpeculateArrayAccess::test
+ * @run main/othervm -XX:CompileCommand=dontinline,*::* -XX:CompileCommand=compileonly,${test.main.class}::test
* -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=1202682944
- * compiler.valhalla.valuetypes.TestSpeculateArrayAccess
- * @run main/othervm -XX:CompileCommand=dontinline,*::* -XX:CompileCommand=compileonly,*TestSpeculateArrayAccess::test
+ * ${test.main.class}
+ * @run main/othervm -XX:CompileCommand=dontinline,*::* -XX:CompileCommand=compileonly,${test.main.class}::test
* -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM
- * compiler.valhalla.valuetypes.TestSpeculateArrayAccess
+ * ${test.main.class}
*/
package compiler.valhalla.valuetypes;
@@ -73,4 +80,3 @@ static void test() {
}
}
}
-
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTearing.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTearing.java
index da8ec541405..07bc9585997 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTearing.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTearing.java
@@ -36,7 +36,7 @@
/*
* @test id=no-flattening
- * @key randomness
+ * @key stress randomness
* @requires vm.compMode != "Xint" & vm.flavor == "server"
* @summary Detect tearing on flat accesses and buffering.
* @library /testlibrary /test/lib /
@@ -49,12 +49,12 @@
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:-UseFieldFlattening -XX:-UseArrayFlattening
* -XX:+StressGCM -XX:+StressLCM
- * compiler.valhalla.valuetypes.TestTearing
+ * ${test.main.class}
*/
/*
* @test id=no-flattening-AII
- * @key randomness
+ * @key stress randomness
* @requires vm.compMode != "Xint" & vm.flavor == "server"
* @summary Detect tearing on flat accesses and buffering.
* @library /testlibrary /test/lib /
@@ -68,12 +68,12 @@
* -XX:+WhiteBoxAPI -XX:-UseFieldFlattening -XX:-UseArrayFlattening
* -XX:+StressGCM -XX:+StressLCM
* -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline
- * compiler.valhalla.valuetypes.TestTearing
+ * ${test.main.class}
*/
/*
* @test id=no-flattening-di
- * @key randomness
+ * @key stress randomness
* @requires vm.compMode != "Xint" & vm.flavor == "server"
* @summary Detect tearing on flat accesses and buffering.
* @library /testlibrary /test/lib /
@@ -87,12 +87,12 @@
* -XX:+WhiteBoxAPI -XX:-UseFieldFlattening -XX:-UseArrayFlattening
* -XX:CompileCommand=dontinline,*::incrementAndCheck*
* -XX:+StressGCM -XX:+StressLCM
- * compiler.valhalla.valuetypes.TestTearing
+ * ${test.main.class}
*/
/*
* @test id=no-flattening-di-AII
- * @key randomness
+ * @key stress randomness
* @requires vm.compMode != "Xint" & vm.flavor == "server"
* @summary Detect tearing on flat accesses and buffering.
* @library /testlibrary /test/lib /
@@ -107,12 +107,12 @@
* -XX:CompileCommand=dontinline,*::incrementAndCheck*
* -XX:+StressGCM -XX:+StressLCM
* -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline
- * compiler.valhalla.valuetypes.TestTearing
+ * ${test.main.class}
*/
/*
* @test id=xcomp-no-stress
- * @key randomness
+ * @key stress randomness
* @requires vm.compMode != "Xint" & vm.flavor == "server"
* @summary Detect tearing on flat accesses and buffering.
* @library /testlibrary /test/lib /
@@ -125,12 +125,12 @@
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+WhiteBoxAPI -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseArrayFlattening
* -Xcomp -XX:-TieredCompilation
- * compiler.valhalla.valuetypes.TestTearing
+ * ${test.main.class}
*/
/*
* @test id=flattening
- * @key randomness
+ * @key stress randomness
* @requires vm.compMode != "Xint" & vm.flavor == "server"
* @summary Detect tearing on flat accesses and buffering.
* @library /testlibrary /test/lib /
@@ -143,12 +143,12 @@
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+WhiteBoxAPI -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseArrayFlattening
* -XX:+StressGCM -XX:+StressLCM
- * compiler.valhalla.valuetypes.TestTearing
+ * ${test.main.class}
*/
/*
* @test id=flattening-AII
- * @key randomness
+ * @key stress randomness
* @requires vm.compMode != "Xint" & vm.flavor == "server"
* @summary Detect tearing on flat accesses and buffering.
* @library /testlibrary /test/lib /
@@ -162,12 +162,12 @@
* -XX:+WhiteBoxAPI -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseArrayFlattening
* -XX:+StressGCM -XX:+StressLCM
* -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline
- * compiler.valhalla.valuetypes.TestTearing
+ * ${test.main.class}
*/
/*
* @test id=flattening-di
- * @key randomness
+ * @key stress randomness
* @requires vm.compMode != "Xint" & vm.flavor == "server"
* @summary Detect tearing on flat accesses and buffering.
* @library /testlibrary /test/lib /
@@ -181,12 +181,12 @@
* -XX:+WhiteBoxAPI -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseArrayFlattening
* -XX:CompileCommand=dontinline,*::incrementAndCheck*
* -XX:+StressGCM -XX:+StressLCM
- * compiler.valhalla.valuetypes.TestTearing
+ * ${test.main.class}
*/
/*
* @test id=flattening-di-AII
- * @key randomness
+ * @key stress randomness
* @requires vm.compMode != "Xint" & vm.flavor == "server"
* @summary Detect tearing on flat accesses and buffering.
* @library /testlibrary /test/lib /
@@ -201,7 +201,7 @@
* -XX:CompileCommand=dontinline,*::incrementAndCheck*
* -XX:+StressGCM -XX:+StressLCM
* -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline
- * compiler.valhalla.valuetypes.TestTearing
+ * ${test.main.class}
*/
@LooselyConsistentValue
@@ -422,11 +422,13 @@ public static void main(String[] args) throws Exception {
loopLimit = 50_000;
}
TestTearing test = new TestTearing();
- Thread runner = null;
+ Runner[] runners = new Runner[10];
for (int i = 0; i < 10; ++i) {
- runner = new Runner(test, loopLimit);
- runner.start();
+ runners[i] = new Runner(test, loopLimit);
+ runners[i].start();
+ }
+ for (Runner runner : runners) {
+ runner.join();
}
- runner.join();
}
}
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTrivialMethods.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTrivialMethods.java
index 7b7ce657529..93995617752 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTrivialMethods.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTrivialMethods.java
@@ -27,6 +27,7 @@
* @summary Verify that trivial accessor methods operating on a value type
* field are C2 compiled to enable scalarization of the arg/return value.
* @requires vm.compiler2.enabled
+ * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
* @library /test/lib /compiler/whitebox /
* @enablePreview
* @modules java.base/jdk.internal.value
@@ -39,8 +40,8 @@
* -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields
* -XX:+IgnoreUnrecognizedVMOptions -XX:-StressCallingConvention
* -XX:CompileCommand=dontinline,*::getter* -XX:CompileCommand=dontinline,*::setter*
- * -XX:CompileCommand=dontinline,*::constantGetter* -XX:+PreloadClasses
- * compiler.valhalla.valuetypes.TestTrivialMethods
+ * -XX:CompileCommand=dontinline,*::constantGetter*
+ * ${test.main.class}
*/
package compiler.valhalla.valuetypes;
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClasses.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClasses.java
index 126611733c3..0c98b5a3346 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClasses.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClasses.java
@@ -119,9 +119,6 @@ public class TestValueClasses {
public static void main(String[] args) {
Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS;
- // Don't generate bytecodes but call through runtime for reflective calls
- scenarios[0].addFlags("-Dsun.reflect.inflationThreshold=10000");
- scenarios[1].addFlags("-Dsun.reflect.inflationThreshold=10000");
scenarios[3].addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck");
scenarios[4].addFlags("-XX:-UseTLAB", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck");
diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreads.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreads.java
index a9b4dbfaac2..fadd3672c0d 100644
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreads.java
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreads.java
@@ -23,7 +23,7 @@
/*
* @test id=default
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -31,38 +31,38 @@
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- * compiler.valhalla.valuetypes.TestVirtualThreads
+ * ${test.main.class}
*/
/*
* @test id=ci
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- * -Xbatch -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::*
- * compiler.valhalla.valuetypes.TestVirtualThreads
+ * -Xbatch -XX:CompileCommand=compileonly,${test.main.class}*::*
+ * ${test.main.class}
*/
/*
* @test id=ci-test
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- * -Xbatch -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test*
- * compiler.valhalla.valuetypes.TestVirtualThreads
+ * -Xbatch -XX:CompileCommand=compileonly,${test.main.class}*::test*
+ * ${test.main.class}
*/
/*
* @test id=ci-test-di
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -70,14 +70,14 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -Xbatch -XX:CompileCommand=dontinline,*::dontinline
- * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test*
+ * -XX:CompileCommand=compileonly,${test.main.class}*::test*
* -XX:CompileCommand=dontinline,*::test*
- * compiler.valhalla.valuetypes.TestVirtualThreads
+ * ${test.main.class}
*/
/*
* @test id=ci-test-di-helper
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -85,14 +85,14 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -Xbatch -XX:CompileCommand=dontinline,*::dontinline
- * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test*
+ * -XX:CompileCommand=compileonly,${test.main.class}*::test*
* -XX:CompileCommand=dontinline,*::*Helper
- * compiler.valhalla.valuetypes.TestVirtualThreads
+ * ${test.main.class}
*/
/*
* @test id=ci-test-di-exclude-helper
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -100,40 +100,40 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -Xbatch -XX:CompileCommand=dontinline,*::dontinline
- * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test*
+ * -XX:CompileCommand=compileonly,${test.main.class}*::test*
* -XX:CompileCommand=exclude,*::*Helper
- * compiler.valhalla.valuetypes.TestVirtualThreads
+ * ${test.main.class}
*/
/*
* @test id=xcomp-ci
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- * -Xcomp -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::*
- * compiler.valhalla.valuetypes.TestVirtualThreads 50000
+ * -Xcomp -XX:CompileCommand=compileonly,${test.main.class}*::*
+ * ${test.main.class} 50000
*/
/*
* @test id=xcomp-co-test
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- * -Xcomp -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test*
- * compiler.valhalla.valuetypes.TestVirtualThreads 50000
+ * -Xcomp -XX:CompileCommand=compileonly,${test.main.class}*::test*
+ * ${test.main.class} 50000
*/
/*
* @test id=xcomp-co-test-di
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -141,14 +141,14 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -Xcomp -XX:CompileCommand=dontinline,*::dontinline
- * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test*
+ * -XX:CompileCommand=compileonly,${test.main.class}*::test*
* -XX:CompileCommand=dontinline,*::test*
- * compiler.valhalla.valuetypes.TestVirtualThreads 50000
+ * ${test.main.class} 50000
*/
/*
* @test id=xcomp-co-test-di-helper
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -156,14 +156,14 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -Xcomp -XX:CompileCommand=dontinline,*::dontinline
- * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test*
+ * -XX:CompileCommand=compileonly,${test.main.class}*::test*
* -XX:CompileCommand=dontinline,*::*Helper
- * compiler.valhalla.valuetypes.TestVirtualThreads 50000
+ * ${test.main.class} 50000
*/
/*
* @test id=xcomp-co-test-di-exclude-helper
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -171,14 +171,14 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -Xcomp -XX:CompileCommand=dontinline,*::dontinline
- * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test*
+ * -XX:CompileCommand=compileonly,${test.main.class}*::test*
* -XX:CompileCommand=exclude,*::*Helper
- * compiler.valhalla.valuetypes.TestVirtualThreads 50000
+ * ${test.main.class} 50000
*/
/*
* @test id=co-di
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -186,13 +186,13 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -Xbatch -XX:CompileCommand=dontinline,*::*
- * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::*
- * compiler.valhalla.valuetypes.TestVirtualThreads 50000
+ * -XX:CompileCommand=compileonly,${test.main.class}*::*
+ * ${test.main.class} 50000
*/
/*
* @test id=xcomp-co-di
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -200,13 +200,13 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -Xcomp -XX:CompileCommand=dontinline,*::*
- * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::*
- * compiler.valhalla.valuetypes.TestVirtualThreads 50000
+ * -XX:CompileCommand=compileonly,${test.main.class}*::*
+ * ${test.main.class} 50000
*/
/*
* @test id=verify-cont
- * @key randomness
+ * @key stress randomness
* @summary Test that Virtual Threads work well with Value Objects.
* @library /test/lib /compiler/whitebox /
* @enablePreview
@@ -215,7 +215,7 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:+VerifyContinuations
- * compiler.valhalla.valuetypes.TestVirtualThreads
+ * ${test.main.class}
*/
package compiler.valhalla.valuetypes;
@@ -828,4 +828,3 @@ public static void main(String[] args) throws Exception {
}
}
}
-
diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorOperations.java b/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorOperations.java
index f627f2fbf62..960f2603789 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorOperations.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorOperations.java
@@ -28,7 +28,7 @@
* @modules jdk.incubator.vector
* @library /test/lib /
* @compile TestFloat16VectorOperations.java
-* @run driver/timeout=480 compiler.vectorapi.TestFloat16VectorOperations
+* @run driver/timeout=480 ${test.main.class}
*/
package compiler.vectorapi;
@@ -54,16 +54,22 @@ public class TestFloat16VectorOperations {
public static void main(String args[]) {
// Test with default MaxVectorSize
- TestFramework.runWithFlags("--add-modules=jdk.incubator.vector");
+ runTest();
// Test with different values of MaxVectorSize
- TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:MaxVectorSize=8");
- TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:MaxVectorSize=16");
- TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:MaxVectorSize=32");
- TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:MaxVectorSize=64");
+ runTest("-XX:MaxVectorSize=8");
+ runTest("-XX:MaxVectorSize=16");
+ runTest("-XX:MaxVectorSize=32");
+ runTest("-XX:MaxVectorSize=64");
// Test with FMA instructions disabled
- TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:-UseFMA");
+ runTest("-XX:-UseFMA",
+ "-DTest=vectorFmaFloat16,vectorFmaFloat16ScalarMixedConstants," +
+ "vectorFmaFloat16MixedConstants,vectorFmaFloat16AllConstants");
+ }
+
+ private static void runTest(String... flags) {
+ new TestFramework().setDefaultWarmup(50).addFlags("--add-modules=jdk.incubator.vector").addFlags(flags).start();
}
static void assertResults(int arity, short ... values) {
diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java
index b1b98306312..923d8fc7c0c 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java
@@ -27,7 +27,7 @@
* @summary Unsigned Vector Min / Max transforms
* @modules jdk.incubator.vector
* @library /test/lib /
-* @run driver compiler.vectorapi.VectorUnsignedMinMaxOperationsTest
+* @run driver ${test.main.class}
*/
package compiler.vectorapi;
@@ -63,7 +63,7 @@ public class VectorUnsignedMinMaxOperationsTest {
public static void main(String[] args) {
TestFramework testFramework = new TestFramework();
- testFramework.setDefaultWarmup(5000)
+ testFramework.setDefaultWarmup(100)
.addFlags("--add-modules=jdk.incubator.vector")
.start();
}
@@ -117,7 +117,6 @@ public VectorUnsignedMinMaxOperationsTest() {
@Test
@IR(counts = {IRNode.UMAX_VB, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umax_byte() {
for (int i = 0; i < COUNT; i += bspec.length()) {
ByteVector.fromArray(bspec, byte_in1, i)
@@ -140,7 +139,6 @@ public void umax_byte_verify() {
@Test
@IR(counts = {IRNode.UMAX_VS, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umax_short() {
for (int i = 0; i < COUNT; i += sspec.length()) {
ShortVector.fromArray(sspec, short_in1, i)
@@ -163,7 +161,6 @@ public void umax_short_verify() {
@Test
@IR(counts = {IRNode.UMAX_VI, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umax_int() {
for (int i = 0; i < COUNT; i += ispec.length()) {
IntVector.fromArray(ispec, int_in1, i)
@@ -186,7 +183,6 @@ public void umax_int_verify() {
@Test
@IR(counts = {IRNode.UMAX_VL, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umax_long() {
for (int i = 0; i < COUNT; i += lspec.length()) {
LongVector.fromArray(lspec, long_in1, i)
@@ -209,7 +205,6 @@ public void umax_long_verify() {
@Test
@IR(counts = {IRNode.UMIN_VB, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_byte() {
for (int i = 0; i < COUNT; i += bspec.length()) {
ByteVector.fromArray(bspec, byte_in1, i)
@@ -232,7 +227,6 @@ public void umin_byte_verify() {
@Test
@IR(counts = {IRNode.UMIN_VS, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_short() {
for (int i = 0; i < COUNT; i += sspec.length()) {
ShortVector.fromArray(sspec, short_in1, i)
@@ -255,7 +249,6 @@ public void umin_short_verify() {
@Test
@IR(counts = {IRNode.UMIN_VI, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_int() {
for (int i = 0; i < COUNT; i += ispec.length()) {
IntVector.fromArray(ispec, int_in1, i)
@@ -278,7 +271,6 @@ public void umin_int_verify() {
@Test
@IR(counts = {IRNode.UMIN_VL, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_long() {
for (int i = 0; i < COUNT; i += lspec.length()) {
LongVector.fromArray(lspec, long_in1, i)
@@ -301,7 +293,6 @@ public void umin_long_verify() {
@Test
@IR(counts = {IRNode.UMIN_VI, " 0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_ir_transform1() {
for (int i = 0; i < COUNT; i += ispec.length()) {
IntVector.fromArray(ispec, int_in1, i)
@@ -324,7 +315,6 @@ public void umin_ir_transform1_verify() {
@Test
@IR(counts = {IRNode.UMAX_VI, " 0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umax_ir_transform1() {
for (int i = 0; i < COUNT; i += ispec.length()) {
IntVector.fromArray(ispec, int_in1, i)
@@ -347,7 +337,6 @@ public void umax_ir_transform1_verify() {
@Test
@IR(counts = {IRNode.UMAX_VI, " 0 ", IRNode.UMIN_VI, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_max_ir_transform1() {
for (int i = 0; i < COUNT; i += ispec.length()) {
IntVector vec1 = IntVector.fromArray(ispec, int_in1, i);
@@ -374,7 +363,6 @@ public void umin_max_ir_transform1_verify() {
@Test
@IR(counts = {IRNode.UMIN_VI, " 0 ", IRNode.UMAX_VI, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_max_ir_transform2() {
for (int i = 0; i < COUNT; i += ispec.length()) {
IntVector vec1 = IntVector.fromArray(ispec, int_in1, i);
@@ -401,7 +389,6 @@ public void umin_max_ir_transform2_verify() {
@Test
@IR(counts = {IRNode.UMAX_VI, " 0 ", IRNode.UMIN_VI, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_max_ir_transform3() {
for (int i = 0; i < COUNT; i += ispec.length()) {
IntVector vec1 = IntVector.fromArray(ispec, int_in1, i);
@@ -428,7 +415,6 @@ public void umin_max_ir_transform3_verify() {
@Test
@IR(counts = {IRNode.UMIN_VI, " 0 ", IRNode.UMAX_VI, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_max_ir_transform4() {
for (int i = 0; i < COUNT; i += ispec.length()) {
IntVector vec1 = IntVector.fromArray(ispec, int_in1, i);
@@ -455,7 +441,6 @@ public void umin_max_ir_transform4_verify() {
@Test
@IR(counts = {IRNode.UMIN_VI, " 0 ", IRNode.UMAX_VI, " >0 "}, applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
- @Warmup(value = 10000)
public void umin_max_ir_transform5() {
for (int i = 0; i < COUNT; i += ispec.length()) {
IntVector vec1 = IntVector.fromArray(ispec, int_in1, i);
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/AnnotationsTests.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/AnnotationsTests.java
index ad5933d4911..cff1f13a1de 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/AnnotationsTests.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/AnnotationsTests.java
@@ -41,13 +41,15 @@
* java.base/jdk.internal.vm.annotation
* @library /test/lib
* @enablePreview
+ * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI runtime.valhalla.valuetypes.AnnotationsTests
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ${test.main.class}
*/
public class AnnotationsTests {
private static final WhiteBox WHITEBOX = WhiteBox.getWhiteBox();
+ private static final boolean UseFieldFlattening = WHITEBOX.getBooleanVMFlag("UseFieldFlattening");
private static final boolean UseNullableAtomicValueFlattening = WHITEBOX.getBooleanVMFlag("UseNullableAtomicValueFlattening");
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
@@ -110,13 +112,9 @@ void test_5() {
try {
GoodClass5 vc = new GoodClass5();
Field f0 = vc.getClass().getDeclaredField("f0");
- if (UseNullableAtomicValueFlattening) {
- Asserts.assertTrue(UNSAFE.isFlatField(f0), "Flat field expected, but field is not flat");
- } else {
- Asserts.assertFalse(UNSAFE.isFlatField(f0), "Unexpected flat field");
- }
+ Asserts.assertEquals(UNSAFE.isFlatField(f0), UseFieldFlattening && UseNullableAtomicValueFlattening, "Unexpected flatness");
Field f1 = vc.getClass().getDeclaredField("f1");
- Asserts.assertTrue(UNSAFE.isFlatField(f1), "Flat field expected, but field is not flat");
+ Asserts.assertEquals(UNSAFE.isFlatField(f1), UseFieldFlattening, "Unexpected flatness");
} catch (IncompatibleClassChangeError e) {
exception = e;
System.out.println("Received " + e);
@@ -289,4 +287,3 @@ void test_13() {
}
}
-
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayCopyingTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayCopyingTest.java
index 17d1bf6404c..3ba7597b6d6 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayCopyingTest.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayCopyingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,9 +36,8 @@
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run junit/othervm/timeout=480 -Xint -XX:+UseSerialGC -XX:+UseCompressedOops -Xlog:gc*=info
- -XX:+UseCompressedClassPointers
-Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- runtime.valhalla.valuetypes.FlatArrayCopyingTest
+ ${test.main.class}
*/
/*
@@ -57,7 +56,7 @@
* @run junit/othervm/timeout=480 -Xint -XX:+UseParallelGC -XX:+UseCompressedOops -Xlog:gc*=info
-XX:ParallelGCThreads=1 -XX:-UseDynamicNumberOfGCThreads
-Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- runtime.valhalla.valuetypes.FlatArrayCopyingTest
+ ${test.main.class}
*/
/*
@@ -76,9 +75,9 @@
* @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions
-Xint -XX:+UseG1GC -XX:+UseCompressedOops -Xlog:gc*=info
-XX:ParallelGCThreads=1 -XX:ConcGCThreads=1 -XX:-UseDynamicNumberOfGCThreads
- -XX:-G1UseConcRefinement -XX:+UseCompressedClassPointers
+ -XX:-G1UseConcRefinement
-Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- runtime.valhalla.valuetypes.FlatArrayCopyingTest
+ ${test.main.class}
*/
/*
@@ -97,9 +96,8 @@
* @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions
-Xint -XX:+UseShenandoahGC -XX:+UseCompressedOops -Xlog:gc*=info
-XX:ParallelGCThreads=1 -XX:ConcGCThreads=1 -XX:-UseDynamicNumberOfGCThreads
- -XX:+UseCompressedClassPointers
-Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- runtime.valhalla.valuetypes.FlatArrayCopyingTest
+ ${test.main.class}
*/
package runtime.valhalla.valuetypes;
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeOverlapCopyTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeOverlapCopyTest.java
index 9fe9c2c0b1d..fb14b3eea8b 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeOverlapCopyTest.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeOverlapCopyTest.java
@@ -24,12 +24,15 @@
/*
* @test
+ * @key stress
* @summary Ensures large overlapping flat array copies do not overflow payload iterator offsets.
* @enablePreview
* @requires os.maxMemory >= 7G
+ * @requires (vm.opt.UseArrayFlattening == null | vm.opt.UseArrayFlattening == "true")
+ * @requires (vm.opt.UseNullableAtomicValueFlattening == null | vm.opt.UseNullableAtomicValueFlattening == "true")
* @modules java.base/jdk.internal.value
* @run main/othervm/timeout=240 -Xint -Xmx6G
- * runtime.valhalla.valuetypes.FlatArrayLargeOverlapCopyTest
+ * ${test.main.class}
*/
package runtime.valhalla.valuetypes;
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatFieldAccessorMethods.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatFieldAccessorMethods.java
index d5b3c33c3f7..7a2860ed3b4 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatFieldAccessorMethods.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatFieldAccessorMethods.java
@@ -29,8 +29,10 @@
* @library /test/lib
* @modules java.base/jdk.internal.misc
* @enablePreview
+ * @requires (vm.opt.UseFieldFlattening == null | vm.opt.UseFieldFlattening == "true")
+ * @requires (vm.opt.UseNullableAtomicValueFlattening == null | vm.opt.UseNullableAtomicValueFlattening == "true")
* @compile FlatFieldAccessorMethods.java
- * @run main runtime.valhalla.valuetypes.FlatFieldAccessorMethods
+ * @run main ${test.main.class}
*/
package runtime.valhalla.valuetypes;
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java
index 17065797627..9b3d540c8fb 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java
@@ -34,9 +34,10 @@
* @library /test/lib
* @modules java.base/jdk.internal.vm.annotation
* @enablePreview
+ * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
* @compile FlattenableSemanticTest.java
- * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening runtime.valhalla.valuetypes.FlattenableSemanticTest
- * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:ForceNonTearable=* runtime.valhalla.valuetypes.FlattenableSemanticTest
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening ${test.main.class}
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:ForceNonTearable=* ${test.main.class}
*/
public class FlattenableSemanticTest {
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/ObjectMethods.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ObjectMethods.java
index a09eff48a13..d6d38bd3299 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/ObjectMethods.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ObjectMethods.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,21 +27,12 @@
import test.java.lang.invoke.lib.InstructionHelper;
/*
- * @test id=compressed-class-pointers
+ * @test id=default
* @summary Check object methods implemented by the VM behave with value types
* @library /test/lib /test/jdk/java/lang/invoke/common
* @enablePreview
* @compile ObjectMethods.java
- * @run main/othervm -XX:+UseCompressedClassPointers runtime.valhalla.valuetypes.ObjectMethods
- */
-
-/*
- * @test id=no-compressed-class-pointers
- * @summary Check object methods implemented by the VM behave with value types
- * @library /test/lib /test/jdk/java/lang/invoke/common
- * @enablePreview
- * @compile ObjectMethods.java
- * @run main/othervm -XX:-UseCompressedClassPointers runtime.valhalla.valuetypes.ObjectMethods
+ * @run main/othervm ${test.main.class}
*/
/*
@@ -50,7 +41,7 @@
* @library /test/lib /test/jdk/java/lang/invoke/common
* @enablePreview
* @compile ObjectMethods.java
- * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote runtime.valhalla.valuetypes.ObjectMethods noverify
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote ${test.main.class} noverify
*/
public class ObjectMethods {
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFieldNullability.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFieldNullability.java
index 0c3b0ac9798..ab09239cb5c 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFieldNullability.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFieldNullability.java
@@ -26,9 +26,10 @@
* @library /test/lib
* @modules java.base/jdk.internal.vm.annotation
* @enablePreview
+ * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
* @compile TestFieldNullability.java
* @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening
- * runtime.valhalla.valuetypes.TestFieldNullability
+ * ${test.main.class}
*/
package runtime.valhalla.valuetypes;
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatteningBudget.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatteningBudget.java
index 3f14170d3e7..15228592fb7 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatteningBudget.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatteningBudget.java
@@ -28,10 +28,11 @@
* java.base/jdk.internal.misc
* @library /test/lib
* @enablePreview
- * @requires vm.opt.UseFieldFlattening != "false"
- * @requires vm.opt.UseNullableAtomicValueFlattening != "false"
+ * @requires (vm.opt.UseFieldFlattening == null | vm.opt.UseFieldFlattening == "true")
+ * @requires (vm.opt.UseNullableAtomicValueFlattening == null | vm.opt.UseNullableAtomicValueFlattening == "true")
+ * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
* @requires vm.compMode != "Xcomp"
- * @run main runtime.valhalla.valuetypes.TestFlatteningBudget
+ * @run main ${test.main.class}
*/
package runtime.valhalla.valuetypes;
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/VolatileTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/VolatileTest.java
index 6fb6b1ceb6f..e8e2ae0ce4f 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/VolatileTest.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/VolatileTest.java
@@ -30,8 +30,9 @@
* java.base/jdk.internal.vm.annotation
* @library /test/lib
* @enablePreview
+ * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
* @compile VolatileTest.java
- * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening runtime.valhalla.valuetypes.VolatileTest
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening ${test.main.class}
*/
import jdk.internal.misc.Unsafe;
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ConcurrentClassLoadingTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ConcurrentClassLoadingTest.java
index b40c5167849..802bb050e16 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ConcurrentClassLoadingTest.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ConcurrentClassLoadingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,13 +24,14 @@
/*
* @test
+ * @key stress
* @summary Invokes eight threads that concurrently have to resolve the same
set of classes, thereby putting stress on the classloader and
deadlocks will be noticed. This execution is iterated many times.
* @library /test/lib
* @enablePreview
* @compile BigClassTreeClassLoader.java
- * @run junit/othervm/timeout=480 -XX:ReservedCodeCacheSize=1G runtime.valhalla.valuetypes.classloading.ConcurrentClassLoadingTest
+ * @run junit/othervm/timeout=480 -XX:ReservedCodeCacheSize=1G ${test.main.class}
*/
package runtime.valhalla.valuetypes.classloading;
diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java
index f57be0a44a7..a04e63dbe94 100644
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,12 +25,13 @@
/*
* @test
* @summary Even if LoadableDescriptors fail, we observe correct operation.
- This uses a custom classloader to ensure that classloading/linking will
- initially fail due to LoadableDescriptors.
- @compile OuterValue.java
- @compile InnerValue.java
+ * This uses a custom classloader to ensure that classloading/linking will
+ * initially fail due to LoadableDescriptors.
* @enablePreview
- * @run junit runtime.valhalla.valuetypes.classloading.PreLoadFailuresDoNotImpactApplicationTest
+ * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true")
+ * @compile OuterValue.java
+ * @compile InnerValue.java
+ * @run junit ${test.main.class}
*/
package runtime.valhalla.valuetypes.classloading;
diff --git a/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java b/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java
index 17e88aeebb0..bce5945120e 100644
--- a/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java
+++ b/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @key stress
*
* @summary converted from VM Testbase jit/escape/AdaptiveBlocking/AdaptiveBlocking001.
* VM Testbase keywords: [jit, quick]
@@ -36,9 +37,9 @@
*
* @library /vmTestbase
* /test/lib
- * @build jit.escape.AdaptiveBlocking.AdaptiveBlocking001.AdaptiveBlocking001
+ * @build ${test.main.class}
* @run driver/timeout=1200 ExecDriver --java -server -Xcomp -XX:+DoEscapeAnalysis
- * jit.escape.AdaptiveBlocking.AdaptiveBlocking001.AdaptiveBlocking001 -numRounds 10
+ * ${test.main.class} -numRounds 10
*/
package jit.escape.AdaptiveBlocking.AdaptiveBlocking001;
From f9a13f8dc3bec24b27ddaf9b586a6f9b682241db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?=
Date: Mon, 5 Oct 2026 08:22:45 +0000
Subject: [PATCH 44/98] 8386622: JFR: Contextual information is applied to
neither jdk.ExecutionSample nor jdk.NativeMethodSample events
Reviewed-by: egahlin
---
src/hotspot/share/jfr/metadata/metadata.xml | 10 +-
.../sampling/jfrCPUTimeThreadSampler.cpp | 12 +--
.../sampling/jfrCPUTimeThreadSampler.hpp | 6 +-
.../periodic/sampling/jfrThreadSampling.cpp | 32 +++++--
.../share/jfr/support/jfrThreadLocal.cpp | 1 -
...ckTrace.java => StackTraceTestMatrix.java} | 94 ++++++++++++++-----
.../TestCPUTimeSampleFullStackTrace.java | 8 +-
.../event/profiling/TestFullStackTrace.java | 9 +-
...estFullStackTracePreserveFramePointer.java | 42 +++++++++
.../jdk/jfr/event/profiling/TestNative.java | 32 +++++--
.../jdk/jdk/jfr/tool/TestPrintContextual.java | 66 ++++++++++++-
11 files changed, 247 insertions(+), 65 deletions(-)
rename test/jdk/jdk/jfr/event/profiling/{BaseTestFullStackTrace.java => StackTraceTestMatrix.java} (60%)
create mode 100644 test/jdk/jdk/jfr/event/profiling/TestFullStackTracePreserveFramePointer.java
diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml
index 22bd21c8ff4..71e2d9c747b 100644
--- a/src/hotspot/share/jfr/metadata/metadata.xml
+++ b/src/hotspot/share/jfr/metadata/metadata.xml
@@ -976,7 +976,7 @@
+ thread="true" period="everyChunk">
@@ -984,7 +984,7 @@
+ thread="true" period="everyChunk">
@@ -992,18 +992,16 @@
+ throttle="true" thread="true" experimental="true" startTime="false">
-
+ thread="true" stackTrace="false" startTime="false" experimental="true">
-
diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp
index 7507b9c994e..235ff51bd34 100644
--- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp
+++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2025 SAP SE. All rights reserved.
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -332,7 +333,7 @@ void JfrCPUSamplerThread::on_javathread_terminate(JavaThread* thread) {
tl->deallocate_cpu_time_jfr_queue();
s4 lost_samples = tl->cpu_time_jfr_queue().lost_samples();
if (lost_samples > 0) {
- JfrCPUTimeThreadSampling::send_lost_event(JfrTicks::now(), JfrThreadLocal::thread_id(thread), lost_samples);
+ JfrCPUTimeThreadSampling::send_lost_event(JfrTicks::now(), lost_samples);
}
tl->release_cpu_time_jfr_queue_lock();
}
@@ -422,11 +423,10 @@ void JfrCPUSamplerThread::stackwalk_threads_in_native() {
static volatile size_t count = 0;
-void JfrCPUTimeThreadSampling::send_empty_event(const JfrTicks &start_time, traceid tid, Tickspan cpu_time_period) {
+void JfrCPUTimeThreadSampling::send_empty_event(const JfrTicks &start_time, Tickspan cpu_time_period) {
EventCPUTimeSample event(UNTIMED);
event.set_failed(true);
event.set_starttime(start_time);
- event.set_eventThread(tid);
event.set_stackTrace(0);
event.set_samplingPeriod(cpu_time_period);
event.set_biased(false);
@@ -436,11 +436,10 @@ void JfrCPUTimeThreadSampling::send_empty_event(const JfrTicks &start_time, trac
static volatile size_t biased_count = 0;
-void JfrCPUTimeThreadSampling::send_event(const JfrTicks &start_time, traceid sid, traceid tid, Tickspan cpu_time_period, bool biased) {
+void JfrCPUTimeThreadSampling::send_event(const JfrTicks &start_time, traceid sid, Tickspan cpu_time_period, bool biased) {
EventCPUTimeSample event(UNTIMED);
event.set_failed(false);
event.set_starttime(start_time);
- event.set_eventThread(tid);
event.set_stackTrace(sid);
event.set_samplingPeriod(cpu_time_period);
event.set_biased(biased);
@@ -454,14 +453,13 @@ void JfrCPUTimeThreadSampling::send_event(const JfrTicks &start_time, traceid si
}
}
-void JfrCPUTimeThreadSampling::send_lost_event(const JfrTicks &time, traceid tid, s4 lost_samples) {
+void JfrCPUTimeThreadSampling::send_lost_event(const JfrTicks &time, s4 lost_samples) {
if (!EventCPUTimeSamplesLost::is_enabled()) {
return;
}
EventCPUTimeSamplesLost event(UNTIMED);
event.set_starttime(time);
event.set_lostSamples(lost_samples);
- event.set_eventThread(tid);
event.commit();
}
diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp
index e7c915fc8be..2585446b2ba 100644
--- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp
+++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp
@@ -133,9 +133,9 @@ class JfrCPUTimeThreadSampling : public JfrCHeapObj {
static void on_javathread_terminate(JavaThread* thread);
void handle_timer_signal(siginfo_t* info, void* context);
- static void send_empty_event(const JfrTicks& start_time, traceid tid, Tickspan cpu_time_period);
- static void send_event(const JfrTicks& start_time, traceid sid, traceid tid, Tickspan cpu_time_period, bool biased);
- static void send_lost_event(const JfrTicks& time, traceid tid, s4 lost_samples);
+ static void send_empty_event(const JfrTicks& start_time, Tickspan cpu_time_period);
+ static void send_event(const JfrTicks& start_time, traceid sid, Tickspan cpu_time_period, bool biased);
+ static void send_lost_event(const JfrTicks& time, s4 lost_samples);
static void trigger_async_processing_of_cpu_time_jfr_requests();
diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp
index 24868d7f896..362950af20a 100644
--- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp
+++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp
@@ -316,6 +316,8 @@ static void record_thread_in_java(const JfrSampleRequest& request, const JfrTick
}
assert(sid != 0, "invariant");
const traceid tid = in_continuation ? tl->vthread_id_with_epoch_update(jt) : JfrThreadLocal::jvm_thread_id(jt);
+ JfrThreadLocal::impersonate(current, tid);
+ assert(JfrThreadLocal::thread_id(current) == tid, "invariant");
send_sample_event(request._sample_ticks, now, sid, tid);
if (current == jt) {
send_safepoint_latency_event(request, now, sid, jt);
@@ -331,10 +333,13 @@ static void record_cpu_time_thread(const JfrCPUTimeSampleRequest& request, const
bool biased = false;
bool in_continuation = false;
bool could_compute_top_frame = compute_top_frame(request._request, top_frame, in_continuation, jt, biased);
+
const traceid tid = in_continuation ? tl->vthread_id_with_epoch_update(jt) : JfrThreadLocal::jvm_thread_id(jt);
+ JfrThreadLocal::impersonate(current, tid);
+ assert(JfrThreadLocal::thread_id(current) == tid, "invariant");
if (!could_compute_top_frame) {
- JfrCPUTimeThreadSampling::send_empty_event(request._request._sample_ticks, tid, request._cpu_time_period);
+ JfrCPUTimeThreadSampling::send_empty_event(request._request._sample_ticks, request._cpu_time_period);
return;
}
traceid sid;
@@ -343,15 +348,13 @@ static void record_cpu_time_thread(const JfrCPUTimeSampleRequest& request, const
JfrStackTrace stacktrace;
if (!stacktrace.record(jt, top_frame, in_continuation, request._request)) {
// Unable to record stacktrace. Fail.
- JfrCPUTimeThreadSampling::send_empty_event(request._request._sample_ticks, tid, request._cpu_time_period);
+ JfrCPUTimeThreadSampling::send_empty_event(request._request._sample_ticks, request._cpu_time_period);
return;
}
sid = JfrStackTraceRepository::add(stacktrace);
}
assert(sid != 0, "invariant");
-
-
- JfrCPUTimeThreadSampling::send_event(request._request._sample_ticks, sid, tid, request._cpu_time_period, biased);
+ JfrCPUTimeThreadSampling::send_event(request._request._sample_ticks, sid, request._cpu_time_period, biased);
if (current == jt) {
send_safepoint_latency_event(request._request, now, sid, jt);
}
@@ -369,6 +372,7 @@ static void drain_enqueued_requests(const JfrTicks& now, JfrThreadLocal* tl, Jav
record_thread_in_java(request, now, tl, jt, current);
}
tl->clear_enqueued_requests();
+ JfrThreadLocal::stop_impersonating(current);
}
assert(!tl->has_enqueued_requests(), "invariant");
}
@@ -390,7 +394,11 @@ static void drain_enqueued_cpu_time_requests(const JfrTicks& now, JfrThreadLocal
assert(queue.is_empty(), "invariant");
tl->set_has_cpu_time_jfr_requests(false);
if (queue.lost_samples() > 0) {
- JfrCPUTimeThreadSampling::send_lost_event( now, JfrThreadLocal::thread_id(jt), queue.get_and_reset_lost_samples());
+ // Lost samples belong to the platform thread that owns the queue.
+ const traceid tid = JfrThreadLocal::jvm_thread_id(jt);
+ JfrThreadLocal::impersonate(current, tid);
+ assert(JfrThreadLocal::thread_id(current) == tid, "invariant");
+ JfrCPUTimeThreadSampling::send_lost_event(now, queue.get_and_reset_lost_samples());
queue.resize_if_needed();
}
if (lock) {
@@ -402,9 +410,9 @@ static void drain_enqueued_cpu_time_requests(const JfrTicks& now, JfrThreadLocal
// Entry point for a thread that has been sampled in native code and has a pending JFR CPU time request.
void JfrThreadSampling::process_cpu_time_request(JavaThread* jt, JfrThreadLocal* tl, Thread* current, bool lock) {
assert(jt != nullptr, "invariant");
-
const JfrTicks now = JfrTicks::now();
drain_enqueued_cpu_time_requests(now, tl, jt, current, lock);
+ JfrThreadLocal::stop_impersonating(current);
}
static void drain_all_enqueued_requests(const JfrTicks& now, JfrThreadLocal* tl, JavaThread* jt, Thread* current) {
@@ -414,6 +422,7 @@ static void drain_all_enqueued_requests(const JfrTicks& now, JfrThreadLocal* tl,
drain_enqueued_requests(now, tl, jt, current);
if (tl->has_cpu_time_jfr_requests()) {
drain_enqueued_cpu_time_requests(now, tl, jt, current, true);
+ JfrThreadLocal::stop_impersonating(current);
}
}
@@ -453,12 +462,16 @@ bool JfrThreadSampling::process_native_sample_request(JfrThreadLocal* tl, JavaTh
}
sid = JfrStackTraceRepository::add(stacktrace);
}
- // Read the tid under the monitor to ensure that if its a virtual thread,
+
+ // Read the tid under the monitor to ensure that if it is a virtual thread,
// it is not unmounted until we are done with it.
tid = JfrThreadLocal::thread_id(jt);
+ // Since the sampler thread cannot commit any other event except its next sample,
+ // no explicit cleanup is required; the next processed sample overwrites the alias.
+ JfrThreadLocal::impersonate(sampler_thread, tid);
}
-
assert(tl->sample_state() == NO_SAMPLE, "invariant");
+ assert(JfrThreadLocal::thread_id(sampler_thread) == tid, "invariant");
send_sample_event(start_time, start_time, sid, tid);
return true;
}
@@ -493,4 +506,3 @@ void JfrThreadSampling::process_sample_request(JavaThread* jt) {
}
drain_all_enqueued_requests(now, tl, jt, jt);
}
-
diff --git a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp
index 3b170c0ea53..b1a5d5e203c 100644
--- a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp
+++ b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp
@@ -379,7 +379,6 @@ bool JfrThreadLocal::is_impersonating(const Thread* t) {
void JfrThreadLocal::impersonate(const Thread* t, traceid other_thread_id) {
assert(t != nullptr, "invariant");
- assert(other_thread_id != 0, "invariant");
JfrThreadLocal* const tl = t->jfr_thread_local();
tl->_thread_id_alias = other_thread_id;
}
diff --git a/test/jdk/jdk/jfr/event/profiling/BaseTestFullStackTrace.java b/test/jdk/jdk/jfr/event/profiling/StackTraceTestMatrix.java
similarity index 60%
rename from test/jdk/jdk/jfr/event/profiling/BaseTestFullStackTrace.java
rename to test/jdk/jdk/jfr/event/profiling/StackTraceTestMatrix.java
index aadd9dded7e..9ae1ca21d2b 100644
--- a/test/jdk/jdk/jfr/event/profiling/BaseTestFullStackTrace.java
+++ b/test/jdk/jdk/jfr/event/profiling/StackTraceTestMatrix.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,24 +36,53 @@
import jdk.test.lib.jfr.Events;
import jdk.test.lib.jfr.RecurseThread;
-public class BaseTestFullStackTrace {
+/*
+ * Exercises sampling events across the following matrix:
+ *
+ * ExecutionSample x platform thread
+ * ExecutionSample x virtual thread
+ * CPUTimeSample x platform thread
+ * CPUTimeSample x virtual thread
+ *
+ * Each cell verifies that the event identifies the sampled thread and that
+ * its stack trace contains the expected recursive Java frames. ExecutionSample
+ * additionally verifies that eventThread and sampledThread identify the same
+ * thread.
+ */
+public class StackTraceTestMatrix {
private final static int MAX_DEPTH = 64; // currently hardcoded in jvm
private final String eventName;
private final String threadFieldName;
+ private final boolean virtual;
- public BaseTestFullStackTrace(String eventName, String threadFieldName) {
+ private StackTraceTestMatrix(String eventName, String threadFieldName, boolean virtual) {
this.eventName = eventName;
this.threadFieldName = threadFieldName;
+ this.virtual = virtual;
+ }
+
+ public static void runAllThreadKinds(String eventName, String threadFieldName) throws Throwable {
+ runPlatformThreads(eventName, threadFieldName);
+ new StackTraceTestMatrix(eventName, threadFieldName, true).run();
+ }
+
+ public static void runPlatformThreads(String eventName, String threadFieldName) throws Throwable {
+ new StackTraceTestMatrix(eventName, threadFieldName, false).run();
}
public void run() throws Throwable {
RecurseThread[] threads = new RecurseThread[3];
+ // Virtual threads execute the RecurseThread workloads on distinct Thread objects.
+ Thread[] javaThreads = new Thread[threads.length];
for (int i = 0; i < threads.length; ++i) {
int depth = MAX_DEPTH - 1 + i;
threads[i] = new RecurseThread(depth);
- threads[i].setName("recursethread-" + depth);
- threads[i].start();
+ String name = "recursethread-" + depth;
+ Thread thread = virtual ? Thread.ofVirtual().unstarted(threads[i]) : threads[i];
+ thread.setName(name);
+ javaThreads[i] = thread;
+ thread.start();
}
for (RecurseThread thread : threads) {
@@ -62,15 +91,15 @@ public void run() throws Throwable {
}
}
- assertStackTraces(threads);
+ assertStackTraces(threads, javaThreads);
- for (RecurseThread thread : threads) {
- thread.quit();
- thread.join();
+ for (int i = 0; i < threads.length; ++i) {
+ threads[i].quit();
+ javaThreads[i].join();
}
}
- private void assertStackTraces(RecurseThread[] threads) throws Throwable {
+ private void assertStackTraces(RecurseThread[] threads, Thread[] javaThreads) throws Throwable {
while (true) {
try (Recording recording = new Recording()) {
if (eventName.equals(EventNames.CPUTimeSample)) {
@@ -81,26 +110,35 @@ private void assertStackTraces(RecurseThread[] threads) throws Throwable {
recording.start();
Thread.sleep(500);
recording.stop();
- if (hasValidStackTraces(recording, threads)) {
+ if (hasValidStackTraces(recording, threads, javaThreads)) {
break;
}
}
};
}
- private boolean hasValidStackTraces(Recording recording, RecurseThread[] threads) throws Throwable {
+ private boolean hasValidStackTraces(Recording recording, RecurseThread[] threads, Thread[] javaThreads) throws Throwable {
boolean[] isEventFound = new boolean[threads.length];
for (RecordedEvent event : Events.fromRecording(recording)) {
System.out.println("Event: " + event);
+ if (EventNames.ExecutionSample.equals(event.getEventType().getName())) {
+ long sampledThreadId =
+ Events.assertField(event, "sampledThread.javaThreadId").getValue();
+ long eventThreadId =
+ Events.assertField(event, "eventThread.javaThreadId").getValue();
+ Asserts.assertEquals(eventThreadId, sampledThreadId,
+ "eventThread and sampledThread must identify the same thread");
+ }
String threadName = Events.assertField(event, threadFieldName + ".javaName").getValue();
long threadId = Events.assertField(event, threadFieldName + ".javaThreadId").getValue();
for (int threadIndex = 0; threadIndex < threads.length; ++threadIndex) {
RecurseThread currThread = threads[threadIndex];
- if (threadId == currThread.getId()) {
- System.out.println("ThreadName=" + currThread.getName() + ", depth=" + currThread.totalDepth);
- Asserts.assertEquals(threadName, currThread.getName(), "Wrong thread name");
+ Thread javaThread = javaThreads[threadIndex];
+ if (threadId == javaThread.threadId()) {
+ System.out.println("ThreadName=" + javaThread.getName() + ", depth=" + currThread.totalDepth);
+ Asserts.assertEquals(threadName, javaThread.getName(), "Wrong thread name");
if ("recurseEnd".equals(getTopMethodName(event))) {
isEventFound[threadIndex] = true;
checkEvent(event, currThread.totalDepth);
@@ -136,7 +174,8 @@ private void checkEvent(RecordedEvent event, int expectedDepth) throws Throwable
try {
stacktrace = event.getStackTrace();
List frames = stacktrace.getFrames();
- Asserts.assertEquals(Math.min(MAX_DEPTH, expectedDepth), frames.size(), "Wrong stacktrace depth. Expected:" + expectedDepth);
+ int expectedStackDepth = Math.min(MAX_DEPTH, expectedDepth + (virtual ? 1 : 0));
+ Asserts.assertEquals(expectedStackDepth, frames.size(), "Wrong stacktrace depth. Expected:" + expectedStackDepth);
List expectedMethods = getExpectedMethods(expectedDepth);
Asserts.assertEquals(expectedMethods.size(), frames.size(), "Wrong expectedMethods depth. Test error.");
@@ -148,13 +187,21 @@ private void checkEvent(RecordedEvent event, int expectedDepth) throws Throwable
}
boolean isTruncated = stacktrace.isTruncated();
- boolean isTruncateExpected = expectedDepth > MAX_DEPTH;
+ // Thread.runWith(Object, Runnable) invokes a virtual-thread task below
+ // RecurseThread.run(). With MAX_DEPTH - 1 recursive frames, it fills the
+ // final stack-depth slot, but continuation frames still remain below it.
+ boolean isTruncateExpected = expectedDepth > MAX_DEPTH ||
+ (virtual && expectedDepth >= MAX_DEPTH - 1);
Asserts.assertEquals(isTruncated, isTruncateExpected, "Wrong value for isTruncated. Expected:" + isTruncateExpected);
String firstMethod = frames.getLast().getMethod().getName();
- boolean isFullTrace = "run".equals(firstMethod);
- String msg = String.format("Wrong values for isTruncated=%b, isFullTrace=%b", isTruncated, isFullTrace);
- Asserts.assertTrue(isTruncated != isFullTrace, msg);
+ if (!virtual) {
+ boolean isFullTrace = "run".equals(firstMethod);
+ String msg = String.format("Wrong values for isTruncated=%b, isFullTrace=%b", isTruncated, isFullTrace);
+ Asserts.assertTrue(isTruncated != isFullTrace, msg);
+ } else if (!isTruncated) {
+ Asserts.assertEquals(firstMethod, "run", "A full virtual-thread trace should end at RecurseThread.run");
+ }
} catch (Throwable t) {
System.out.println(String.format("stacktrace:%n%s", stacktrace));
throw t;
@@ -167,8 +214,13 @@ private List getExpectedMethods(int depth) {
for (int i = 0; i < depth - 2; ++i) {
methods.add((i % 2) == 0 ? "recurseA" : "recurseB");
}
+ // A platform thread enters the recursive workload through RecurseThread.run().
methods.add("run");
- if (depth > MAX_DEPTH) {
+ if (virtual) {
+ // A virtual thread invokes that Runnable through Thread.runWith(Object, Runnable).
+ methods.add("runWith");
+ }
+ if (methods.size() > MAX_DEPTH) {
methods = methods.subList(0, MAX_DEPTH);
}
return methods;
diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleFullStackTrace.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleFullStackTrace.java
index 0d1108346ab..9a5a4610b5a 100644
--- a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleFullStackTrace.java
+++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleFullStackTrace.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,15 +27,15 @@
/**
* @test
- * @requires vm.hasJFR & os.family == "linux"
+ * @requires vm.hasJFR & vm.continuations & os.family == "linux"
* @library /test/lib
- * @build jdk.jfr.event.profiling.BaseTestFullStackTrace
+ * @build jdk.jfr.event.profiling.StackTraceTestMatrix
* @run main/othervm jdk.jfr.event.profiling.TestCPUTimeSampleFullStackTrace
*/
public class TestCPUTimeSampleFullStackTrace {
public static void main(String[] args) throws Throwable {
- new BaseTestFullStackTrace(EventNames.CPUTimeSample, "eventThread").run();
+ StackTraceTestMatrix.runAllThreadKinds(EventNames.CPUTimeSample, "eventThread");
}
}
diff --git a/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java b/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java
index bfffb5e6f1d..855c318c55d 100644
--- a/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java
+++ b/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,17 +27,16 @@
/**
* @test
- * @requires vm.hasJFR
+ * @requires vm.hasJFR & vm.continuations
* @requires vm.opt.DeoptimizeALot != true
* @library /test/lib
- * @build jdk.jfr.event.profiling.BaseTestFullStackTrace
+ * @build jdk.jfr.event.profiling.StackTraceTestMatrix
* @run main/othervm jdk.jfr.event.profiling.TestFullStackTrace
- * @run main/othervm -XX:CompileCommand=compileonly,jdk.test.lib.jfr.RecurseThread::recurse* -XX:+PreserveFramePointer jdk.jfr.event.profiling.TestFullStackTrace
*/
public class TestFullStackTrace {
public static void main(String[] args) throws Throwable {
- new BaseTestFullStackTrace(EventNames.ExecutionSample, "sampledThread").run();
+ StackTraceTestMatrix.runAllThreadKinds(EventNames.ExecutionSample, "sampledThread");
}
}
diff --git a/test/jdk/jdk/jfr/event/profiling/TestFullStackTracePreserveFramePointer.java b/test/jdk/jdk/jfr/event/profiling/TestFullStackTracePreserveFramePointer.java
new file mode 100644
index 00000000000..95fda43a0d3
--- /dev/null
+++ b/test/jdk/jdk/jfr/event/profiling/TestFullStackTracePreserveFramePointer.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.profiling;
+
+import jdk.test.lib.jfr.EventNames;
+
+/**
+ * @test
+ * @requires vm.hasJFR
+ * @requires vm.opt.DeoptimizeALot != true
+ * @library /test/lib
+ * @build jdk.jfr.event.profiling.StackTraceTestMatrix
+ * @run main/othervm -XX:CompileCommand=compileonly,jdk.test.lib.jfr.RecurseThread::recurse* -XX:+PreserveFramePointer ${test.main.class}
+ */
+public class TestFullStackTracePreserveFramePointer {
+
+ public static void main(String[] args) throws Throwable {
+ StackTraceTestMatrix.runPlatformThreads(EventNames.ExecutionSample, "sampledThread");
+ }
+
+}
diff --git a/test/jdk/jdk/jfr/event/profiling/TestNative.java b/test/jdk/jdk/jfr/event/profiling/TestNative.java
index e7e076051f4..5a2c31e5d62 100644
--- a/test/jdk/jdk/jfr/event/profiling/TestNative.java
+++ b/test/jdk/jdk/jfr/event/profiling/TestNative.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,11 +24,13 @@
package jdk.jfr.event.profiling;
import java.time.Duration;
+import java.util.concurrent.atomic.AtomicReference;
-import jdk.jfr.Recording;
import jdk.jfr.consumer.RecordingStream;
import jdk.jfr.internal.JVM;
+import jdk.test.lib.Asserts;
import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
/*
* @test
@@ -45,21 +47,39 @@ public class TestNative {
static volatile boolean alive = true;
public static void main(String[] args) throws Exception {
+ Thread target = new Thread(TestNative::nativeMethod, "Native Sample Target");
+ target.setDaemon(true);
+ AtomicReference failure = new AtomicReference<>();
try (RecordingStream rs = new RecordingStream()) {
rs.enable(NATIVE_EVENT).withPeriod(Duration.ofMillis(1));
+ rs.onError(t -> {
+ failure.compareAndSet(null, t);
+ alive = false;
+ rs.close();
+ });
rs.onEvent(NATIVE_EVENT, e -> {
+ long sampledThreadId = Events.assertField(e, "sampledThread.javaThreadId").getValue();
+ if (sampledThreadId != target.threadId()) {
+ return;
+ }
+ long eventThreadId = Events.assertField(e, "eventThread.javaThreadId").getValue();
+ Asserts.assertEquals(eventThreadId, sampledThreadId,
+ "eventThread and sampledThread must identify the same thread");
alive = false;
rs.close();
});
- Thread t = new Thread(TestNative::nativeMethod);
- t.setDaemon(true);
- t.start();
+ target.start();
rs.start();
+ } finally {
+ alive = false;
+ }
+ if (failure.get() != null) {
+ throw new RuntimeException("Native sample validation failed", failure.get());
}
}
- public static void nativeMethod() {
+ static void nativeMethod() {
while (alive) {
JVM.getPid();
}
diff --git a/test/jdk/jdk/jfr/tool/TestPrintContextual.java b/test/jdk/jdk/jfr/tool/TestPrintContextual.java
index e6df9c7c729..1d31bf9aeeb 100644
--- a/test/jdk/jdk/jfr/tool/TestPrintContextual.java
+++ b/test/jdk/jdk/jfr/tool/TestPrintContextual.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,12 +30,15 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
import jdk.jfr.Contextual;
import jdk.jfr.Event;
import jdk.jfr.Name;
import jdk.jfr.Recording;
import jdk.jfr.StackTrace;
+import jdk.jfr.consumer.RecordingStream;
import jdk.test.lib.JDKToolLauncher;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
@@ -43,7 +46,7 @@
/**
* @test
* @requires vm.flagless
- * @requires vm.hasJFR
+ * @requires vm.hasJFR & vm.continuations
* @library /test/lib
* @run main/othervm jdk.jfr.tool.TestPrintContextual
*/
@@ -109,6 +112,7 @@ public static void main(String[] args) throws Exception {
testDeepContext();
testThreadedContext();
testFiltered();
+ testSampledThreadContext();
}
// Tests that context values are injected into non-contextual events
@@ -356,6 +360,61 @@ private static void testFiltered() throws Exception {
}
}
+ // Tests that context values are also injected into sampled threads.
+ private static void testSampledThreadContext() throws Exception {
+ testSampledThreadContext(false);
+ testSampledThreadContext(true);
+ }
+
+ private static void testSampledThreadContext(boolean virtual) throws Exception {
+ String threadKind = virtual ? "virtual" : "platform";
+ String contextName = threadKind + " sample context";
+ CountDownLatch contextStarted = new CountDownLatch(1);
+ CountDownLatch sampleReceived = new CountDownLatch(1);
+ AtomicBoolean running = new AtomicBoolean(true);
+ Thread target = (virtual ? Thread.ofVirtual() : Thread.ofPlatform())
+ .name(threadKind + " sample target")
+ .unstarted(() -> {
+ TraceEvent trace = new TraceEvent();
+ trace.name = contextName;
+ trace.begin();
+ contextStarted.countDown();
+ while (running.get()) {
+ Thread.onSpinWait();
+ }
+ trace.commit();
+ });
+
+ try (RecordingStream rs = new RecordingStream()) {
+ rs.enable("Trace").withoutStackTrace();
+ rs.enable("jdk.ExecutionSample").withoutStackTrace().withPeriod(java.time.Duration.ofMillis(1));
+ rs.onEvent("jdk.ExecutionSample", event -> {
+ if (event.getThread().getJavaThreadId() == target.threadId()) {
+ sampleReceived.countDown();
+ }
+ });
+ rs.startAsync();
+ target.start();
+ contextStarted.await();
+ sampleReceived.await();
+ running.set(false);
+ target.join();
+
+ Path file = Path.of(threadKind + "-sample-context.jfr");
+ rs.dump(file);
+ List events = parseEvents(readPrintedLines(file, "--stack-depth", "0"));
+ for (PrintedEvent event : events) {
+ if (event.name.equals("jdk.ExecutionSample") && contextName.equals(event.getContextValue("Trace.name"))) {
+ return;
+ }
+ }
+ throw new Exception("No ExecutionSample found with context " + contextName);
+ } finally {
+ running.set(false);
+ target.join();
+ }
+ }
+
private static void assertName(PrintedEvent event, String name) throws Exception {
if (!event.name.equals(name)) {
throw new Exception("Expected event name " + name + ", but was " + event.name);
@@ -401,6 +460,9 @@ private static List parseEvents(List lines) {
pe = null;
} else if (pe != null) {
int index = line.indexOf("=");
+ if (index < 0) {
+ continue;
+ }
String field = line.substring(0, index).trim();
String value = line.substring(index + 1).trim();
if (value.startsWith("\"") && value.endsWith("\"")) {
From 93bfd596427c2c40f0c1da09d4397e2aed18b4fe Mon Sep 17 00:00:00 2001
From: Prasanta Sadhukhan
Date: Mon, 5 Oct 2026 08:58:21 +0000
Subject: [PATCH 45/98] 8391985: View.getNextVisualPositionFrom can throw
NullPointerException
Reviewed-by: prr, jdv
---
.../share/classes/javax/swing/text/View.java | 9 ++-
.../text/View/TestViewVisualPosition.java | 72 +++++++++++++++++++
2 files changed, 78 insertions(+), 3 deletions(-)
create mode 100644 test/jdk/javax/swing/text/View/TestViewVisualPosition.java
diff --git a/src/java.desktop/share/classes/javax/swing/text/View.java b/src/java.desktop/share/classes/javax/swing/text/View.java
index 7fcc00caaac..29187efe280 100644
--- a/src/java.desktop/share/classes/javax/swing/text/View.java
+++ b/src/java.desktop/share/classes/javax/swing/text/View.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -518,8 +518,11 @@ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
getStartOffset();
break;
}
- JTextComponent target = (JTextComponent) getContainer();
- Caret c = (target != null) ? target.getCaret() : null;
+ Container container = getContainer();
+ if (!(container instanceof JTextComponent target)) {
+ return -1;
+ }
+ Caret c = target.getCaret();
// YECK! Ideally, the x location from the magic caret position
// would be passed in.
Point mcp;
diff --git a/test/jdk/javax/swing/text/View/TestViewVisualPosition.java b/test/jdk/javax/swing/text/View/TestViewVisualPosition.java
new file mode 100644
index 00000000000..9e2d28e5d51
--- /dev/null
+++ b/test/jdk/javax/swing/text/View/TestViewVisualPosition.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8391985
+ * @summary View.getNextVisualPositionFrom can throw NullPointerException
+ * @run main TestViewVisualPosition
+ */
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import javax.swing.SwingConstants;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+import javax.swing.text.Position;
+import javax.swing.text.View;
+
+public class TestViewVisualPosition {
+ public static void main(String[] args) throws Exception {
+ PlainDocument document = new PlainDocument();
+ document.insertString(0, "x", null);
+ View view = new View(document.getDefaultRootElement()) {
+ @Override
+ public float getPreferredSpan(int axis) {
+ return 0;
+ }
+
+ @Override
+ public void paint(Graphics g, Shape allocation) {
+
+ }
+
+ @Override
+ public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
+ return null;
+ }
+
+ @Override
+ public int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn) {
+ return 0;
+ }
+ };
+ view.getNextVisualPositionFrom(
+ 0,
+ Position.Bias.Forward,
+ new Rectangle(0, 0, 10, 10),
+ SwingConstants.NORTH,
+ new Position.Bias[1]);
+ }
+}
From f29984825f40dcab2e603400a2c6c2940d3a37c4 Mon Sep 17 00:00:00 2001
From: Kieran Farrell
Date: Mon, 5 Oct 2026 11:09:21 +0000
Subject: [PATCH 46/98] 8361344: Address sun/security/ssl/SSLLogger.java code
coverage gaps
Reviewed-by: mdonovan
---
.../security/ssl/SSLLogger/SSLLoggerTest.java | 172 ++++++++++++++++++
1 file changed, 172 insertions(+)
create mode 100644 test/jdk/sun/security/ssl/SSLLogger/SSLLoggerTest.java
diff --git a/test/jdk/sun/security/ssl/SSLLogger/SSLLoggerTest.java b/test/jdk/sun/security/ssl/SSLLogger/SSLLoggerTest.java
new file mode 100644
index 00000000000..e8d4b30d3fb
--- /dev/null
+++ b/test/jdk/sun/security/ssl/SSLLogger/SSLLoggerTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8361344
+ * @summary Verify SSLLogger map entry formatting and throwable logging
+ * @modules java.base/sun.security.ssl:+open
+ * @run testng/othervm -Djavax.net.debug=all SSLLoggerTest
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.lang.System.Logger.Level;
+import java.util.ListResourceBundle;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import sun.security.ssl.SSLLogger;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+public class SSLLoggerTest {
+ private static final String NL = System.lineSeparator();
+ private System.Logger logger;
+
+ private PrintStream originalErr;
+ private PrintStream capturedErr;
+ private ByteArrayOutputStream capturedBytes;
+
+
+ @BeforeClass
+ public void initializeLogger() throws Exception {
+ // access SSLLogger's private console logger
+ var field = SSLLogger.class.getDeclaredField("logger");
+ field.setAccessible(true);
+ logger = (System.Logger) field.get(null);
+ assertTrue(logger instanceof SSLLogger, "SSL logger not retrieved");
+ }
+
+ @BeforeMethod
+ public void setUp() {
+ // capture SSLLogger output in a fresh buffer for each test run
+ originalErr = System.err;
+ capturedBytes = new ByteArrayOutputStream();
+ capturedErr = new PrintStream(capturedBytes, true, UTF_8);
+ System.setErr(capturedErr);
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDown() {
+ if (originalErr != null) {
+ System.setErr(originalErr);
+ }
+ if (capturedErr != null) {
+ capturedErr.close();
+ }
+ }
+
+ @DataProvider(name = "mapEntries")
+ public Object[][] mapEntries() {
+ // description, entry value, expected formatted entry
+ return new Object[][] {
+ { "string", "value", " \"key\": \"value\"" },
+ { "empty string", "", " \"key\": \"\"" },
+ { "empty string array", new String[0],
+ " \"key\": [" + NL + " ]" },
+ { "multiple strings", new String[] { "one", "two" },
+ " \"key\": [" + NL
+ + " \"one\"," + NL
+ + " \"two\"" + NL + " ]" },
+ { "byte array", new byte[] { 0, 0x0a, (byte) 0xff },
+ " \"key\": \"000AFF\"" },
+ { "byte", (byte) 0x0a, " \"key\": \"0a\"" },
+ { "other object", Integer.valueOf(42), " \"key\": \"42\"" }
+ };
+ }
+
+ @DataProvider(name = "logEntries")
+ public Object[][] logEntries() {
+ ResourceBundle bundle = new ListResourceBundle() {
+ @Override
+ protected Object[][] getContents() {
+ return new Object[][] { { "bundle", "translated message" } };
+ }
+ };
+
+ // level, bundle, log message, throwable, expected
+ return new Object[][] {
+ { Level.INFO, null, "info",
+ new RuntimeException("info exception"),
+ "java.lang.RuntimeException: info exception" },
+ { Level.WARNING, null, "warning",
+ new IllegalStateException("warning exception"),
+ "java.lang.IllegalStateException: warning exception" },
+ { Level.ERROR, null, "inner cause",
+ new RuntimeException("outer exception",
+ new IllegalArgumentException("inner exception")),
+ "Caused by: java.lang.IllegalArgumentException: inner exception" },
+ { Level.INFO, bundle, "bundle",
+ new RuntimeException("bundle exception"),
+ "java.lang.RuntimeException: bundle exception" }
+ };
+ }
+
+ @Test(dataProvider = "mapEntries")
+ public void testFormatMapEntry(String name, Object value, String expected) {
+ // standard usage via SSLLogger.info calls formatMapEntry
+ SSLLogger.info(name, Map.entry("key", value));
+ capturedErr.flush();
+ String log = capturedBytes.toString(UTF_8);
+
+ // check the message and formatted map entry at the end of the log
+ String suffix = "|" + name + " (\n" + expected + "\n)\n";
+ assertTrue(log.endsWith(suffix),
+ name + ": expected suffix [" + suffix + "]\nActual: [" + log + "]");
+ }
+
+ @Test(dataProvider = "logEntries")
+ public void testLogThrowable(Level level, ResourceBundle rb,
+ String message, Throwable thrwbl,
+ String expected) {
+ logger.log(level, rb, message, thrwbl);
+ capturedErr.flush();
+ String log = capturedBytes.toString(UTF_8);
+
+ assertTrue(log.startsWith("javax.net.ssl|" + level + "|"), log);
+ assertTrue(log.contains("|" + message + " (\n"), log);
+ assertTrue(log.contains("\"throwable\" : {"), log);
+ assertTrue(log.contains(expected),
+ "Expected [" + expected + "] but got [" + log + "]");
+ }
+
+ @Test
+ public void testThrowableLoggingOff() {
+ assertFalse(logger.isLoggable(Level.OFF));
+ logger.log(Level.OFF, null, "off",
+ new RuntimeException("exception"));
+ capturedErr.flush();
+ assertEquals(capturedBytes.toString(UTF_8), "",
+ "The log call with throwable should not log at Level.OFF");
+ }
+}
From 6310a3c779b33bc92175a019c02b7cb257ab9ecf Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev
Date: Mon, 5 Oct 2026 11:52:46 +0000
Subject: [PATCH 47/98] 8393318: VarHandle CAE case should be handled as in
JDK-8391651
Reviewed-by: jsjolen, dholmes
---
.../classes/jdk/internal/misc/Unsafe.java | 3 +-
.../inlinetypes/VarHandleCAEOfEmptyClass.java | 52 +++++++++++++++++++
2 files changed, 54 insertions(+), 1 deletion(-)
create mode 100644 test/hotspot/jtreg/runtime/valhalla/inlinetypes/VarHandleCAEOfEmptyClass.java
diff --git a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
index f7a82e9d72d..3bdcb87d6e7 100644
--- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
+++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
@@ -1808,7 +1808,8 @@ public final Object compareAndExchangeFlatValue(Object o, long offset,
V expected,
V x) {
Object[] array = newSpecialArray(valueType, 2, layout);
- compareAndSetFlatValueAsBytes(array, o, offset, layout, valueType, expected, x);
+ int containerLayout = arrayLayout(array);
+ compareAndSetFlatValueAsBytes(array, o, offset, containerLayout, valueType, expected, x);
return array[0];
}
diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/VarHandleCAEOfEmptyClass.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/VarHandleCAEOfEmptyClass.java
new file mode 100644
index 00000000000..ec3975b0344
--- /dev/null
+++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/VarHandleCAEOfEmptyClass.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package runtime.valhalla.inlinetypes;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+/*
+ * @test VarHandleCAEOfEmptyClass
+ * @summary VarHandle compareAndExchange can handle empty value classes
+ * @bug 8391651
+ * @enablePreview
+ * @compile VarHandleCAEOfEmptyClass.java
+ * @run main runtime.valhalla.inlinetypes.VarHandleCAEOfEmptyClass
+ */
+
+public class VarHandleCAEOfEmptyClass {
+ static value class Empty { }
+
+ static class Holder {
+ Empty value;
+ }
+
+ public static void main(String[] args) throws ReflectiveOperationException {
+ VarHandle handle = MethodHandles.lookup().findVarHandle(Holder.class, "value", Empty.class);
+ if (handle.compareAndExchange(new Holder(), null, new Empty()) != null) {
+ throw new RuntimeException("compareAndExchange failed");
+ }
+ }
+}
From 4e8bec6f862b58732537dea15cb3dd50a01fede0 Mon Sep 17 00:00:00 2001
From: Axel Boldt-Christmas
Date: Mon, 5 Oct 2026 12:52:22 +0000
Subject: [PATCH 48/98] 8393451: ValuePayload copy and null marker
simplifications and cleanups
Reviewed-by: stefank, cnorrbin
---
src/hotspot/share/gc/z/zBarrierSet.inline.hpp | 5 +-
.../share/oops/accessBackend.inline.hpp | 14 +-
src/hotspot/share/oops/flatArrayKlass.cpp | 5 +-
src/hotspot/share/oops/valuePayload.hpp | 17 ++-
.../share/oops/valuePayload.inline.hpp | 129 ++++++++----------
5 files changed, 72 insertions(+), 98 deletions(-)
diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp
index 566e503ccf3..beb0ff8dfad 100644
--- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp
+++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp
@@ -497,8 +497,7 @@ inline void ZBarrierSet::AccessBarrier::value_copy_in_h
ValueKlass* const klass = src.klass();
- const LayoutKind layout_kind = LayoutKindHelper::get_copy_layout(src.layout_kind(), dst.layout_kind());
- const size_t payload_size = klass->layout_size_in_bytes(layout_kind);
+ const size_t payload_size = ValuePayload::copy_size_in_bytes(src, dst);
// The addr() points at the payload start, not the object start.
const address src_payload = src.addr();
@@ -537,7 +536,7 @@ inline void ZBarrierSet::AccessBarrier::value_store_nul
return;
}
- const size_t payload_size = klass->layout_size_in_bytes(layout_kind);
+ const size_t payload_size = dst.size_in_bytes();
// The addr() points at the payload start, not the object start.
const address dst_payload = dst.addr();
diff --git a/src/hotspot/share/oops/accessBackend.inline.hpp b/src/hotspot/share/oops/accessBackend.inline.hpp
index ab99247223d..1c8585185b7 100644
--- a/src/hotspot/share/oops/accessBackend.inline.hpp
+++ b/src/hotspot/share/oops/accessBackend.inline.hpp
@@ -336,23 +336,13 @@ template
inline void RawAccessBarrier::value_copy(const ValuePayload& src, const ValuePayload& dst) {
precond(src.klass() == dst.klass());
- const ValueKlass* klass = src.klass();
- const LayoutKind copy_layout = LayoutKindHelper::get_copy_layout(
- src.layout_kind(), dst.layout_kind());
- const int size = klass->layout_size_in_bytes(copy_layout);
-
AccessInternal::value_copy_internal(src.addr(), dst.addr(),
- static_cast(size));
+ ValuePayload::copy_size_in_bytes(src, dst));
}
template
inline void RawAccessBarrier::value_store_null(const ValuePayload& dst) {
- address dst_addr = dst.addr();
- const LayoutKind lk = dst.layout_kind();
- const ValueKlass* klass = dst.klass();
- const int size = klass->layout_size_in_bytes(lk);
-
- AccessInternal::value_store_null(dst_addr, static_cast(size));
+ AccessInternal::value_store_null(dst.addr(), dst.size_in_bytes());
}
#endif // SHARE_OOPS_ACCESSBACKEND_INLINE_HPP
diff --git a/src/hotspot/share/oops/flatArrayKlass.cpp b/src/hotspot/share/oops/flatArrayKlass.cpp
index f5ddcd1b68d..73c3b233182 100644
--- a/src/hotspot/share/oops/flatArrayKlass.cpp
+++ b/src/hotspot/share/oops/flatArrayKlass.cpp
@@ -256,8 +256,7 @@ void FlatArrayKlass::copy_array(arrayOop s, int src_pos,
if (fsk->layout_kind() == fdk->layout_kind()) {
// Because source and destination have the same layout, we do not have
- // to worry about null checks and atomicity problems and can call the
- // Access API directly.
+ // to worry about null checks and atomicity problems.
int index_delta;
if (needs_backwards_copy(sa, src_pos, da, dst_pos, length)) {
index_delta = -1;
@@ -268,7 +267,7 @@ void FlatArrayKlass::copy_array(arrayOop s, int src_pos,
}
for (int i = 0; i < length; i++) {
- HeapAccess<>::value_copy(src_payload, dst_payload);
+ src_payload.copy_to(dst_payload);
src_payload.advance_index(index_delta);
dst_payload.advance_index(index_delta);
}
diff --git a/src/hotspot/share/oops/valuePayload.hpp b/src/hotspot/share/oops/valuePayload.hpp
index 1e742729bbe..63673f12efe 100644
--- a/src/hotspot/share/oops/valuePayload.hpp
+++ b/src/hotspot/share/oops/valuePayload.hpp
@@ -110,12 +110,14 @@ class ValuePayload {
inline void set_offset(ptrdiff_t offset);
static inline void copy(const ValuePayload& src,
- const ValuePayload& dst,
- LayoutKind copy_layout_kind);
+ const ValuePayload& dst);
inline void mark_as_non_null();
inline void mark_as_null();
+ inline bool has_null_marker() const;
+ inline bool is_payload_null() const;
+
inline bool uses_absolute_addr() const;
inline oop& container();
@@ -127,8 +129,7 @@ class ValuePayload {
inline void assert_is_flat_field(const InstanceKlass* klass, int offset) const NOT_DEBUG_RETURN;
inline void assert_post_construction_invariants() const NOT_DEBUG_RETURN;
static inline void assert_pre_copy_invariants(const ValuePayload& src,
- const ValuePayload& dst,
- LayoutKind copy_layout_kind) NOT_DEBUG_RETURN;
+ const ValuePayload& dst) NOT_DEBUG_RETURN;
public:
inline ValueKlass* klass() const;
@@ -137,12 +138,13 @@ class ValuePayload {
inline address addr() const;
- inline bool has_null_marker() const;
- inline bool is_payload_null() const;
+ inline size_t size_in_bytes() const;
class Handle;
class OopHandle;
+ static inline size_t copy_size_in_bytes(const ValuePayload& src, const ValuePayload& dst);
+
[[nodiscard]] static inline ValuePayload construct_from_parts(address absolute_addr,
ValueKlass* klass,
LayoutKind layout_kind);
@@ -200,6 +202,9 @@ class FlatValuePayload : public ValuePayload {
inline void write_without_nullability_check(valueOop obj);
inline void write(valueOop obj, TRAPS);
+ inline bool has_null_marker() const;
+ inline bool is_payload_null() const;
+
[[nodiscard]] static inline FlatValuePayload construct_from_parts(oop container,
ptrdiff_t offset,
ValueKlass* klass,
diff --git a/src/hotspot/share/oops/valuePayload.inline.hpp b/src/hotspot/share/oops/valuePayload.inline.hpp
index 4a1f567c945..07fa1ba4238 100644
--- a/src/hotspot/share/oops/valuePayload.inline.hpp
+++ b/src/hotspot/share/oops/valuePayload.inline.hpp
@@ -39,6 +39,7 @@
#include "runtime/handles.inline.hpp"
#include "runtime/javaThread.inline.hpp"
#include "utilities/debug.hpp"
+#include "utilities/integerCast.hpp"
#include "utilities/ostream.hpp"
#include "utilities/vmError.hpp"
@@ -183,31 +184,9 @@ inline void ValuePayload::set_offset(ptrdiff_t offset) {
}
inline void ValuePayload::copy(const ValuePayload& src,
- const ValuePayload& dst,
- LayoutKind copy_layout_kind) {
- assert_pre_copy_invariants(src, dst, copy_layout_kind);
-
- ValueKlass* const klass = src.klass();
-
- switch (copy_layout_kind) {
- case LayoutKind::NULLABLE_ATOMIC_FLAT:
- case LayoutKind::NULLABLE_NON_ATOMIC_FLAT: {
- if (src.is_payload_null()) {
- HeapAccess<>::value_store_null(dst);
- } else {
- HeapAccess<>::value_copy(src, dst);
- }
- } break;
- case LayoutKind::BUFFERED:
- case LayoutKind::NULL_FREE_ATOMIC_FLAT:
- case LayoutKind::NULL_FREE_NON_ATOMIC_FLAT: {
- if (!klass->is_empty_value_type()) {
- HeapAccess<>::value_copy(src, dst);
- }
- } break;
- default:
- ShouldNotReachHere();
- }
+ const ValuePayload& dst) {
+ assert_pre_copy_invariants(src, dst);
+ HeapAccess<>::value_copy(src, dst);
}
inline void ValuePayload::mark_as_non_null() {
@@ -220,6 +199,14 @@ inline void ValuePayload::mark_as_null() {
klass()->mark_payload_as_null(addr());
}
+inline bool ValuePayload::has_null_marker() const {
+ return klass()->layout_has_null_marker(layout_kind());
+}
+
+inline bool ValuePayload::is_payload_null() const {
+ return has_null_marker() && klass()->is_payload_marked_as_null(addr());
+}
+
inline bool ValuePayload::uses_absolute_addr() const {
return _storage.uses_absolute_addr();
}
@@ -360,8 +347,7 @@ inline void ValuePayload::assert_post_construction_invariants() const {
}
inline void ValuePayload::assert_pre_copy_invariants(const ValuePayload& src,
- const ValuePayload& dst,
- LayoutKind copy_layout_kind) {
+ const ValuePayload& dst) {
OnVMError on_assertion_failuire([&](outputStream* st) {
st->print_cr("=== assert_post_construction_invariants failure ===");
StreamIndentor si(st);
@@ -377,12 +363,6 @@ inline void ValuePayload::assert_pre_copy_invariants(const ValuePayload& src,
dst.print_on(st);
st->cr();
}
- {
- st->print_cr("--- copy layout kind ---");
- StreamIndentor si(st);
- LayoutKindHelper::print_on(copy_layout_kind, st);
- st->cr();
- }
});
const ValueKlass* const src_klass = src.klass();
@@ -390,6 +370,8 @@ inline void ValuePayload::assert_pre_copy_invariants(const ValuePayload& src,
precond(src_klass == dst_klass);
+ const LayoutKind copy_layout_kind = LayoutKindHelper::get_copy_layout(src.layout_kind(), dst.layout_kind());
+
const bool src_is_buffered = src.layout_kind() == LayoutKind::BUFFERED;
const bool dst_is_buffered = dst.layout_kind() == LayoutKind::BUFFERED;
const bool src_and_dst_same_layout_kind = src.layout_kind() == dst.layout_kind();
@@ -407,17 +389,12 @@ inline void ValuePayload::assert_pre_copy_invariants(const ValuePayload& src,
precond(!src_klass->supports_nullable_layouts() || container != src_klass->null_reset_value());
}
- const int src_layout_size_in_bytes = src_klass->layout_size_in_bytes(src.layout_kind());
- const int dst_layout_size_in_bytes = dst_klass->layout_size_in_bytes(dst.layout_kind());
- const int copy_layout_size_in_bytes =
- src_has_copy_layout
- ? src_layout_size_in_bytes
- : dst_layout_size_in_bytes;
+ const size_t src_layout_size_in_bytes = src.size_in_bytes();
+ const size_t dst_layout_size_in_bytes = dst.size_in_bytes();
+ const size_t copy_layout_size_in_bytes = copy_size_in_bytes(src, dst);
precond(copy_layout_size_in_bytes <= src_layout_size_in_bytes);
precond(copy_layout_size_in_bytes <= dst_layout_size_in_bytes);
- precond(LayoutKindHelper::get_copy_layout(src.layout_kind(),
- dst.layout_kind()) == copy_layout_kind);
}
#endif // ASSERT
@@ -441,12 +418,15 @@ inline address ValuePayload::addr() const {
: (cast_from_oop(container()) + offset());
}
-inline bool ValuePayload::has_null_marker() const {
- return klass()->layout_has_null_marker(layout_kind());
+inline size_t ValuePayload::size_in_bytes() const {
+ return integer_cast(klass()->layout_size_in_bytes(layout_kind()));
}
-inline bool ValuePayload::is_payload_null() const {
- return has_null_marker() && klass()->is_payload_marked_as_null(addr());
+inline size_t ValuePayload::copy_size_in_bytes(const ValuePayload& src, const ValuePayload& dst) {
+ precond(src.klass() == dst.klass());
+
+ const LayoutKind copy_layout_kind = LayoutKindHelper::get_copy_layout(src.layout_kind(), dst.layout_kind());
+ return integer_cast(src.klass()->layout_size_in_bytes(copy_layout_kind));
}
inline ValuePayload ValuePayload::construct_from_parts(address absolute_addr,
@@ -473,14 +453,16 @@ inline valueOop BufferedValuePayload::container() const {
}
inline void BufferedValuePayload::copy_to(const BufferedValuePayload& dst) {
- copy(*this, dst, LayoutKind::BUFFERED);
+ copy(*this, dst);
}
inline FlatValuePayload::FlatValuePayload(oop container,
ptrdiff_t offset,
ValueKlass* klass,
LayoutKind layout_kind)
- : ValuePayload(container, offset, klass, layout_kind) {}
+ : ValuePayload(container, offset, klass, layout_kind) {
+ postcond(LayoutKindHelper::is_flat(layout_kind));
+}
inline valueOop FlatValuePayload::allocate_instance(TRAPS) {
// Preserve the container oop across the instance allocation.
@@ -495,7 +477,7 @@ inline bool FlatValuePayload::copy_to(BufferedValuePayload& dst) {
// Copy from FLAT to BUFFERED, null marker fix may be required.
// Copy the payload to the buffered object.
- copy(*this, dst, layout_kind());
+ copy(*this, dst);
if (!has_null_marker() && dst.has_null_marker()) {
// We must fix the null marker if the src does not have a null marker but
@@ -523,39 +505,30 @@ inline void FlatValuePayload::copy_from(BufferedValuePayload& src) {
// valid non null value.
src.mark_as_non_null();
}
- copy(src, *this, layout_kind());
+ copy(src, *this);
}
inline void FlatValuePayload::copy_to(const FlatValuePayload& dst) {
- copy(*this, dst, layout_kind());
+ copy(*this, dst);
}
inline valueOop FlatValuePayload::read(TRAPS) {
- switch (layout_kind()) {
- case LayoutKind::NULLABLE_ATOMIC_FLAT:
- case LayoutKind::NULLABLE_NON_ATOMIC_FLAT: {
- if (is_payload_null()) {
- return nullptr;
- }
- } // Fallthrough
- case LayoutKind::NULL_FREE_ATOMIC_FLAT:
- case LayoutKind::NULL_FREE_NON_ATOMIC_FLAT: {
- valueOop res = allocate_instance(CHECK_NULL);
- BufferedValuePayload dst(res, klass());
- if (!copy_to(dst)) {
- // copy_to may fail if the payload has been updated with a null value
- // between our is_payload_null() check above and the copy.
- // In this case we have copied a null value into the buffer the payload.
- return nullptr;
- }
- // Must ensure the content of the buffered value is visible
- // before publishing the buffered value oop
- OrderAccess::storestore();
- return res;
- } break;
- default:
- ShouldNotReachHere();
+ if (is_payload_null()) {
+ return nullptr;
+ }
+
+ valueOop res = allocate_instance(CHECK_NULL);
+ BufferedValuePayload dst(res, klass());
+ if (!copy_to(dst)) {
+ // copy_to may fail if the payload has been updated with a null value
+ // between our is_payload_null() check above and the copy.
+ // In this case we have copied a null value into the buffer the payload.
+ return nullptr;
}
+ // Must ensure the content of the buffered value is visible
+ // before publishing the buffered value oop
+ OrderAccess::storestore();
+ return res;
}
inline void FlatValuePayload::write_without_nullability_check(valueOop obj) {
@@ -578,6 +551,14 @@ inline void FlatValuePayload::write(valueOop obj, TRAPS) {
write_without_nullability_check(obj);
}
+inline bool FlatValuePayload::has_null_marker() const {
+ return ValuePayload::has_null_marker();
+}
+
+inline bool FlatValuePayload::is_payload_null() const {
+ return ValuePayload::is_payload_null();
+}
+
inline FlatValuePayload FlatValuePayload::construct_from_parts(oop container,
ptrdiff_t offset,
ValueKlass* klass,
From 76bbfb3ee769a77f56e154e1a538cfa9f13c49f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?=
Date: Mon, 5 Oct 2026 14:00:40 +0000
Subject: [PATCH 49/98] 8382615: Expand MinMaxVector benchmark to floating
point values
Reviewed-by: roland, missa
---
.../openjdk/bench/java/lang/MinMaxVector.java | 189 ++++++++++++++++++
1 file changed, 189 insertions(+)
diff --git a/test/micro/org/openjdk/bench/java/lang/MinMaxVector.java b/test/micro/org/openjdk/bench/java/lang/MinMaxVector.java
index 3aa89604273..6bc161d933e 100644
--- a/test/micro/org/openjdk/bench/java/lang/MinMaxVector.java
+++ b/test/micro/org/openjdk/bench/java/lang/MinMaxVector.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2025, Red Hat, Inc. All rights reserved.
+ * Copyright (c) 2026 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
@@ -36,6 +37,7 @@
import org.openjdk.jmh.annotations.Warmup;
import java.util.Arrays;
+import java.util.DoubleSummaryStatistics;
import java.util.IntSummaryStatistics;
import java.util.LongSummaryStatistics;
import java.util.Random;
@@ -69,12 +71,22 @@ public static class LoopState {
int[] minIntB;
long[] minLongA;
long[] minLongB;
+ float[] minFloatA;
+ float[] minFloatB;
+ double[] minDoubleA;
+ double[] minDoubleB;
int[] maxIntA;
int[] maxIntB;
long[] maxLongA;
long[] maxLongB;
+ float[] maxFloatA;
+ float[] maxFloatB;
+ double[] maxDoubleA;
+ double[] maxDoubleB;
int[] resultIntArray;
long[] resultLongArray;
+ float[] resultFloatArray;
+ double[] resultDoubleArray;
@Setup
public void setup() {
@@ -83,12 +95,22 @@ public void setup() {
maxLongB = longs[1];
maxIntA = toInts(maxLongA);
maxIntB = toInts(maxLongB);
+ maxFloatA = toFloats(maxLongA);
+ maxFloatB = toFloats(maxLongB);
+ maxDoubleA = toDoubles(maxLongA);
+ maxDoubleB = toDoubles(maxLongB);
minLongA = negate(maxLongA);
minLongB = negate(maxLongB);
minIntA = toInts(minLongA);
minIntB = toInts(minLongB);
+ minFloatA = toFloats(minLongA);
+ minFloatB = toFloats(minLongB);
+ minDoubleA = toDoubles(minLongA);
+ minDoubleB = toDoubles(minLongB);
resultIntArray = new int[size];
resultLongArray = new long[size];
+ resultFloatArray = new float[size];
+ resultDoubleArray = new double[size];
}
static long[] negate(long[] nums) {
@@ -99,6 +121,18 @@ static int[] toInts(long[] nums) {
return Arrays.stream(nums).mapToInt(i -> (int) i).toArray();
}
+ static float[] toFloats(long[] nums) {
+ final float[] floats = new float[nums.length];
+ for (int i = 0; i < nums.length; i++) {
+ floats[i] = (float) nums[i];
+ }
+ return floats;
+ }
+
+ static double[] toDoubles(long[] nums) {
+ return Arrays.stream(nums).mapToDouble(i -> (double) i).toArray();
+ }
+
static long[][] distributeLongRandomIncrement(int size, int probability) {
long[][] result;
int aboveCount, abovePercent;
@@ -166,10 +200,18 @@ public static class RangeState
int[] resultInts;
long[] longs;
long[] resultLongs;
+ float[] floats;
+ float[] resultFloats;
+ double[] doubles;
+ double[] resultDoubles;
int highestInt;
int lowestInt;
long highestLong;
long lowestLong;
+ float highestFloat;
+ float lowestFloat;
+ double highestDouble;
+ double lowestDouble;
Random r = new Random(seed);
@Setup
@@ -178,10 +220,16 @@ public void setup() {
resultInts = new int[size];
longs = new long[size];
resultLongs = new long[size];
+ floats = new float[size];
+ resultFloats = new float[size];
+ doubles = new double[size];
+ resultDoubles = new double[size];
for (int i = 0; i < size; i++) {
ints[i] = r.nextInt();
longs[i] = r.nextLong();
+ floats[i] = r.nextFloat();
+ doubles[i] = r.nextDouble();
}
final IntSummaryStatistics intStats = Arrays.stream(ints).summaryStatistics();
@@ -191,6 +239,19 @@ public void setup() {
final LongSummaryStatistics longStats = Arrays.stream(longs).summaryStatistics();
highestLong = (long) (longStats.getMax() * (range / 100f));
lowestLong = longStats.getMin() + (longStats.getMax() - highestLong);
+
+ float maxFloat = Float.MIN_VALUE;
+ float minFloat = Float.MAX_VALUE;
+ for (float f : floats) {
+ maxFloat = Math.max(maxFloat, f);
+ minFloat = Math.min(minFloat, f);
+ }
+ highestFloat = maxFloat * (range / 100f);
+ lowestFloat = minFloat + (maxFloat - highestFloat);
+
+ final DoubleSummaryStatistics doubleStats = Arrays.stream(doubles).summaryStatistics();
+ highestDouble = doubleStats.getMax() * (range / 100f);
+ lowestDouble = doubleStats.getMin() + (doubleStats.getMax() - highestDouble);
}
}
@@ -321,4 +382,132 @@ public long longReductionSimpleMax(LoopState state) {
}
return result;
}
+
+ @Benchmark
+ public float[] floatClippingRange(RangeState state) {
+ for (int i = 0; i < state.size; i++) {
+ state.resultFloats[i] = Math.min(Math.max(state.floats[i], state.lowestFloat), state.highestFloat);
+ }
+ return state.resultFloats;
+ }
+
+ @Benchmark
+ public float[] floatLoopMin(LoopState state) {
+ for (int i = 0; i < state.size; i++) {
+ state.resultFloatArray[i] = Math.min(state.minFloatA[i], state.minFloatB[i]);
+ }
+ return state.resultFloatArray;
+ }
+
+ @Benchmark
+ public float[] floatLoopMax(LoopState state) {
+ for (int i = 0; i < state.size; i++) {
+ state.resultFloatArray[i] = Math.max(state.maxFloatA[i], state.maxFloatB[i]);
+ }
+ return state.resultFloatArray;
+ }
+
+ @Benchmark
+ public float floatReductionMultiplyMin(LoopState state) {
+ float result = 0;
+ for (int i = 0; i < state.size; i++) {
+ final float v = 11 * state.minFloatA[i];
+ result = Math.min(v, result);
+ }
+ return result;
+ }
+
+ @Benchmark
+ public float floatReductionSimpleMin(LoopState state) {
+ float result = 0;
+ for (int i = 0; i < state.size; i++) {
+ final float v = state.minFloatA[i];
+ result = Math.min(v, result);
+ }
+ return result;
+ }
+
+ @Benchmark
+ public float floatReductionMultiplyMax(LoopState state) {
+ float result = 0;
+ for (int i = 0; i < state.size; i++) {
+ final float v = 11 * state.maxFloatA[i];
+ result = Math.max(v, result);
+ }
+ return result;
+ }
+
+ @Benchmark
+ public float floatReductionSimpleMax(LoopState state) {
+ float result = 0;
+ for (int i = 0; i < state.size; i++) {
+ final float v = state.maxFloatA[i];
+ result = Math.max(v, result);
+ }
+ return result;
+ }
+
+ @Benchmark
+ public double[] doubleClippingRange(RangeState state) {
+ for (int i = 0; i < state.size; i++) {
+ state.resultDoubles[i] = Math.min(Math.max(state.doubles[i], state.lowestDouble), state.highestDouble);
+ }
+ return state.resultDoubles;
+ }
+
+ @Benchmark
+ public double[] doubleLoopMin(LoopState state) {
+ for (int i = 0; i < state.size; i++) {
+ state.resultDoubleArray[i] = Math.min(state.minDoubleA[i], state.minDoubleB[i]);
+ }
+ return state.resultDoubleArray;
+ }
+
+ @Benchmark
+ public double[] doubleLoopMax(LoopState state) {
+ for (int i = 0; i < state.size; i++) {
+ state.resultDoubleArray[i] = Math.max(state.maxDoubleA[i], state.maxDoubleB[i]);
+ }
+ return state.resultDoubleArray;
+ }
+
+ @Benchmark
+ public double doubleReductionMultiplyMin(LoopState state) {
+ double result = 0;
+ for (int i = 0; i < state.size; i++) {
+ final double v = 11 * state.minDoubleA[i];
+ result = Math.min(v, result);
+ }
+ return result;
+ }
+
+ @Benchmark
+ public double doubleReductionSimpleMin(LoopState state) {
+ double result = 0;
+ for (int i = 0; i < state.size; i++) {
+ final double v = state.minDoubleA[i];
+ result = Math.min(v, result);
+ }
+ return result;
+ }
+
+ @Benchmark
+ public double doubleReductionMultiplyMax(LoopState state) {
+ double result = 0;
+ for (int i = 0; i < state.size; i++) {
+ final double v = 11 * state.maxDoubleA[i];
+ result = Math.max(v, result);
+ }
+ return result;
+ }
+
+ @Benchmark
+ public double doubleReductionSimpleMax(LoopState state) {
+ double result = 0;
+ for (int i = 0; i < state.size; i++) {
+ final double v = state.maxDoubleA[i];
+ result = Math.max(v, result);
+ }
+ return result;
+ }
}
From 3bb884db76d7bad186746c3cbd707a1bfc40d812 Mon Sep 17 00:00:00 2001
From: Ioi Lam
Date: Mon, 5 Oct 2026 15:11:17 +0000
Subject: [PATCH 50/98] 8393528: DumpingWithNoCoops.java fails with 'Setting
InitialHeapSize to 4G for CDS dumping' missing
Reviewed-by: jpai
---
.../runtime/cds/appcds/DumpingWithNoCoops.java | 16 +---------------
1 file changed, 1 insertion(+), 15 deletions(-)
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/DumpingWithNoCoops.java b/test/hotspot/jtreg/runtime/cds/appcds/DumpingWithNoCoops.java
index b5fc35ad149..a179fe84243 100644
--- a/test/hotspot/jtreg/runtime/cds/appcds/DumpingWithNoCoops.java
+++ b/test/hotspot/jtreg/runtime/cds/appcds/DumpingWithNoCoops.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -79,19 +79,6 @@ String heapArgsString(HeapArgs ha) {
new HeapArgs( 2, 1, 33),
};
- static void checkExpectedMessages(HeapArgs ha, OutputAnalyzer output) throws Exception {
- final int DUMPTIME_MAX_HEAP = 4; // 4 GB
- if (ha.minSize > DUMPTIME_MAX_HEAP) {
- output.shouldContain("Setting MinHeapSize to 4G for CDS dumping");
- }
- if (ha.initialSize > DUMPTIME_MAX_HEAP) {
- output.shouldContain("Setting InitialHeapSize to 4G for CDS dumping");
- }
- if (ha.maxSize > DUMPTIME_MAX_HEAP) {
- output.shouldContain("Setting MaxHeapSize to 4G for CDS dumping");
- }
- }
-
public static void main(String[] args) throws Exception {
final String noCoops = "-XX:-UseCompressedOops";
final String logArg = "-Xlog:gc+heap=trace,cds=debug,aot=debug";
@@ -118,7 +105,6 @@ public static void main(String[] args) throws Exception {
dumptimeArgs.add(heapSize);
}
output = TestCommon.dump(appJar, appClasses, dumptimeArgs.toArray(new String[0]));
- checkExpectedMessages(ha, output);
}
TestCommon.checkDump(output);
From ddf6ad610d7fd0577e7827d30a7998ec32bb919d Mon Sep 17 00:00:00 2001
From: Emanuel Peter
Date: Mon, 5 Oct 2026 16:24:12 +0000
Subject: [PATCH 51/98] 8388560: C2 VerifyIterativeGVN: fix many missing
optimization/notification cases for arithmetic nodes
Reviewed-by: qamai, chagedorn
---
src/hotspot/share/opto/addnode.cpp | 4 +
src/hotspot/share/opto/loopopts.cpp | 2 +
src/hotspot/share/opto/node.cpp | 4 +
src/hotspot/share/opto/phaseX.cpp | 532 ++++++++----------
src/hotspot/share/opto/superword.cpp | 6 +
.../loopopts/superword/TestReductions.java | 13 +-
6 files changed, 241 insertions(+), 320 deletions(-)
diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp
index aa523fe9be8..4a6659db879 100644
--- a/src/hotspot/share/opto/addnode.cpp
+++ b/src/hotspot/share/opto/addnode.cpp
@@ -1610,6 +1610,8 @@ Node* MaxLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
}
if (can_reshape) {
return fold_subI_no_underflow_pattern(this, phase);
+ } else {
+ phase->record_for_igvn(this);
}
return nullptr;
}
@@ -1642,6 +1644,8 @@ Node* MinLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
}
if (can_reshape) {
return fold_subI_no_underflow_pattern(this, phase);
+ } else {
+ phase->record_for_igvn(this);
}
return nullptr;
}
diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp
index 77ccf3b31bd..d5332dbef54 100644
--- a/src/hotspot/share/opto/loopopts.cpp
+++ b/src/hotspot/share/opto/loopopts.cpp
@@ -612,6 +612,8 @@ Node* PhaseIdealLoop::remix_address_expressions(Node* n) {
n_op == Op_MulD) {
if (n2_loop == n_loop) {
assert(n1_loop != n_loop, "");
+ // IGVN may want to swap the edges back later, to commute (canonicalize) the operation.
+ _igvn.rehash_node_delayed(n);
n->swap_edges(1, 2);
}
}
diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp
index d16edc38e23..163b9ee8978 100644
--- a/src/hotspot/share/opto/node.cpp
+++ b/src/hotspot/share/opto/node.cpp
@@ -1238,6 +1238,10 @@ bool Node::has_special_unique_user() const {
} else if (op == Op_LoadUS && n->Opcode() == Op_LShiftI) {
// Condition for RShiftI(LShiftI(LoadUS(...), 16), 16) => LoadS(...), see RShiftINode::Ideal
return true;
+ } else if ((op == Op_LoadB || op == Op_LoadS) && n->Opcode() == Op_AndI) {
+ // AndINode::Ideal turns AndI(LoadB/S) into AndI(LoadUB/US), if the LoadB
+ // only has a single use.
+ return true;
} else if (op == Op_AddL) {
// Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y))
return n->Opcode() == Op_ConvL2I && n->in(1) == this;
diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp
index c3f255ab08e..9587d0d046d 100644
--- a/src/hotspot/share/opto/phaseX.cpp
+++ b/src/hotspot/share/opto/phaseX.cpp
@@ -440,22 +440,34 @@ PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn,
assert(worklist.is_subset_of(_useful), "only useful nodes should still be in the worklist");
+ // While we don't need to rehash, some optimizations are sensitive to the
+ // relative ordering of node IDs, for example AddNode::commute wants to keep
+ // in1 < in2. Therefore, we keep the relative ordering stable.
+ uint next_idx = 0;
+ for (int old_idx = 0; old_idx < _old2new_map.length(); old_idx++) {
+ if (_useful.member_set().test(old_idx)) {
+ _old2new_map.at_put(old_idx, next_idx++);
+ }
+ }
+ assert(next_idx == _useful.size(), "must map all useful nodes");
+
// Iterate over the set of live nodes.
for (uint current_idx = 0; current_idx < _useful.size(); current_idx++) {
Node* n = _useful.at(current_idx);
- const Type* type = gvn->type_or_null(n);
- _new_type_array.map(current_idx, type);
+ uint old_idx = n->_idx;
+ int new_idx = _old2new_map.at(old_idx);
+ assert(new_idx >= 0, "every useful node must have new idx");
- assert(_old2new_map.at(n->_idx) == -1, "already seen");
- _old2new_map.at_put(n->_idx, current_idx);
+ const Type* type = gvn->type_or_null(n);
+ _new_type_array.map(new_idx, type);
if (old_node_note_array != nullptr) {
- Node_Notes* nn = C->locate_node_notes(old_node_note_array, n->_idx);
- C->set_node_notes_at(current_idx, nn);
+ Node_Notes* nn = C->locate_node_notes(old_node_note_array, old_idx);
+ C->set_node_notes_at(new_idx, nn);
}
- n->set_idx(current_idx); // Update node ID.
+ n->set_idx(new_idx); // Update node ID.
if (update_embedded_ids(n) < 0) {
_delayed.push(n); // has embedded IDs; handle later
@@ -1379,6 +1391,51 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape, bool deep_revisit
// because there are known cases where Ideal can optimize after IGVN.
// Some may be expected and cannot be fixed, and others should be fixed.
switch (n->Opcode()) {
+ // BoolNode::Ideal canonicalizes integer comparisons, but only if "!is_counted_loop_exit_test".
+ // We only optimize if:
+ // Cmp -> Bool -> If
+ // And not if:
+ // Cmp -> Bool -> CountedLoopEnd
+ // In loop unswitching, we turn a CountedLoopEnd into an If.
+ // We would now have to notify the input of the modified node,
+ // which we don't do so far.
+ // One simple hack would be to just push the Bool node on
+ // the worklist in that optimization, in an ad-hoc fashon.
+ // But more principled would probably be to do this as part
+ // of replace_input_of, which calls set_req_X, which already
+ // has some notification logic, for example using
+ // Node::has_special_unique_user. There are also other places
+ // the graph could be updated and lose the CountedLoopEnd node,
+ // and in those places we also use Node::has_special_unique_user,
+ // and other related code.
+ // I would suggest we refactor and extend that notification
+ // code in a future RFE.
+ //
+ // Found with:
+ // -XX:VerifyIterativeGVN=1110
+ // compiler/loopopts/TestBaseCountedEndLoopUnswitchCandidate.java
+ case Op_Bool:
+ return;
+
+ // I have encountered some issues with AddHF.
+ // It could be due to issues arising from JDK-8388873, we should
+ // check again after that is fixed.
+ //
+ // Found on aarch64 with:
+ // -XX:-TieredCompilation -XX:VerifyIterativeGVN=1110
+ // compiler/c2/irTests/TestFloat16ScalarOperations.java
+ case Op_AddHF:
+ return;
+
+ // In XorI/LNode::Ideal, we optimize Xor(x, -1), but
+ // only if is_used_in_only_arithmetic: so we would
+ // need notification if the Xor only has arithmetic
+ // nodes. I think this also calls for a generalization
+ // of Node::has_special_unique_user.
+ case Op_XorI:
+ case Op_XorL:
+ return;
+
// RegionNode::Ideal does "Skip around the useless IF diamond".
// 245 IfTrue === 244
// 258 If === 245 257
@@ -1398,182 +1455,6 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape, bool deep_revisit
case Op_Region:
return;
- // In AddNode::Ideal, we call "commute", which swaps the inputs so
- // that smaller idx are first. Tracking it back, it led me to
- // PhaseIdealLoop::remix_address_expressions which swapped the edges.
- //
- // Example:
- // Before PhaseIdealLoop::remix_address_expressions
- // 154 AddI === _ 12 144
- // After PhaseIdealLoop::remix_address_expressions
- // 154 AddI === _ 144 12
- // After AddNode::Ideal
- // 154 AddI === _ 12 144
- //
- // I suspect that the node should be added to the IGVN worklist after
- // PhaseIdealLoop::remix_address_expressions
- //
- // This is the only case I looked at, there may be others. Found like this:
- // java -XX:VerifyIterativeGVN=0100 -Xbatch --version
- //
- // The following hit the same logic in PhaseIdealLoop::remix_address_expressions.
- //
- // Note: currently all of these fail also for other reasons, for example
- // because of "commute" doing the reordering with the phi below. Once
- // that is resolved, we can come back to this issue here.
- //
- // case Op_AddD:
- // case Op_AddI:
- // case Op_AddL:
- // case Op_AddF:
- // case Op_MulI:
- // case Op_MulL:
- // case Op_MulF:
- // case Op_MulD:
- // if (n->in(1)->_idx > n->in(2)->_idx) {
- // // Expect "commute" to revert this case.
- // return false;
- // }
- // break; // keep verifying
-
- // AddFPNode::Ideal calls "commute", which can reorder the inputs for this:
- // Check for tight loop increments: Loop-phi of Add of loop-phi
- // It wants to take the phi into in(1):
- // 471 Phi === 435 38 390
- // 390 AddF === _ 471 391
- //
- // Other Associative operators are also affected equally.
- //
- // Investigate why this does not happen earlier during IGVN.
- //
- // Found with:
- // test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java
- // -XX:VerifyIterativeGVN=1110
- case Op_AddD:
- //case Op_AddI: // Also affected for other reasons, see case further down.
- //case Op_AddL: // Also affected for other reasons, see case further down.
- case Op_AddF:
- case Op_MulI:
- case Op_MulL:
- case Op_MulF:
- case Op_MulD:
- case Op_MinF:
- case Op_MinD:
- case Op_MaxF:
- case Op_MaxD:
- // XorINode::Ideal
- // Found with:
- // compiler/intrinsics/chacha/TestChaCha20.java
- // -XX:VerifyIterativeGVN=1110
- case Op_XorI:
- case Op_XorL:
- // It seems we may have similar issues with the HF cases.
- // Found with aarch64:
- // compiler/vectorization/TestFloat16VectorOperations.java
- // -XX:VerifyIterativeGVN=1110
- case Op_AddHF:
- case Op_MulHF:
- case Op_MaxHF:
- case Op_MinHF:
- return;
-
- // In MulNode::Ideal the edges can be swapped to help value numbering:
- //
- // // We are OK if right is a constant, or right is a load and
- // // left is a non-constant.
- // if( !(t2->singleton() ||
- // (in(2)->is_Load() && !(t1->singleton() || in(1)->is_Load())) ) ) {
- // if( t1->singleton() || // Left input is a constant?
- // // Otherwise, sort inputs (commutativity) to help value numbering.
- // (in(1)->_idx > in(2)->_idx) ) {
- // swap_edges(1, 2);
- //
- // Why was this not done earlier during IGVN?
- //
- // Found with:
- // test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithG1.java
- // -XX:VerifyIterativeGVN=1110
- case Op_AndI:
- // Same for AndL.
- // Found with:
- // compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java
- // -XX:VerifyIterativeGVN=1110
- case Op_AndL:
- return;
-
- // SubLNode::Ideal does transform like:
- // Convert "c1 - (y+c0)" into "(c1-c0) - y"
- //
- // In IGVN before verification:
- // 8423 ConvI2L === _ 3519 [[ 8424 ]] #long:-2
- // 8422 ConvI2L === _ 8399 [[ 8424 ]] #long:3..256:www
- // 8424 AddL === _ 8422 8423 [[ 8383 ]] !orig=[8382]
- // 8016 ConL === 0 [[ 8383 ]] #long:0
- // 8383 SubL === _ 8016 8424 [[ 8156 ]] !orig=[8154]
- //
- // And then in verification:
- // 8338 ConL === 0 [[ 8339 8424 ]] #long:-2 <----- Was constant folded.
- // 8422 ConvI2L === _ 8399 [[ 8424 ]] #long:3..256:www
- // 8424 AddL === _ 8422 8338 [[ 8383 ]] !orig=[8382]
- // 8016 ConL === 0 [[ 8383 ]] #long:0
- // 8383 SubL === _ 8016 8424 [[ 8156 ]] !orig=[8154]
- //
- // So the form changed from:
- // c1 - (y + [8423 ConvI2L])
- // to
- // c1 - (y + -2)
- // but the SubL was not added to the IGVN worklist. Investigate why.
- // There could be other issues too.
- //
- // There seems to be a related AddL IGVN optimization that triggers
- // the same SubL optimization, so investigate that too.
- //
- // Found with:
- // java -XX:VerifyIterativeGVN=0100 -Xcomp --version
- case Op_SubL:
- return;
-
- // SubINode::Ideal does
- // Convert "x - (y+c0)" into "(x-y) - c0" AND
- // Convert "c1 - (y+c0)" into "(c1-c0) - y"
- //
- // Investigate why this does not yet happen during IGVN.
- //
- // Found with:
- // test/hotspot/jtreg/compiler/c2/IVTest.java
- // -XX:VerifyIterativeGVN=1110
- case Op_SubI:
- return;
-
- // AddNode::IdealIL does transform like:
- // Convert x + (con - y) into "(x - y) + con"
- //
- // In IGVN before verification:
- // 8382 ConvI2L
- // 8381 ConvI2L === _ 791 [[ 8383 ]] #long:0
- // 8383 SubL === _ 8381 8382
- // 8168 ConvI2L
- // 8156 AddL === _ 8168 8383 [[ 8158 ]]
- //
- // And then in verification:
- // 8424 AddL
- // 8016 ConL === 0 [[ 8383 ]] #long:0 <--- Was constant folded.
- // 8383 SubL === _ 8016 8424
- // 8168 ConvI2L
- // 8156 AddL === _ 8168 8383 [[ 8158 ]]
- //
- // So the form changed from:
- // x + (ConvI2L(0) - [8382 ConvI2L])
- // to
- // x + (0 - [8424 AddL])
- // but the AddL was not added to the IGVN worklist. Investigate why.
- // There could be other issues, too. For example with "commute", see above.
- //
- // Found with:
- // java -XX:VerifyIterativeGVN=0100 -Xcomp --version
- case Op_AddL:
- return;
-
// SubTypeCheckNode::Ideal calls SubTypeCheckNode::verify_helper, which does
// Node* cmp = phase->transform(new CmpPNode(subklass, in(SuperKlass)));
// record_for_cleanup(cmp, phase);
@@ -1671,20 +1552,6 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape, bool deep_revisit
case Op_ConvI2L:
return;
- // AddNode::IdealIL can do this transform (and similar other ones):
- // Convert "a*b+a*c into a*(b+c)
- // The example had AddI(MulI(a, b), MulI(a, c)). Why did this not happen
- // during IGVN? There was a mutation for one of the MulI, and only
- // after that the pattern was as needed for the optimization. The MulI
- // was added to the IGVN worklist, but not the AddI. This probably
- // can be fixed by adding the correct pattern in add_users_of_use_to_worklist.
- //
- // Found with:
- // test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java
- // -XX:VerifyIterativeGVN=1110
- case Op_AddI:
- return;
-
// ArrayCopyNode::Ideal
// calls ArrayCopyNode::prepare_array_copy
// calls Compile::conv_I2X_index -> is called with sizetype = intcon(0), I think that
@@ -1731,67 +1598,6 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape, bool deep_revisit
case Op_CastII:
return;
- // MaxLNode::Ideal
- // calls AddNode::Ideal
- // calls commute -> decides to swap edges
- //
- // Another notification issue, because we check inputs of inputs?
- // MaxL -> Phi -> Loop
- // MaxL -> Phi -> MaxL
- //
- // Found with:
- // compiler/c2/irTests/TestIfMinMax.java
- // -XX:VerifyIterativeGVN=1110
- case Op_MaxL:
- case Op_MinL:
- return;
-
- // OrINode::Ideal
- // calls AddNode::Ideal
- // calls commute -> left is Load, right not -> commute.
- //
- // Not sure why notification does not work here, seems like
- // the depth is only 1, so it should work. Needs investigation.
- //
- // Found with:
- // compiler/codegen/TestCharVect2.java#id0
- // -XX:VerifyIterativeGVN=1110
- case Op_OrI:
- case Op_OrL:
- return;
-
- // Bool -> constant folded to 1.
- // Issue with notification?
- //
- // Found with:
- // compiler/c2/irTests/TestVectorizationMismatchedAccess.java
- // -XX:VerifyIterativeGVN=1110
- case Op_Bool:
- return;
-
- // LShiftLNode::Ideal
- // Looks at pattern: "(x + x) << c0", converts it to "x << (c0 + 1)"
- // Probably a notification issue.
- //
- // Found with:
- // compiler/conversions/TestMoveConvI2LOrCastIIThruAddIs.java
- // -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110
- case Op_LShiftL:
- return;
-
- // LShiftINode::Ideal
- // pattern: ((x + con1) << con2) -> x << con2 + con1 << con2
- // Could be issue with notification of inputs of inputs
- //
- // Side-note: should cases like these not be shared between
- // LShiftI and LShiftL?
- //
- // Found with:
- // compiler/escapeAnalysis/Test6689060.java
- // -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110
- case Op_LShiftI:
- return;
-
// AddPNode::Ideal seems to do set_req without removing lock first.
// Found with various vector tests tier1-tier3.
case Op_AddP:
@@ -1841,13 +1647,6 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape, bool deep_revisit
// java -XX:VerifyIterativeGVN=1110 -Xcomp --version
case Op_CmpP:
return;
-
- // MinINode::Ideal
- // Did not investigate, but there are some patterns that might
- // need more notification.
- case Op_MinI:
- case Op_MaxI: // preemptively removed it as well.
- return;
}
if (n->is_Store()) {
@@ -2053,24 +1852,6 @@ void PhaseIterGVN::verify_Identity_for(Node* n) {
case Op_CheckCastPP:
return;
- // In SubNode::Identity, we do:
- // Convert "(X+Y) - Y" into X and "(X+Y) - X" into Y
- // In the example, the AddI had an input replaced, the AddI is
- // added to the IGVN worklist, but the SubI is one link further
- // down and is not added. I checked add_users_of_use_to_worklist
- // where I would expect the SubI would be added, and I cannot
- // find the pattern, only this one:
- // If changed AddI/SubI inputs, check CmpU for range check optimization.
- //
- // Fix this "notification" issue and check if there are any other
- // issues.
- //
- // Found with:
- // java -XX:VerifyIterativeGVN=1000 -Xcomp --version
- case Op_SubI:
- case Op_SubL:
- return;
-
// PhiNode::Identity checks for patterns like:
// r = (x != con) ? x : con;
// that can be constant folded to "x".
@@ -2084,22 +1865,6 @@ void PhaseIterGVN::verify_Identity_for(Node* n) {
// -XX:VerifyIterativeGVN=1110
case Op_Phi:
return;
-
- // ConvI2LNode::Identity does
- // convert I2L(L2I(x)) => x
- //
- // Investigate why this did not already happen during IGVN.
- //
- // Found with:
- // compiler/loopopts/superword/TestDependencyOffsets.java#vanilla-A
- // -XX:VerifyIterativeGVN=1110
- case Op_ConvI2L:
- return;
-
- // AbsINode::Identity
- // Not investigated yet.
- case Op_AbsI:
- return;
}
if (n->is_Load()) {
@@ -2533,8 +2298,18 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_
}
}
- int use_op = use->Opcode();
- if(use->is_Cmp()) { // Enable CMP/BOOL optimization
+ // AndLNode::Ideal folds GraphKit::mark_word_test patterns. Give it a chance to run.
+ if (n->is_Load() && use->is_Phi()) {
+ for (DUIterator_Fast imax, i = use->fast_outs(imax); i < imax; i++) {
+ Node* u = use->fast_out(i);
+ if (u->Opcode() == Op_AndL) {
+ worklist.push(u);
+ }
+ }
+ }
+
+ const int use_op = use->Opcode();
+ if (use->is_Cmp()) { // Enable CMP/BOOL optimization
add_users_to_worklist0(use, worklist); // Put Bool on worklist
for (DUIterator_Fast jmax, j = use->fast_outs(jmax); j < jmax; j++) {
Node* bol = use->fast_out(j);
@@ -2680,6 +2455,18 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_
return u->Opcode() == Op_AndI || u->Opcode() == Op_AndL;
});
}
+ // OrI/LNode::Ideal converts shift/or patterns into rotates, which
+ // needs to trigger when x and y common.
+ // e.g. (x << 14) | (y >>> 18)
+ if (use_op == Op_LShiftI || use_op == Op_URShiftI) {
+ add_users_to_worklist_if(worklist, use, [](Node* u) {
+ return u->Opcode() == Op_OrI;
+ });
+ } else if (use_op == Op_LShiftL || use_op == Op_URShiftL) {
+ add_users_to_worklist_if(worklist, use, [](Node* u) {
+ return u->Opcode() == Op_OrL;
+ });
+ }
// If changed LShift inputs, check CompressBits and ExpandBits users for
// compress(x, 1 << n), compress(x, -1 << n),
// expand(x, 1 << n), expand(x, -1 << n) optimizations.
@@ -2709,6 +2496,33 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_
return u->Opcode() == Op_CmpU;
});
}
+ // LShiftNode::IdealIL:
+ // (x + c1) << c2 -> (x << c2) + c3
+ // (c1 - x) << c2 -> c3 - (x << c2)
+ if (use_op == Op_AddI || use_op == Op_AddL ||
+ use_op == Op_SubI || use_op == Op_SubL) {
+ add_users_to_worklist_if(worklist, use, [](Node* u) {
+ return u->Opcode() == Op_LShiftI || u->Opcode() == Op_LShiftL;
+ });
+ }
+ // AddNode::Ideal reassociates constants to the outside, e.g.:
+ // (x + C) + y -> (x + y) + C
+ // (x | C) | y -> (x | y) | C
+ if (use->is_Add()) {
+ add_users_to_worklist_if(worklist, use, [&](Node* u) {
+ return u->Opcode() == use_op;
+ });
+ }
+ // If changed AddI/AddL inputs, check for add users:
+ // e.g. x - (y + n) -> x - (y + C) -> (x - y) + (-C)
+ // before mutation after mutation optimized by
+ // AddNode::Ideal
+ if (use_op == Op_AddI || use_op == Op_AddL) {
+ int sub_op = (use_op == Op_AddI) ? Op_SubI : Op_SubL;
+ add_users_to_worklist_if(worklist, use, [&](Node* u) {
+ return u->Opcode() == sub_op;
+ });
+ }
// If changed AddI/AddL inputs, check URShift users for
// "((X << z) + Y) >>> z" optimization in URShift{I,L}Node::Ideal.
if (use_op == Op_AddI || use_op == Op_AddL) {
@@ -2737,10 +2551,20 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_
}
}
// If changed AndI/AndL inputs, check RShift/URShift users for "(x & mask) >> shift" optimization opportunity
+ // LShiftNode::IdealIL optimizes patterns like: LShift(And(RShift(x, c), Y), c)
if (use_op == Op_AndI || use_op == Op_AndL) {
add_users_to_worklist_if(worklist, use, [](Node* u) {
return u->Opcode() == Op_RShiftI || u->Opcode() == Op_RShiftL ||
- u->Opcode() == Op_URShiftI || u->Opcode() == Op_URShiftL;
+ u->Opcode() == Op_URShiftI || u->Opcode() == Op_URShiftL ||
+ u->Opcode() == Op_LShiftI || u->Opcode() == Op_LShiftL;
+ });
+ }
+ // MulNode::AndIL_sum_and_mask can optimize:
+ // AndX(AddX(x, y), mask) -> AndX(x, mask)
+ if (use_op == Op_AddI || use_op == Op_AddL) {
+ const int and_op = (use_op == Op_AddI) ? Op_AndI : Op_AndL;
+ add_users_to_worklist_if(worklist, use, [&](Node* u) {
+ return u->Opcode() == and_op;
});
}
// Check for redundant conversion patterns:
@@ -2750,15 +2574,20 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_
// ConvI2F->ConvF2I->ConvI2F
// Note: there may be other 3-nodes conversion chains that would require to be added here, but these
// are the only ones that are known to trigger missed optimizations otherwise
+ //
+ // ConvI2LNode::Identity optimizes the following 2-hop optimization, once x is proven to be in int range:
+ // ConvI2L(ConvL2I(x)) -> x
if (use_op == Op_ConvL2D ||
use_op == Op_ConvI2F ||
use_op == Op_ConvL2F ||
- use_op == Op_ConvF2I) {
- add_users_to_worklist_if(worklist, use, [=](Node* u) {
+ use_op == Op_ConvF2I ||
+ use_op == Op_ConvL2I) {
+ add_users_to_worklist_if(worklist, use, [&](Node* u) {
return (use_op == Op_ConvL2D && u->Opcode() == Op_ConvD2L) ||
(use_op == Op_ConvI2F && u->Opcode() == Op_ConvF2I) ||
(use_op == Op_ConvL2F && u->Opcode() == Op_ConvF2L) ||
- (use_op == Op_ConvF2I && u->Opcode() == Op_ConvI2F);
+ (use_op == Op_ConvF2I && u->Opcode() == Op_ConvI2F) ||
+ (use_op == Op_ConvL2I && u->Opcode() == Op_ConvI2L);
});
}
// ConvD2F::Ideal matches ConvD2F(SqrtD(ConvF2D(x))) => SqrtF(x).
@@ -2777,7 +2606,7 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_
// address expression flattening.
if (use_op == Op_AddP) {
bool offset_changed = n == use->in(AddPNode::Offset);
- add_users_to_worklist_if(worklist, use, [=](Node* u) {
+ add_users_to_worklist_if(worklist, use, [&](Node* u) {
return u->is_Mem() ||
(offset_changed && u->is_AddP() && u->in(AddPNode::Offset)->is_Con());
});
@@ -2790,8 +2619,12 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_
});
}
// Check for Max/Min(A, Max/Min(B, C)) where A == B or A == C
- if (use->is_MinMax()) {
- add_users_to_worklist_if(worklist, use, [](Node* u) { return u->is_MinMax(); });
+ // MinMaxNode::IdealI also optimizes these cases (if no overflow):
+ // MinI(AddI(x, -1), x) -> AddI(x, -1)
+ if (use->is_MinMax() || use->Opcode() == Op_AddI) {
+ add_users_to_worklist_if(worklist, use, [](Node* u) {
+ return u->is_MinMax();
+ });
}
// Check for A | (B | C) and (B | C) | A where A == B or A == C.
if (use_op == Op_OrI || use_op == Op_OrL) {
@@ -2957,9 +2790,90 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_
// If changed Sub inputs, check Add for identity.
// e.g., (x - y) + y -> x; x + (y - x) -> y.
+ // SubI/LNode::Ideal also optimize this:
+ // (x - y) - x -> -y
if (use_op == Op_SubI || use_op == Op_SubL) {
const int add_op = (use_op == Op_SubI) ? Op_AddI : Op_AddL;
- add_users_to_worklist_if(worklist, use, [=](Node* u) { return u->Opcode() == add_op; });
+ add_users_to_worklist_if(worklist, use, [&](Node* u) {
+ return u->Opcode() == add_op || u->Opcode() == use_op;
+ });
+ }
+
+ // If changed Mul inputs, check Add/Sub for common-factor reassociation.
+ // e.g., (a * b) + (a * c) -> a * (b + c).
+ if (use_op == Op_MulI || use_op == Op_MulL) {
+ const int add_op = (use_op == Op_MulI) ? Op_AddI : Op_AddL;
+ const int sub_op = (use_op == Op_MulI) ? Op_SubI : Op_SubL;
+ add_users_to_worklist_if(worklist, use, [&](Node* u) {
+ return u->Opcode() == add_op || u->Opcode() == sub_op;
+ });
+ }
+
+ // MulNode::Ideal distributes constant multiplication:
+ // e.g., (x + c1) * c2 -> x * c2 + (c1 * c2)
+ if (use_op == Op_AddI || use_op == Op_AddL) {
+ const int mul_op = (use_op == Op_AddI) ? Op_MulI : Op_MulL;
+ add_users_to_worklist_if(worklist, use, [&](Node* u) { return u->Opcode() == mul_op; });
+ }
+
+ // We may have a loop-phi that is about to close the AddI recurrence,
+ // and we would have to ensure AddNode::commute is called for the AddI.
+ // e.g. use = Phi(x, n) -> use = Phi(x, u) -> use = Phi(x, u)
+ // u = AddI(y, use) u = AddI(y, use) -> u = AddI(use, y)
+ // current state, After mutation, After commute,
+ // before mutation before commute canonical loop incr
+ //
+ // Alternatively, we may have a region-phi, that is about to turn
+ // into a loop-phi, and where the AddI recurrence is already closed,
+ // and the AddI has its inputs sorted by idx. In this case, we also
+ // need AddNode::commute to canonicalize the AddI, so that the phi
+ // input is on the left now.
+ // e.g. use = Phi(region, u) -> use = Phi(loop, u) -> use = Phi(loop, u)
+ // u = AddI(y, use) u = AddI(y, use) -> u = AddI(use, y)
+ // current state, loop-phi, After commute,
+ // region-phi before commute canonical loop incr
+ if (use->is_Phi() &&
+ use->req() == 3 &&
+ (n == use->in(0) || // possibly: region-phi -> loop-phi
+ n == use->in(LoopNode::LoopBackControl))) { // possibly: closing AddI recurrence
+ add_users_to_worklist_if(worklist, use, [](Node* u) {
+ return u->is_Add();
+ });
+ }
+
+ // AndLNode::Ideal optimizes GraphKit::mark_word_test patterns
+ // Pattern: AndL(LoadL(x=mark word), y)
+ // Pattern: AndL(Phi(LoadL(x=mark word), z), y)
+ if (use->is_Load()) {
+ for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) {
+ Node* u = use->fast_out(i2);
+ if (u->Opcode() == Op_AndL) {
+ // n -> Load -> AndL
+ worklist.push(u);
+ } else if (u->is_Phi()) {
+ // n -> Load -> Phi -> AndL
+ add_users_to_worklist_if(worklist, u, [](Node* u2) {
+ return u2->Opcode() == Op_AndL;
+ });
+ }
+ }
+ }
+
+ // PhiNode::Ideal can optimize:
+ // Pattern: Phi(condition, x + y, x) -> x + Phi(condition, y, 0)
+ if (use_op == Op_AddI) {
+ add_users_to_worklist_if(worklist, use, [](Node* u) {
+ return u->is_Phi();
+ });
+ }
+
+ // AndVNode::Ideal and OrVNode::Ideal have 2-hop operations for
+ // repeated and/or with the same value:
+ // Pattern: AndV(AndV(a, b), a) -> AndV(a, b)
+ if (use_op == Op_AndV || use_op == Op_OrV) {
+ add_users_to_worklist_if(worklist, use, [&](Node* u) {
+ return u->Opcode() == use_op;
+ });
}
// (Phi (ValueType ValueType)) is transformed into (ValueType (Phi ) (Phi )...)
// and is applied if there are EncodeP/DecodeN or casts between a Phi and InlineType nodes
diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp
index 8acdf2b8000..62fa32c7045 100644
--- a/src/hotspot/share/opto/superword.cpp
+++ b/src/hotspot/share/opto/superword.cpp
@@ -1081,10 +1081,12 @@ SuperWord::PairOrderStatus SuperWord::order_inputs_of_uses_to_match_def_pair(Nod
if (is_marked_reduction(use1) && is_marked_reduction(use2)) {
Node* use1_in2 = use1->in(2);
if (use1_in2->is_Phi() || is_marked_reduction(use1_in2)) {
+ igvn().rehash_node_delayed(use1);
use1->swap_edges(1, 2);
}
Node* use2_in2 = use2->in(2);
if (use2_in2->is_Phi() || is_marked_reduction(use2_in2)) {
+ igvn().rehash_node_delayed(use2);
use2->swap_edges(1, 2);
}
return PairOrderStatus::Ordered;
@@ -1100,14 +1102,17 @@ SuperWord::PairOrderStatus SuperWord::order_inputs_of_uses_to_match_def_pair(Nod
if (i1 != i2) {
if ((i1 == (3-i2)) && (use2->is_Add() || use2->is_Mul())) {
// 2. Commutative: swap edges, and hope the other position matches too.
+ igvn().rehash_node_delayed(use2);
use2->swap_edges(i1, i2);
} else if (VectorNode::is_muladds2i(use2) && use1 != use2) {
// 3.a/b: MulAddS2I.
if (i1 == 5 - i2) { // ((i1 == 3 && i2 == 2) || (i1 == 2 && i2 == 3) || (i1 == 1 && i2 == 4) || (i1 == 4 && i2 == 1))
+ igvn().rehash_node_delayed(use2);
use2->swap_edges(1, 2);
use2->swap_edges(3, 4);
}
if (i1 == 3 - i2 || i1 == 7 - i2) { // ((i1 == 1 && i2 == 2) || (i1 == 2 && i2 == 1) || (i1 == 3 && i2 == 4) || (i1 == 4 && i2 == 3))
+ igvn().rehash_node_delayed(use2);
use2->swap_edges(2, 3);
use2->swap_edges(1, 4);
}
@@ -1118,6 +1123,7 @@ SuperWord::PairOrderStatus SuperWord::order_inputs_of_uses_to_match_def_pair(Nod
}
} else if (i1 == i2 && VectorNode::is_muladds2i(use2) && use1 != use2) {
// 3.c: MulAddS2I.
+ igvn().rehash_node_delayed(use2);
use2->swap_edges(1, 3);
use2->swap_edges(2, 4);
return PairOrderStatus::Unknown;
diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java
index 599e95bd6ab..d7b4278ede9 100644
--- a/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java
+++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java
@@ -118,8 +118,7 @@ public static void main(String[] args) {
switch (args[0]) {
case "P0" -> { framework.addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:AutoVectorizationOverrideProfitability=0"); }
case "P1" -> { framework.addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:AutoVectorizationOverrideProfitability=1"); }
- // Note: increasing the node count limit also helps in some cases.
- case "P2" -> { framework.addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:AutoVectorizationOverrideProfitability=2", "-XX:LoopUnrollLimit=1000"); }
+ case "P2" -> { framework.addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:AutoVectorizationOverrideProfitability=2"); }
default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); }
};
framework.start();
@@ -2116,15 +2115,7 @@ private static long longAddBig() {
IRNode.MUL_REDUCTION_VL, "> 0",
IRNode.MUL_VL, "> 0"},
applyIfCPUFeatureOr = {"avx512dq", "true", "sve", "true"},
- applyIfAnd = {"AutoVectorizationOverrideProfitability", "> 0",
- "LoopUnrollLimit", ">= 1000"})
- @IR(failOn = IRNode.LOAD_VECTOR_L,
- applyIfCPUFeature = {"avx512dq", "true"},
- applyIfAnd = {"AutoVectorizationOverrideProfitability", "> 0",
- "LoopUnrollLimit", "< 1000"})
- // Increasing the body limit seems to help. Filed for investigation: JDK-8370685
- // If you can eliminate this exception for LoopUnrollLimit, please remove
- // the flag completely from the test, also the "addFlags" at the top.
+ applyIf = {"AutoVectorizationOverrideProfitability", "> 0"})
@IR(failOn = IRNode.LOAD_VECTOR_L,
applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"})
// MulVL is not implemented on NEON, so we also not have the reduction.
From 6602ddf2f2d6b9d5693519bc82b00a91c3838976 Mon Sep 17 00:00:00 2001
From: Liyuan Wang
Date: Mon, 5 Oct 2026 17:03:03 +0000
Subject: [PATCH 52/98] 8393048: HijrahDate.withVariant fails when the target
Hijrah variant has a shorter month
Reviewed-by: jlu
---
.../java/time/chrono/HijrahChronology.java | 1 +
.../classes/java/time/chrono/HijrahDate.java | 4 +-
.../java/time/chrono/HijrahConfigCheck.java | 15 +++++++
.../java/time/chrono/HijrahConfigTest.java | 5 ++-
...-Hijrah-variant_islamic-variant.properties | 42 +++++++++++++++++++
5 files changed, 64 insertions(+), 3 deletions(-)
create mode 100644 test/jdk/java/time/nonjunit/java/time/chrono/hijrah-config-Hijrah-variant_islamic-variant.properties
diff --git a/src/java.base/share/classes/java/time/chrono/HijrahChronology.java b/src/java.base/share/classes/java/time/chrono/HijrahChronology.java
index ccc3dd3d858..3551e6c80f6 100644
--- a/src/java.base/share/classes/java/time/chrono/HijrahChronology.java
+++ b/src/java.base/share/classes/java/time/chrono/HijrahChronology.java
@@ -637,6 +637,7 @@ int getDayOfYear(int prolepticYear, int month) {
* @return the length of the month
*/
int getMonthLength(int prolepticYear, int monthOfYear) {
+ checkCalendarInit();
int epochMonth = yearToEpochMonth(prolepticYear) + (monthOfYear - 1);
if (epochMonth < 0 || epochMonth >= hijrahEpochMonthStartDays.length) {
throw new DateTimeException("Invalid Hijrah date, year: " +
diff --git a/src/java.base/share/classes/java/time/chrono/HijrahDate.java b/src/java.base/share/classes/java/time/chrono/HijrahDate.java
index bdd3c0a25c1..d40de870d88 100644
--- a/src/java.base/share/classes/java/time/chrono/HijrahDate.java
+++ b/src/java.base/share/classes/java/time/chrono/HijrahDate.java
@@ -452,7 +452,7 @@ public HijrahDate with(TemporalAdjuster adjuster) {
* HijrahChronology. If the chronology has a shorter month length
* for the month, the day is reduced to be the last day of the month.
*
- * @param chronology the new HijrahChonology, non-null
+ * @param chronology the new HijrahChronology, non-null
* @return a HijrahDate with the requested HijrahChronology, non-null
*/
public HijrahDate withVariant(HijrahChronology chronology) {
@@ -460,7 +460,7 @@ public HijrahDate withVariant(HijrahChronology chronology) {
return this;
}
// Like resolvePreviousValid the day is constrained to stay in the same month
- int monthDays = chronology.getDayOfYear(prolepticYear, monthOfYear);
+ int monthDays = chronology.getMonthLength(prolepticYear, monthOfYear);
return HijrahDate.of(chronology, prolepticYear, monthOfYear,(dayOfMonth > monthDays) ? monthDays : dayOfMonth );
}
diff --git a/test/jdk/java/time/nonjunit/java/time/chrono/HijrahConfigCheck.java b/test/jdk/java/time/nonjunit/java/time/chrono/HijrahConfigCheck.java
index 317ba15205b..a40686a068b 100644
--- a/test/jdk/java/time/nonjunit/java/time/chrono/HijrahConfigCheck.java
+++ b/test/jdk/java/time/nonjunit/java/time/chrono/HijrahConfigCheck.java
@@ -28,11 +28,14 @@
import java.time.ZoneOffset;
import java.time.chrono.ChronoLocalDateTime;
import java.time.chrono.Chronology;
+import java.time.chrono.HijrahChronology;
+import java.time.chrono.HijrahDate;
import java.util.Locale;
public class HijrahConfigCheck {
private static final String VALID_CALTYPE = "islamic-valid";
private static final String INVALID_CALTYPE = "islamic-invalid";
+ private static final String VARIANT_CALTYPE = "islamic-variant";
public static void main(String... args) {
// Availability test
@@ -71,5 +74,17 @@ public static void main(String... args) {
throw new RuntimeException("Unexpected exception for invalid Hijrah configuration", ex);
}
}
+
+ // Variant configuration test
+ // Year 1300 month 1 in the variant config has 29 days,
+ // so day 30 is clamped to 29.
+ HijrahChronology variantChronology = (HijrahChronology) Chronology.of(VARIANT_CALTYPE);
+ HijrahDate hijrahDateWithVariant = HijrahDate.of(1300, 1, 30).withVariant(variantChronology);
+ HijrahDate expected = variantChronology.date(1300,1,29);
+ if (!hijrahDateWithVariant.equals(expected)) {
+ throw new RuntimeException("Variant Hijrah configuration did not produce expected date. " +
+ "Expected: " + expected + ", but got: " + hijrahDateWithVariant);
+ }
+
}
}
diff --git a/test/jdk/java/time/nonjunit/java/time/chrono/HijrahConfigTest.java b/test/jdk/java/time/nonjunit/java/time/chrono/HijrahConfigTest.java
index f809a7ab855..23d1a0eec47 100644
--- a/test/jdk/java/time/nonjunit/java/time/chrono/HijrahConfigTest.java
+++ b/test/jdk/java/time/nonjunit/java/time/chrono/HijrahConfigTest.java
@@ -32,7 +32,7 @@
/*
* @test
* @summary Tests whether a custom Hijrah configuration properties file works correctly
- * @bug 8187987 8392848
+ * @bug 8187987 8392848 8393048
* @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g)
* @library /tools/lib /test/lib
* @modules java.base/jdk.internal.jimage
@@ -45,6 +45,7 @@ public class HijrahConfigTest {
private static final String VALID_TEST_CONFIG = "hijrah-config-Hijrah-valid_islamic-valid.properties";
private static final String INVALID_TEST_CONFIG = "hijrah-config-Hijrah-invalid_islamic-invalid.properties";
+ private static final String VARIANT_TEST_CONFIG = "hijrah-config-Hijrah-variant_islamic-variant.properties";
public static void main(String[] args) throws Exception {
Helper helper = Helper.newHelper();
@@ -67,6 +68,8 @@ public static void main(String[] args) throws Exception {
confPath.resolve(VALID_TEST_CONFIG));
Files.copy(Path.of(System.getProperty("test.src"), INVALID_TEST_CONFIG),
confPath.resolve(INVALID_TEST_CONFIG));
+ Files.copy(Path.of(System.getProperty("test.src"), VARIANT_TEST_CONFIG),
+ confPath.resolve(VARIANT_TEST_CONFIG));
// Run tests
Path launcher = outputPath.resolve("bin").resolve("java");
diff --git a/test/jdk/java/time/nonjunit/java/time/chrono/hijrah-config-Hijrah-variant_islamic-variant.properties b/test/jdk/java/time/nonjunit/java/time/chrono/hijrah-config-Hijrah-variant_islamic-variant.properties
new file mode 100644
index 00000000000..a3b70342382
--- /dev/null
+++ b/test/jdk/java/time/nonjunit/java/time/chrono/hijrah-config-Hijrah-variant_islamic-variant.properties
@@ -0,0 +1,42 @@
+# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+# A test configuration properties file for a custom Hijrah chronology.
+# The data here are solely hypothetical and do not represent any of
+# the actual Hijrah variants.
+
+# Test-only custom chronology for JDK-8393048
+# Year 1300 month 1 is deliberately set as a shorter month of 29 days.
+
+# Version of this definition
+version=0.1
+
+# Java chronology ID
+id=Hijrah-variant
+
+# Standard calendar type specification
+type=islamic-variant
+
+# defines the corresponding ISO date to the earliest Hijrah date
+iso-start=1882-11-12
+
+# 1 2 3 4 5 6 7 8 9 10 11 12
+1300=29 30 30 29 30 30 29 30 29 30 29 29
From a3f7f9c8d961d9df796381ba8b4e943f96f20a49 Mon Sep 17 00:00:00 2001
From: Naoto Sato
Date: Mon, 5 Oct 2026 17:24:22 +0000
Subject: [PATCH 53/98] 8392996: Timezone name formatting repeatedly looks up
missing CLDR dstOffset data
Reviewed-by: jlu
---
.../tools/cldrconverter/CLDRConverter.java | 21 +++++++++++----
.../ResourceBundleGenerator.java | 2 +-
.../classes/java/text/SimpleDateFormat.java | 7 +++--
.../time/format/DateTimeFormatterBuilder.java | 4 +--
.../classes/sun/util/calendar/ZoneInfo.java | 13 +++++++++-
.../sun/util/calendar/ZoneInfoFile.java | 4 +--
.../util/locale/provider/LocaleResources.java | 26 +++++++++++++++----
.../locale/provider/TimeZoneNameUtility.java | 21 ++++++++++-----
8 files changed, 72 insertions(+), 26 deletions(-)
diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
index b7754326c97..5de53add192 100644
--- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
+++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
@@ -87,7 +87,7 @@ public class CLDRConverter {
static final String EXEMPLAR_CITY_PREFIX = "timezone.excity.";
static final String ZONE_NAME_PREFIX = "timezone.displayname.";
static final String METAZONE_ID_PREFIX = "metazone.id.";
- static final String METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset.";
+ static final String METAZONE_DSTOFFSETS = "metazone.dstoffsets";
static final String PARENT_LOCALE_PREFIX = "parentLocale.";
static final String LIKELY_SCRIPT_PREFIX = "likelyScript.";
static final String META_EMPTY_ZONE_NAME = "EMPTY_ZONE";
@@ -863,10 +863,21 @@ private static Map extractZoneNames(Map map, Str
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
names.putAll(exCities);
- // Explicit metazone offsets
- if (id.equals("root")) {
- explicitDstOffsets.forEach((k, v) ->
- names.put(METAZONE_DSTOFFSET_PREFIX + k, v));
+ // Explicit metazone offsets. For example,
+ // "metazone.dstoffsets" -> "America/Vancouver=-07;Europe/Dublin=+01"
+ if (id.equals("root") && !explicitDstOffsets.isEmpty()) {
+ names.put(METAZONE_DSTOFFSETS,
+ explicitDstOffsets.entrySet().stream()
+ .sorted(Map.Entry.comparingByKey())
+ .map(e -> {
+ String tzid = e.getKey();
+ if (tzid.isEmpty() || tzid.indexOf('=') >= 0 || tzid.indexOf(';') >= 0) {
+ throw new IllegalArgumentException("Invalid timezone ID: " + tzid);
+ }
+ ZoneOffset.of(e.getValue()); // checks if the offset is valid
+ return tzid + "=" + e.getValue();
+ })
+ .collect(Collectors.joining(";")));
}
// If there's no UTC entry at this point, add an empty one
diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java
index 8e9635ab519..dd06587b0e3 100644
--- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java
+++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java
@@ -197,7 +197,7 @@ public void generateBundle(String packageName, String baseName, String localeID,
var escapedVal = CLDRConverter.escape(valStr);
if (type == BundleType.TIMEZONE &&
!(key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) ||
- key.startsWith(CLDRConverter.METAZONE_DSTOFFSET_PREFIX)) ||
+ key.startsWith(CLDRConverter.METAZONE_DSTOFFSETS)) ||
valStr.startsWith(META_VALUE_PREFIX)) {
out.printf(" { \"%s\", %s },\n", keyStr, escapedVal);
} else {
diff --git a/src/java.base/share/classes/java/text/SimpleDateFormat.java b/src/java.base/share/classes/java/text/SimpleDateFormat.java
index 6957ee60bd4..66bbd55192a 100644
--- a/src/java.base/share/classes/java/text/SimpleDateFormat.java
+++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java
@@ -1303,7 +1303,7 @@ private void subFormat(int patternCharIndex, int count,
int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
int dstOffset = calendar.get(Calendar.DST_OFFSET) + zoneOffset;
- String explicitDstOffset = null;
+ ZoneOffset explicitDstOffset = null;
// Check if an explicit metazone DST offset exists.
// Only check against instances of ZoneInfo, since the standard JDK timezones
// are guaranteed to extend this internal type.
@@ -1312,14 +1312,13 @@ private void subFormat(int patternCharIndex, int count,
if (explicitDstOffset != null) {
// The time zone ID has an explicit dst offset. Ensure that
// our current TimeZone is canonical.
- var canonicalZone = ZoneInfo.getTimeZone(tzid);
- if (canonicalZone == null || !canonicalZone.equals(zi)) {
+ if (!ZoneInfo.hasCanonicalRule(zi)) {
explicitDstOffset = null;
}
}
}
boolean daylight = explicitDstOffset != null ?
- dstOffset == ZoneOffset.of(explicitDstOffset).getTotalSeconds() * 1_000 :
+ dstOffset == explicitDstOffset.getTotalSeconds() * 1_000 :
dstOffset != zoneOffset;
if (formatData.locale == null || formatData.isZoneStringsSet) {
int zoneIndex = formatData.getZoneIndex(tzid);
diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
index 9bbffe48a5e..d368c3ad8e1 100644
--- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
+++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
@@ -4514,9 +4514,9 @@ public boolean format(DateTimePrintContext context, StringBuilder buf, boolean o
if (!isGeneric) {
if (dt.isSupported(INSTANT_SECONDS)) {
// Check if an explicit metazone DST offset exists
- String dstOffset = TimeZoneNameUtility.explicitDstOffset(zname);
+ ZoneOffset dstOffset = TimeZoneNameUtility.explicitDstOffset(zname);
if (dt.isSupported(OFFSET_SECONDS) && dstOffset != null) {
- type = ZoneOffset.from(dt).equals(ZoneOffset.of(dstOffset)) ? DST : STD;
+ type = ZoneOffset.from(dt).equals(dstOffset) ? DST : STD;
} else {
type = zone.getRules().isDaylightSavings(Instant.from(dt)) ? DST : STD;
}
diff --git a/src/java.base/share/classes/sun/util/calendar/ZoneInfo.java b/src/java.base/share/classes/sun/util/calendar/ZoneInfo.java
index 9de9400c34a..7a90bff7d94 100644
--- a/src/java.base/share/classes/sun/util/calendar/ZoneInfo.java
+++ b/src/java.base/share/classes/sun/util/calendar/ZoneInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -596,6 +596,17 @@ public static TimeZone getTimeZone(String ID) {
return ZoneInfoFile.getZoneInfo(ID);
}
+ /**
+ * {@return {@code true} if the specified ZoneInfo object has the same
+ * rule as the canonical ZoneInfo for the ID, {@code false} otherwise}
+ *
+ * @param zi ZoneInfo object to check
+ */
+ public static boolean hasCanonicalRule(ZoneInfo zi) {
+ var canonical = ZoneInfoFile.getZoneInfo0(zi.getID());
+ return canonical != null && canonical.hasSameRules(zi);
+ }
+
private transient SimpleTimeZone lastRule;
/**
diff --git a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java
index 874bbd59b0f..c4dfef0fbe8 100644
--- a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java
+++ b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -134,7 +134,7 @@ public static ZoneInfo getZoneInfo(String zoneId) {
return zi;
}
- private static ZoneInfo getZoneInfo0(String zoneId) {
+ static ZoneInfo getZoneInfo0(String zoneId) {
try {
ZoneInfo zi = zones.get(zoneId);
if (zi != null) {
diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java
index 0629eadcb7c..08cd5feb5ca 100644
--- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java
+++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java
@@ -45,6 +45,7 @@
import java.text.ListFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
+import java.time.ZoneOffset;
import java.time.format.FormatStyle;
import java.util.Arrays;
import java.util.Calendar;
@@ -106,8 +107,8 @@ public class LocaleResources {
// TimeZoneNamesBundle exemplar city prefix
private static final String TZNB_EXCITY_PREFIX = "timezone.excity.";
- // TimeZoneNamesBundle explicit metazone dst offset prefix
- private static final String TZNB_METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset.";
+ // TimeZoneNamesBundle explicit metazone dst offsets
+ private static final String TZNB_METAZONE_DSTOFFSETS = "metazone.dstoffsets";
// null singleton cache value
private static final Object NULLOBJECT = new Object();
@@ -327,7 +328,7 @@ public Object getTimeZoneNames(String key) {
if (Objects.isNull(data) || Objects.isNull(val = data.get())) {
TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale);
if (key.startsWith(TZNB_EXCITY_PREFIX) ||
- key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) {
+ key.startsWith(TZNB_METAZONE_DSTOFFSETS)) {
if (tznb.containsKey(key)) {
val = tznb.getString(key);
assert val instanceof String;
@@ -360,6 +361,22 @@ public Object getTimeZoneNames(String key) {
return val;
}
+ // Returns explicit DST offset map solely for TimeZoneNameUtility.
+ // No need to be cached, as it is only invoked once.
+ public Map getExplicitDstOffsets() {
+ TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale);
+ if (tznb.containsKey("metazone.dstoffsets")) {
+ Map offsets = HashMap.newHashMap(32);
+ for (String entry : tznb.getString("metazone.dstoffsets").split(";", -1)) {
+ int separator = entry.indexOf('=');
+ offsets.put(entry.substring(0, separator), ZoneOffset.of(entry.substring(separator + 1)));
+ }
+ return offsets;
+ } else {
+ return Map.of();
+ }
+ }
+
@SuppressWarnings("unchecked")
Set getZoneIDs() {
Set zoneIDs;
@@ -385,7 +402,7 @@ String[][] getZoneStrings() {
Set tzIds = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs()));
for (String key : keyset) {
if (!key.startsWith(TZNB_EXCITY_PREFIX) &&
- !key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) {
+ !key.startsWith(TZNB_METAZONE_DSTOFFSETS)) {
value.add(rb.getStringArray(key));
tzIds.remove(key);
}
@@ -569,7 +586,6 @@ public String[] getCNPatterns(NumberFormat.Style formatStyle) {
return compactNumberPatterns;
}
-
/**
* Returns the FormatData resource bundle of this LocaleResources.
* The FormatData should be used only for accessing extra
diff --git a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java
index 014b3af680f..ca0ef170152 100644
--- a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java
+++ b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java
@@ -26,6 +26,7 @@
package sun.util.locale.provider;
import java.lang.ref.SoftReference;
+import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -61,6 +62,12 @@ public final class TimeZoneNameUtility {
private static final Map>> cachedDisplayNames =
new ConcurrentHashMap<>();
+ /**
+ * Explicit DST offset map
+ */
+ private static final LazyConstant