From 8145cfac8c697e37a05979e4b642828616764e9f Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Thu, 17 Apr 2025 16:13:45 +0000 Subject: [PATCH 001/736] 8352637: Enhance bytecode verification Reviewed-by: rhalade, mschoene, dlong, coleenp --- src/hotspot/share/classfile/stackMapTable.cpp | 10 ++++- src/hotspot/share/classfile/stackMapTable.hpp | 2 +- src/hotspot/share/classfile/verifier.cpp | 20 ++++------ .../share/interpreter/bytecodeStream.hpp | 19 ++++++++- .../share/native/libverify/check_code.c | 39 +++++++++++++------ 5 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/classfile/stackMapTable.cpp b/src/hotspot/share/classfile/stackMapTable.cpp index 9e02956aceb..85fb4de8686 100644 --- a/src/hotspot/share/classfile/stackMapTable.cpp +++ b/src/hotspot/share/classfile/stackMapTable.cpp @@ -132,8 +132,16 @@ bool StackMapTable::match_stackmap( } void StackMapTable::check_jump_target( - StackMapFrame* frame, int32_t target, TRAPS) const { + StackMapFrame* frame, int bci, int offset, TRAPS) const { ErrorContext ctx; + // Jump targets must be within the method and the method size is limited. See JVMS 4.11 + int min_offset = -1 * max_method_code_size; + if (offset < min_offset || offset > max_method_code_size) { + frame->verifier()->verify_error(ErrorContext::bad_stackmap(bci, frame), + "Illegal target of jump or branch (bci %d + offset %d)", bci, offset); + return; + } + int target = bci + offset; bool match = match_stackmap( frame, target, true, false, &ctx, CHECK_VERIFY(frame->verifier())); if (!match || (target < 0 || target >= _code_length)) { diff --git a/src/hotspot/share/classfile/stackMapTable.hpp b/src/hotspot/share/classfile/stackMapTable.hpp index 6d4c0ce36c0..9b46fa89345 100644 --- a/src/hotspot/share/classfile/stackMapTable.hpp +++ b/src/hotspot/share/classfile/stackMapTable.hpp @@ -67,7 +67,7 @@ class StackMapTable : public StackObj { // Check jump instructions. Make sure there are no uninitialized // instances on backward branch. - void check_jump_target(StackMapFrame* frame, int32_t target, TRAPS) const; + void check_jump_target(StackMapFrame* frame, int bci, int offset, TRAPS) const; // The following methods are only used inside this class. diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 9b93e283362..38dba1d3d5f 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -781,7 +781,6 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { // Merge with the next instruction { - int target; VerificationType type, type2; VerificationType atype; @@ -1606,9 +1605,8 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { case Bytecodes::_ifle: current_frame.pop_stack( VerificationType::integer_type(), CHECK_VERIFY(this)); - target = bcs.dest(); stackmap_table.check_jump_target( - ¤t_frame, target, CHECK_VERIFY(this)); + ¤t_frame, bcs.bci(), bcs.get_offset_s2(), CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_if_acmpeq : case Bytecodes::_if_acmpne : @@ -1619,19 +1617,16 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { case Bytecodes::_ifnonnull : current_frame.pop_stack( VerificationType::reference_check(), CHECK_VERIFY(this)); - target = bcs.dest(); stackmap_table.check_jump_target - (¤t_frame, target, CHECK_VERIFY(this)); + (¤t_frame, bcs.bci(), bcs.get_offset_s2(), CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_goto : - target = bcs.dest(); stackmap_table.check_jump_target( - ¤t_frame, target, CHECK_VERIFY(this)); + ¤t_frame, bcs.bci(), bcs.get_offset_s2(), CHECK_VERIFY(this)); no_control_flow = true; break; case Bytecodes::_goto_w : - target = bcs.dest_w(); stackmap_table.check_jump_target( - ¤t_frame, target, CHECK_VERIFY(this)); + ¤t_frame, bcs.bci(), bcs.get_offset_s4(), CHECK_VERIFY(this)); no_control_flow = true; break; case Bytecodes::_tableswitch : case Bytecodes::_lookupswitch : @@ -2280,15 +2275,14 @@ void ClassVerifier::verify_switch( } } } - int target = bci + default_offset; - stackmap_table->check_jump_target(current_frame, target, CHECK_VERIFY(this)); + stackmap_table->check_jump_target(current_frame, bci, default_offset, CHECK_VERIFY(this)); for (int i = 0; i < keys; i++) { // Because check_jump_target() may safepoint, the bytecode could have // moved, which means 'aligned_bcp' is no good and needs to be recalculated. aligned_bcp = align_up(bcs->bcp() + 1, jintSize); - target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize); + int offset = (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize); stackmap_table->check_jump_target( - current_frame, target, CHECK_VERIFY(this)); + current_frame, bci, offset, CHECK_VERIFY(this)); } NOT_PRODUCT(aligned_bcp = nullptr); // no longer valid at this point } diff --git a/src/hotspot/share/interpreter/bytecodeStream.hpp b/src/hotspot/share/interpreter/bytecodeStream.hpp index 89d97053b45..412951691c5 100644 --- a/src/hotspot/share/interpreter/bytecodeStream.hpp +++ b/src/hotspot/share/interpreter/bytecodeStream.hpp @@ -100,8 +100,23 @@ class BaseBytecodeStream: StackObj { void set_next_bci(int bci) { assert(0 <= bci && bci <= method()->code_size(), "illegal bci"); _next_bci = bci; } // Bytecode-specific attributes - int dest() const { return bci() + bytecode().get_offset_s2(raw_code()); } - int dest_w() const { return bci() + bytecode().get_offset_s4(raw_code()); } + int get_offset_s2() const { return bytecode().get_offset_s2(raw_code()); } + int get_offset_s4() const { return bytecode().get_offset_s4(raw_code()); } + + // These methods are not safe to use before or during verification as they may + // have large offsets and cause overflows + int dest() const { + int min_offset = -1 * max_method_code_size; + int offset = bytecode().get_offset_s2(raw_code()); + guarantee(offset >= min_offset && offset <= max_method_code_size, "must be"); + return bci() + offset; + } + int dest_w() const { + int min_offset = -1 * max_method_code_size; + int offset = bytecode().get_offset_s4(raw_code()); + guarantee(offset >= min_offset && offset <= max_method_code_size, "must be"); + return bci() + offset; + } // One-byte indices. u1 get_index_u1() const { assert_raw_index_size(1); return *(jubyte*)(bcp()+1); } diff --git a/src/java.base/share/native/libverify/check_code.c b/src/java.base/share/native/libverify/check_code.c index 7266ac8f93c..32df102dcb3 100644 --- a/src/java.base/share/native/libverify/check_code.c +++ b/src/java.base/share/native/libverify/check_code.c @@ -395,7 +395,8 @@ static jboolean is_superclass(context_type *, fullinfo_type); static void initialize_exception_table(context_type *); static int instruction_length(unsigned char *iptr, unsigned char *end); -static jboolean isLegalTarget(context_type *, int offset); +static jboolean isLegalOffset(context_type *, int bci, int offset); +static jboolean isLegalTarget(context_type *, int target); static void verify_constant_pool_type(context_type *, int, unsigned); static void initialize_dataflow(context_type *); @@ -1154,9 +1155,9 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) case JVM_OPC_goto: { /* Set the ->operand to be the instruction number of the target. */ int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2]; - int target = offset + jump; - if (!isLegalTarget(context, target)) + if (!isLegalOffset(context, offset, jump)) CCerror(context, "Illegal target of jump or branch"); + int target = offset + jump; this_idata->operand.i = code_data[target]; break; } @@ -1170,9 +1171,9 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) int jump = (((signed char)(code[offset+1])) << 24) + (code[offset+2] << 16) + (code[offset+3] << 8) + (code[offset + 4]); - int target = offset + jump; - if (!isLegalTarget(context, target)) + if (!isLegalOffset(context, offset, jump)) CCerror(context, "Illegal target of jump or branch"); + int target = offset + jump; this_idata->operand.i = code_data[target]; break; } @@ -1211,13 +1212,16 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) } } saved_operand = NEW(int, keys + 2); - if (!isLegalTarget(context, offset + _ck_ntohl(lpc[0]))) + int jump = _ck_ntohl(lpc[0]); + if (!isLegalOffset(context, offset, jump)) CCerror(context, "Illegal default target in switch"); - saved_operand[keys + 1] = code_data[offset + _ck_ntohl(lpc[0])]; + int target = offset + jump; + saved_operand[keys + 1] = code_data[target]; for (k = keys, lptr = &lpc[3]; --k >= 0; lptr += delta) { - int target = offset + _ck_ntohl(lptr[0]); - if (!isLegalTarget(context, target)) + jump = _ck_ntohl(lptr[0]); + if (!isLegalOffset(context, offset, jump)) CCerror(context, "Illegal branch in tableswitch"); + target = offset + jump; saved_operand[k + 1] = code_data[target]; } saved_operand[0] = keys + 1; /* number of successors */ @@ -1746,11 +1750,24 @@ static int instruction_length(unsigned char *iptr, unsigned char *end) /* Given the target of a branch, make sure that it's a legal target. */ static jboolean -isLegalTarget(context_type *context, int offset) +isLegalTarget(context_type *context, int target) { int code_length = context->code_length; int *code_data = context->code_data; - return (offset >= 0 && offset < code_length && code_data[offset] >= 0); + return (target >= 0 && target < code_length && code_data[target] >= 0); +} + +/* Given a bci and offset, make sure the offset is valid and the target is legal */ +static jboolean +isLegalOffset(context_type *context, int bci, int offset) +{ + int code_length = context->code_length; + int *code_data = context->code_data; + int max_offset = 65535; // JVMS 4.11 + int min_offset = -65535; + if (offset < min_offset || offset > max_offset) return JNI_FALSE; + int target = bci + offset; + return (target >= 0 && target < code_length && code_data[target] >= 0); } From d9dad578b87a258095468ee6ff8b0769bac0defc Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Thu, 26 Jun 2025 02:33:17 +0000 Subject: [PATCH 002/736] 8356294: Enhance Path Factories Reviewed-by: ahgross, rriggs, rhalade, lancea, naoto --- .../jaxp/DocumentBuilderFactoryImpl.java | 19 ++++++++++++++++--- .../xpath/internal/jaxp/XPathFactoryImpl.java | 10 ++++++---- .../apache/xpath/internal/jaxp/XPathImpl.java | 9 ++++++--- .../xpath/internal/jaxp/XPathImplUtil.java | 12 ++++++++++-- .../classes/jdk/xml/internal/JdkXmlUtils.java | 16 +++++++++++++++- .../jdk/xml/internal/XMLSecurityManager.java | 16 ++++++++++++++++ 6 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl.java index 385b8e29439..bc8e93b4f0b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl.java @@ -41,7 +41,7 @@ import org.xml.sax.SAXNotSupportedException; /** * @author Rajiv Mordani * @author Edwin Goei - * @LastModified: May 2025 + * @LastModified: June 2025 */ public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory { /** These are DocumentBuilderFactory attributes not DOM attributes */ @@ -59,11 +59,24 @@ public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory { XMLSecurityManager fSecurityManager; XMLSecurityPropertyManager fSecurityPropertyMgr; + /** + * Creates a new {@code DocumentBuilderFactory} instance. + */ public DocumentBuilderFactoryImpl() { + this(null, null); + } + + /** + * Creates a new {@code DocumentBuilderFactory} instance with a {@code XMLSecurityManager} + * and {@code XMLSecurityPropertyManager}. + * @param xsm the {@code XMLSecurityManager} + * @param xspm the {@code XMLSecurityPropertyManager} + */ + public DocumentBuilderFactoryImpl(XMLSecurityManager xsm, XMLSecurityPropertyManager xspm) { JdkXmlConfig config = JdkXmlConfig.getInstance(false); // security (property) managers updated with current system properties - fSecurityManager = config.getXMLSecurityManager(true); - fSecurityPropertyMgr = config.getXMLSecurityPropertyManager(true); + fSecurityManager = (xsm == null) ? config.getXMLSecurityManager(true) : xsm; + fSecurityPropertyMgr = (xspm == null) ? config.getXMLSecurityPropertyManager(true) : xspm; } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java index 1288f1dbac3..2f4d2ade545 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java @@ -35,7 +35,7 @@ import jdk.xml.internal.*; * * @author Ramesh Mandava * - * @LastModified: May 2025 + * @LastModified: June 2025 */ public class XPathFactoryImpl extends XPathFactory { @@ -72,6 +72,7 @@ public class XPathFactoryImpl extends XPathFactory { * The XML security manager */ private XMLSecurityManager _xmlSecMgr; + private XMLSecurityPropertyManager _xmlSecPropMgr; /** * javax.xml.xpath.XPathFactory implementation. @@ -80,6 +81,7 @@ public class XPathFactoryImpl extends XPathFactory { JdkXmlConfig config = JdkXmlConfig.getInstance(false); _xmlSecMgr = config.getXMLSecurityManager(true); _featureManager = config.getXMLFeatures(true); + _xmlSecPropMgr = config.getXMLSecurityPropertyManager(true); } /** @@ -129,7 +131,7 @@ public class XPathFactoryImpl extends XPathFactory { */ public javax.xml.xpath.XPath newXPath() { return new XPathImpl(xPathVariableResolver, xPathFunctionResolver, - !_isNotSecureProcessing, _featureManager, _xmlSecMgr); + !_isNotSecureProcessing, _featureManager, _xmlSecMgr, _xmlSecPropMgr); } /** @@ -183,6 +185,7 @@ public class XPathFactoryImpl extends XPathFactory { if (value && _featureManager != null) { _featureManager.setFeature(JdkXmlFeatures.XmlFeature.ENABLE_EXTENSION_FUNCTION, JdkProperty.State.FSP, false); + _xmlSecMgr.setSecureProcessing(value); } // all done processing feature @@ -338,8 +341,7 @@ public class XPathFactoryImpl extends XPathFactory { throw new NullPointerException(fmsg); } - if (_xmlSecMgr != null && - _xmlSecMgr.setLimit(name, JdkProperty.State.APIPROPERTY, value)) { + if (JdkXmlUtils.setProperty(_xmlSecMgr, _xmlSecPropMgr, name, value)) { return; } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java index 53099ad078e..c2faf90ce2e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java @@ -36,6 +36,7 @@ import javax.xml.xpath.XPathVariableResolver; import jdk.xml.internal.JdkXmlConfig; import jdk.xml.internal.JdkXmlFeatures; import jdk.xml.internal.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityPropertyManager; import org.w3c.dom.Document; import org.xml.sax.InputSource; @@ -50,7 +51,7 @@ import org.xml.sax.InputSource; * New methods: evaluateExpression * Refactored to share code with XPathExpressionImpl. * - * @LastModified: May 2025 + * @LastModified: June 2025 */ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { @@ -62,12 +63,13 @@ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr) { this(vr, fr, false, JdkXmlConfig.getInstance(false).getXMLFeatures(false), - JdkXmlConfig.getInstance(false).getXMLSecurityManager(false)); + JdkXmlConfig.getInstance(false).getXMLSecurityManager(false), + JdkXmlConfig.getInstance(false).getXMLSecurityPropertyManager(false)); } XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr, boolean featureSecureProcessing, JdkXmlFeatures featureManager, - XMLSecurityManager xmlSecMgr) { + XMLSecurityManager xmlSecMgr, XMLSecurityPropertyManager xmlSecPropMgr) { this.origVariableResolver = this.variableResolver = vr; this.origFunctionResolver = this.functionResolver = fr; this.featureSecureProcessing = featureSecureProcessing; @@ -75,6 +77,7 @@ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { overrideDefaultParser = featureManager.getFeature( JdkXmlFeatures.XmlFeature.JDK_OVERRIDE_PARSER); this.xmlSecMgr = xmlSecMgr; + this.xmlSecPropMgr = xmlSecPropMgr; } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java index a92090900fa..3de72f3f68b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java @@ -31,6 +31,7 @@ import com.sun.org.apache.xpath.internal.axes.LocPathIterator; import com.sun.org.apache.xpath.internal.objects.XObject; import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; import java.io.IOException; +import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -44,6 +45,7 @@ import javax.xml.xpath.XPathVariableResolver; import jdk.xml.internal.JdkXmlFeatures; import jdk.xml.internal.JdkXmlUtils; import jdk.xml.internal.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityPropertyManager; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.traversal.NodeIterator; @@ -54,7 +56,7 @@ import org.xml.sax.SAXException; * This class contains several utility methods used by XPathImpl and * XPathExpressionImpl * - * @LastModified: Apr 2025 + * @LastModified: June 2025 */ class XPathImplUtil { XPathFunctionResolver functionResolver; @@ -67,6 +69,7 @@ class XPathImplUtil { boolean featureSecureProcessing = false; JdkXmlFeatures featureManager; XMLSecurityManager xmlSecMgr; + XMLSecurityPropertyManager xmlSecPropMgr; /** * Evaluate an XPath context using the internal XPath engine @@ -128,7 +131,12 @@ class XPathImplUtil { // // so we really have to create a fresh DocumentBuilder every time we need one // - KK - DocumentBuilderFactory dbf = JdkXmlUtils.getDOMFactory(overrideDefaultParser); + DocumentBuilderFactory dbf = JdkXmlUtils.getDOMFactory( + overrideDefaultParser, xmlSecMgr, xmlSecPropMgr); + if (xmlSecMgr != null && xmlSecMgr.isSecureProcessingSet()) { + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, + xmlSecMgr.isSecureProcessing()); + } return dbf.newDocumentBuilder().parse(source); } catch (ParserConfigurationException | SAXException | IOException e) { throw new XPathExpressionException (e); 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 93b63a746f1..9e718b264e4 100644 --- a/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java +++ b/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java @@ -445,6 +445,20 @@ public class JdkXmlUtils { * @return a DocumentBuilderFactory instance. */ public static DocumentBuilderFactory getDOMFactory(boolean overrideDefaultParser) { + return getDOMFactory(overrideDefaultParser, null, null); + } + + /** + * {@return a DocumentBuilderFactory instance} + * + * @param overrideDefaultParser a flag indicating whether the system-default + * implementation may be overridden. If the system property of the + * DOM factory ID is set, override is always allowed. + * @param xsm XMLSecurityManager + * @param xspm XMLSecurityPropertyManager + */ + public static DocumentBuilderFactory getDOMFactory(boolean overrideDefaultParser, + XMLSecurityManager xsm, XMLSecurityPropertyManager xspm) { boolean override = overrideDefaultParser; String spDOMFactory = SecuritySupport.getJAXPSystemProperty(DOM_FACTORY_ID); @@ -453,7 +467,7 @@ public class JdkXmlUtils { } DocumentBuilderFactory dbf = !override - ? new DocumentBuilderFactoryImpl() + ? new DocumentBuilderFactoryImpl(xsm, xspm) : DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); // false is the default setting. This step here is for compatibility 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 5ca4073e20f..a1687c420c3 100644 --- a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java +++ b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java @@ -244,6 +244,12 @@ public final class XMLSecurityManager implements Cloneable { */ boolean secureProcessing; + /** + * Flag indicating the secure processing is set explicitly through factories' + * setFeature method and then the setSecureProcessing method + */ + boolean secureProcessingSet; + /** * States that determine if properties are set explicitly */ @@ -340,6 +346,7 @@ public final class XMLSecurityManager implements Cloneable { * Setting FEATURE_SECURE_PROCESSING explicitly */ public void setSecureProcessing(boolean secure) { + secureProcessingSet = true; secureProcessing = secure; for (Limit limit : Limit.values()) { if (secure) { @@ -358,6 +365,15 @@ public final class XMLSecurityManager implements Cloneable { return secureProcessing; } + /** + * Returns the state indicating whether the Secure Processing is set explicitly, + * via factories' setFeature and then this class' setSecureProcessing method. + * @return the state indicating whether the Secure Processing is set explicitly + */ + public boolean isSecureProcessingSet() { + return secureProcessingSet; + } + /** * Finds a limit's new name with the given property name. * @param propertyName the property name specified From c4485059149ab19882440659a0a167154d70c9a6 Mon Sep 17 00:00:00 2001 From: Raffaello Giulietti Date: Thu, 3 Jul 2025 13:57:01 +0000 Subject: [PATCH 003/736] 8359454: Enhance String handling Reviewed-by: rhalade, rriggs --- .../share/classes/java/lang/AbstractStringBuilder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index d317557cbb1..f1da102236a 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -1448,8 +1448,8 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence shift(currValue, coder, count, dstOffset, len); count += len; // Coder of CharSequence may be a mismatch, requiring the value array to be inflated - byte[] newValue = (s instanceof String str) - ? putStringAt(currValue, coder, count, dstOffset, str, start, end) + byte[] newValue = (s instanceof String str && str.length() == len) + ? putStringAt(currValue, coder, count, dstOffset, str) : putCharsAt(currValue, coder, count, dstOffset, s, start, end); if (currValue != newValue) { this.coder = UTF16; @@ -1928,10 +1928,10 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence * @param index the index to insert the string * @param str the string */ - private static byte[] putStringAt(byte[] value, byte coder, int count, int index, String str, int off, int end) { + private static byte[] putStringAt(byte[] value, byte coder, int count, int index, String str) { byte[] newValue = inflateIfNeededFor(value, count, coder, str.coder()); coder = (newValue == value) ? coder : UTF16; - str.getBytes(newValue, off, index, coder, end - off); + str.getBytes(newValue, 0, index, coder, str.length()); return newValue; } From e1d1fa91cf2670b171e64ad79b88f5d1ad3e51f7 Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Wed, 9 Jul 2025 19:31:30 +0000 Subject: [PATCH 004/736] 8360937: Enhance certificate handling Reviewed-by: ahgross, rhalade, jnibedita, ascarpino, naoto --- .../classes/sun/security/util/DerValue.java | 16 +++++++ .../share/classes/sun/security/x509/AVA.java | 48 +++++++++++++++++-- .../test/lib/security/CertificateBuilder.java | 23 +++++++-- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/sun/security/util/DerValue.java b/src/java.base/share/classes/sun/security/util/DerValue.java index 19e7083180b..ec8b482b07d 100644 --- a/src/java.base/share/classes/sun/security/util/DerValue.java +++ b/src/java.base/share/classes/sun/security/util/DerValue.java @@ -859,6 +859,22 @@ public class DerValue { return readStringInternal(tag_UniversalString, new UTF_32BE()); } + /** + * Checks that the BMPString does not contain any surrogate characters, + * which are outside the Basic Multilingual Plane. + * + * @throws IOException if illegal characters are detected + */ + public void validateBMPString() throws IOException { + String bmpString = getBMPString(); + for (int i = 0; i < bmpString.length(); i++) { + if (Character.isSurrogate(bmpString.charAt(i))) { + throw new IOException( + "Illegal character in BMPString, index: " + i); + } + } + } + /** * Reads the ASN.1 NULL value */ diff --git a/src/java.base/share/classes/sun/security/x509/AVA.java b/src/java.base/share/classes/sun/security/x509/AVA.java index 915421c76f2..214ae718288 100644 --- a/src/java.base/share/classes/sun/security/x509/AVA.java +++ b/src/java.base/share/classes/sun/security/x509/AVA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,10 +28,13 @@ package sun.security.x509; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Reader; +import java.nio.charset.Charset; import java.text.Normalizer; import java.util.*; +import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.charset.StandardCharsets.UTF_16BE; import sun.security.util.*; import sun.security.pkcs.PKCS9Attribute; @@ -589,6 +592,10 @@ public class AVA implements DerEncoder { throw new IOException("AVA, extra bytes = " + derval.data.available()); } + + if (value.tag == DerValue.tag_BMPString) { + value.validateBMPString(); + } } AVA(DerInputStream in) throws IOException { @@ -713,7 +720,8 @@ public class AVA implements DerEncoder { * NOTE: this implementation only emits DirectoryStrings of the * types returned by isDerString(). */ - String valStr = new String(value.getDataBytes(), UTF_8); + String valStr = + new String(value.getDataBytes(), getCharset(value, false)); /* * 2.4 (cont): If the UTF-8 string does not have any of the @@ -832,7 +840,8 @@ public class AVA implements DerEncoder { * NOTE: this implementation only emits DirectoryStrings of the * types returned by isDerString(). */ - String valStr = new String(value.getDataBytes(), UTF_8); + String valStr = + new String(value.getDataBytes(), getCharset(value, true)); /* * 2.4 (cont): If the UTF-8 string does not have any of the @@ -927,6 +936,39 @@ public class AVA implements DerEncoder { } } + /* + * Returns the charset that should be used to decode each DN string type. + * + * This method ensures that multi-byte (UTF8String and BMPString) types + * are decoded using the correct charset and the String forms represent + * the correct characters. For 8-bit ASCII-based types (PrintableString + * and IA5String), we return ISO_8859_1 rather than ASCII, so that the + * complete range of characters can be represented, as many certificates + * do not comply with the Internationalized Domain Name ACE format. + * + * NOTE: this method only supports DirectoryStrings of the types returned + * by isDerString(). + */ + private static Charset getCharset(DerValue value, boolean canonical) { + if (canonical) { + return switch (value.tag) { + case DerValue.tag_PrintableString -> ISO_8859_1; + case DerValue.tag_UTF8String -> UTF_8; + default -> throw new Error("unexpected tag: " + value.tag); + }; + } + + return switch (value.tag) { + case DerValue.tag_PrintableString, + DerValue.tag_T61String, + DerValue.tag_IA5String, + DerValue.tag_GeneralString -> ISO_8859_1; + case DerValue.tag_BMPString -> UTF_16BE; + case DerValue.tag_UTF8String -> UTF_8; + default -> throw new Error("unexpected tag: " + value.tag); + }; + } + boolean hasRFC2253Keyword() { return AVAKeyword.hasKeyword(oid, RFC2253); } diff --git a/test/lib/jdk/test/lib/security/CertificateBuilder.java b/test/lib/jdk/test/lib/security/CertificateBuilder.java index e5044d46b0f..d35a21e7ab5 100644 --- a/test/lib/jdk/test/lib/security/CertificateBuilder.java +++ b/test/lib/jdk/test/lib/security/CertificateBuilder.java @@ -53,6 +53,7 @@ import sun.security.x509.KeyUsageExtension; import sun.security.x509.SubjectAlternativeNameExtension; import sun.security.x509.URIName; import sun.security.x509.KeyIdentifier; +import sun.security.x509.X500Name; /** @@ -90,7 +91,7 @@ import sun.security.x509.KeyIdentifier; public class CertificateBuilder { private final CertificateFactory factory; - private X500Principal subjectName = null; + private X500Name subjectName = null; private BigInteger serialNumber = null; private PublicKey publicKey = null; private Date notBefore = null; @@ -199,7 +200,7 @@ public class CertificateBuilder { * on this certificate. */ public CertificateBuilder setSubjectName(X500Principal name) { - subjectName = name; + subjectName = X500Name.asX500Name(name); return this; } @@ -209,7 +210,23 @@ public class CertificateBuilder { * @param name The subject name in RFC 2253 format */ public CertificateBuilder setSubjectName(String name) { - subjectName = new X500Principal(name); + try { + subjectName = new X500Name(name); + } catch (IOException ioe) { + throw new IllegalArgumentException(ioe); + } + return this; + } + + /** + * Set the subject name for the certificate. This method is useful when + * you need more control over the contents of the subject name. + * + * @param name an {@code X500Name} to be used as the subject name + * on this certificate + */ + public CertificateBuilder setSubjectName(X500Name name) { + subjectName = name; return this; } From d55e1b4a11aec65e8dfcd163370c4d8b5800c26f Mon Sep 17 00:00:00 2001 From: Ana Maria Mihalceanu Date: Tue, 21 Oct 2025 16:46:50 +0000 Subject: [PATCH 005/736] 8370222: Wrong output for a command in jlink man page Reviewed-by: alanb --- src/jdk.jlink/share/man/jlink.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/jdk.jlink/share/man/jlink.md b/src/jdk.jlink/share/man/jlink.md index 74f2d119c69..dc256af43b5 100644 --- a/src/jdk.jlink/share/man/jlink.md +++ b/src/jdk.jlink/share/man/jlink.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -279,8 +279,6 @@ Suggested providers: java.smartcardio provides java.security.Provider used by java.base java.xml.crypto provides java.security.Provider used by java.base jdk.crypto.cryptoki provides java.security.Provider used by java.base - jdk.crypto.ec provides java.security.Provider used by java.base - jdk.crypto.mscapi provides java.security.Provider used by java.base jdk.security.jgss provides java.security.Provider used by java.base ``` From 43e036ba89dc8a09129313705f61354463d2c266 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 21 Oct 2025 19:00:51 +0000 Subject: [PATCH 006/736] 8366424: Missing type profiling in generated Record Object methods Reviewed-by: jvernee --- .../java/lang/runtime/ObjectMethods.java | 228 ++++++++++++++---- .../lang/runtime/RecordMethodsBenchmark.java | 171 +++++++++++++ 2 files changed, 349 insertions(+), 50 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/runtime/RecordMethodsBenchmark.java diff --git a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java index 24b55600954..18aa6f29f1f 100644 --- a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java +++ b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java @@ -25,18 +25,26 @@ package java.lang.runtime; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassHierarchyResolver; +import java.lang.classfile.Opcode; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.StringConcatFactory; import java.lang.invoke.TypeDescriptor; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Objects; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.*; import static java.util.Objects.requireNonNull; /** @@ -58,15 +66,18 @@ public final class ObjectMethods { private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true); private static final MethodHandle ZERO = MethodHandles.zero(int.class); private static final MethodHandle CLASS_IS_INSTANCE; - private static final MethodHandle OBJECTS_EQUALS; - private static final MethodHandle OBJECTS_HASHCODE; - private static final MethodHandle OBJECTS_TOSTRING; + private static final MethodHandle IS_NULL; + private static final MethodHandle IS_ARG0_NULL; + private static final MethodHandle IS_ARG1_NULL; private static final MethodHandle OBJECT_EQ; private static final MethodHandle HASH_COMBINER; + private static final MethodType MT_OBJECT_BOOLEAN = MethodType.methodType(boolean.class, Object.class); + private static final MethodType MT_INT = MethodType.methodType(int.class); + private static final MethodTypeDesc MTD_OBJECT_BOOLEAN = MethodTypeDesc.of(CD_boolean, CD_Object); + private static final MethodTypeDesc MTD_INT = MethodTypeDesc.of(CD_int); private static final HashMap, MethodHandle> primitiveEquals = new HashMap<>(); private static final HashMap, MethodHandle> primitiveHashers = new HashMap<>(); - private static final HashMap, MethodHandle> primitiveToString = new HashMap<>(); static { try { @@ -76,12 +87,12 @@ public final class ObjectMethods { CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance", MethodType.methodType(boolean.class, Object.class)); - OBJECTS_EQUALS = publicLookup.findStatic(Objects.class, "equals", - MethodType.methodType(boolean.class, Object.class, Object.class)); - OBJECTS_HASHCODE = publicLookup.findStatic(Objects.class, "hashCode", - MethodType.methodType(int.class, Object.class)); - OBJECTS_TOSTRING = publicLookup.findStatic(Objects.class, "toString", - MethodType.methodType(String.class, Object.class)); + + var objectsIsNull = publicLookup.findStatic(Objects.class, "isNull", + MethodType.methodType(boolean.class, Object.class)); + IS_NULL = objectsIsNull; + IS_ARG0_NULL = MethodHandles.dropArguments(objectsIsNull, 1, Object.class); + IS_ARG1_NULL = MethodHandles.dropArguments(objectsIsNull, 0, Object.class); OBJECT_EQ = lookup.findStatic(OBJECT_METHODS_CLASS, "eq", MethodType.methodType(boolean.class, Object.class, Object.class)); @@ -121,23 +132,6 @@ public final class ObjectMethods { MethodType.methodType(int.class, double.class))); primitiveHashers.put(boolean.class, lookup.findStatic(Boolean.class, "hashCode", MethodType.methodType(int.class, boolean.class))); - - primitiveToString.put(byte.class, lookup.findStatic(Byte.class, "toString", - MethodType.methodType(String.class, byte.class))); - primitiveToString.put(short.class, lookup.findStatic(Short.class, "toString", - MethodType.methodType(String.class, short.class))); - primitiveToString.put(char.class, lookup.findStatic(Character.class, "toString", - MethodType.methodType(String.class, char.class))); - primitiveToString.put(int.class, lookup.findStatic(Integer.class, "toString", - MethodType.methodType(String.class, int.class))); - primitiveToString.put(long.class, lookup.findStatic(Long.class, "toString", - MethodType.methodType(String.class, long.class))); - primitiveToString.put(float.class, lookup.findStatic(Float.class, "toString", - MethodType.methodType(String.class, float.class))); - primitiveToString.put(double.class, lookup.findStatic(Double.class, "toString", - MethodType.methodType(String.class, double.class))); - primitiveToString.put(boolean.class, lookup.findStatic(Boolean.class, "toString", - MethodType.methodType(String.class, boolean.class))); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); @@ -159,24 +153,41 @@ public final class ObjectMethods { private static boolean eq(boolean a, boolean b) { return a == b; } /** Get the method handle for combining two values of a given type */ - private static MethodHandle equalator(Class clazz) { - return (clazz.isPrimitive() - ? primitiveEquals.get(clazz) - : OBJECTS_EQUALS.asType(MethodType.methodType(boolean.class, clazz, clazz))); + private static MethodHandle equalator(MethodHandles.Lookup lookup, Class clazz) throws Throwable { + if (clazz.isPrimitive()) + return primitiveEquals.get(clazz); + MethodType mt = MethodType.methodType(boolean.class, clazz, clazz); + return MethodHandles.guardWithTest(IS_ARG0_NULL.asType(mt), + IS_ARG1_NULL.asType(mt), + lookup.findVirtual(clazz, "equals", MT_OBJECT_BOOLEAN).asType(mt)); } /** Get the hasher for a value of a given type */ - private static MethodHandle hasher(Class clazz) { - return (clazz.isPrimitive() - ? primitiveHashers.get(clazz) - : OBJECTS_HASHCODE.asType(MethodType.methodType(int.class, clazz))); + private static MethodHandle hasher(MethodHandles.Lookup lookup, Class clazz) throws Throwable { + if (clazz.isPrimitive()) + return primitiveHashers.get(clazz); + MethodType mt = MethodType.methodType(int.class, clazz); + return MethodHandles.guardWithTest(IS_NULL.asType(MethodType.methodType(boolean.class, clazz)), + MethodHandles.dropArguments(MethodHandles.zero(int.class), 0, clazz), + lookup.findVirtual(clazz, "hashCode", MT_INT).asType(mt)); } - /** Get the stringifier for a value of a given type */ - private static MethodHandle stringifier(Class clazz) { - return (clazz.isPrimitive() - ? primitiveToString.get(clazz) - : OBJECTS_TOSTRING.asType(MethodType.methodType(String.class, clazz))); + // If this type must be a monomorphic receiver, that is, one that has no + // subtypes in the JVM. For example, Object-typed fields may have a more + // specific one type at runtime and thus need optimizations. + private static boolean isMonomorphic(Class type) { + // Includes primitives and final classes, but not arrays. + // All array classes are reported to be final, but Object[] can have subtypes like String[] + return Modifier.isFinal(type.getModifiers()) && !type.isArray(); + } + + private static String specializerClassName(Class targetClass, String kind) { + String name = targetClass.getName(); + if (targetClass.isHidden()) { + // use the original class name + name = name.replace('/', '_'); + } + return name + "$$" + kind + "Specializer"; } /** @@ -185,8 +196,8 @@ public final class ObjectMethods { * @param getters the list of getters * @return the method handle */ - private static MethodHandle makeEquals(Class receiverClass, - List getters) { + private static MethodHandle makeEquals(MethodHandles.Lookup lookup, Class receiverClass, + List getters) throws Throwable { MethodType rr = MethodType.methodType(boolean.class, receiverClass, receiverClass); MethodType ro = MethodType.methodType(boolean.class, receiverClass, Object.class); MethodHandle instanceFalse = MethodHandles.dropArguments(FALSE, 0, receiverClass, Object.class); // (RO)Z @@ -195,8 +206,70 @@ public final class ObjectMethods { MethodHandle isInstance = MethodHandles.dropArguments(CLASS_IS_INSTANCE.bindTo(receiverClass), 0, receiverClass); // (RO)Z MethodHandle accumulator = MethodHandles.dropArguments(TRUE, 0, receiverClass, receiverClass); // (RR)Z - for (MethodHandle getter : getters) { - MethodHandle equalator = equalator(getter.type().returnType()); // (TT)Z + int size = getters.size(); + MethodHandle[] equalators = new MethodHandle[size]; + boolean hasPolymorphism = false; + for (int i = 0; i < size; i++) { + var getter = getters.get(i); + var type = getter.type().returnType(); + if (isMonomorphic(type)) { + equalators[i] = equalator(lookup, type); + } else { + hasPolymorphism = true; + } + } + + // Currently, hotspot does not support polymorphic inlining. + // As a result, if we have a MethodHandle to Object.equals, + // it does not enjoy separate profiles like individual invokevirtuals, + // and we must spin bytecode to accomplish separate profiling. + if (hasPolymorphism) { + String[] names = new String[size]; + + var classFileContext = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of(ClassHierarchyResolver.ofClassLoading(lookup))); + var bytes = classFileContext.build(ClassDesc.of(specializerClassName(lookup.lookupClass(), "Equalator")), clb -> { + for (int i = 0; i < size; i++) { + if (equalators[i] == null) { + var name = "equalator".concat(Integer.toString(i)); + names[i] = name; + var type = getters.get(i).type().returnType(); + boolean isInterface = type.isInterface(); + var typeDesc = type.describeConstable().orElseThrow(); + clb.withMethodBody(name, MethodTypeDesc.of(CD_boolean, typeDesc, typeDesc), ACC_STATIC, cob -> { + var nonNullPath = cob.newLabel(); + var fail = cob.newLabel(); + cob.aload(0) + .ifnonnull(nonNullPath) + .aload(1) + .ifnonnull(fail) + .iconst_1() // arg0 null, arg1 null + .ireturn() + .labelBinding(fail) + .iconst_0() // arg0 null, arg1 non-null + .ireturn() + .labelBinding(nonNullPath) + .aload(0) // arg0.equals(arg1) - bytecode subject to customized profiling + .aload(1) + .invoke(isInterface ? Opcode.INVOKEINTERFACE : Opcode.INVOKEVIRTUAL, typeDesc, "equals", MTD_OBJECT_BOOLEAN, isInterface) + .ireturn(); + }); + } + } + }); + + var specializerLookup = lookup.defineHiddenClass(bytes, true, MethodHandles.Lookup.ClassOption.STRONG); + + for (int i = 0; i < size; i++) { + if (equalators[i] == null) { + var type = getters.get(i).type().returnType(); + equalators[i] = specializerLookup.findStatic(specializerLookup.lookupClass(), names[i], MethodType.methodType(boolean.class, type, type)); + } + } + } + + for (int i = 0; i < size; i++) { + var getter = getters.get(i); + MethodHandle equalator = equalators[i]; // (TT)Z MethodHandle thisFieldEqual = MethodHandles.filterArguments(equalator, 0, getter, getter); // (RR)Z accumulator = MethodHandles.guardWithTest(thisFieldEqual, accumulator, instanceFalse.asType(rr)); } @@ -212,13 +285,68 @@ public final class ObjectMethods { * @param getters the list of getters * @return the method handle */ - private static MethodHandle makeHashCode(Class receiverClass, - List getters) { + private static MethodHandle makeHashCode(MethodHandles.Lookup lookup, Class receiverClass, + List getters) throws Throwable { MethodHandle accumulator = MethodHandles.dropArguments(ZERO, 0, receiverClass); // (R)I + int size = getters.size(); + MethodHandle[] hashers = new MethodHandle[size]; + boolean hasPolymorphism = false; + for (int i = 0; i < size; i++) { + var getter = getters.get(i); + var type = getter.type().returnType(); + if (isMonomorphic(type)) { + hashers[i] = hasher(lookup, type); + } else { + hasPolymorphism = true; + } + } + + // Currently, hotspot does not support polymorphic inlining. + // As a result, if we have a MethodHandle to Object.hashCode, + // it does not enjoy separate profiles like individual invokevirtuals, + // and we must spin bytecode to accomplish separate profiling. + if (hasPolymorphism) { + String[] names = new String[size]; + + var classFileContext = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of(ClassHierarchyResolver.ofClassLoading(lookup))); + var bytes = classFileContext.build(ClassDesc.of(specializerClassName(lookup.lookupClass(), "Hasher")), clb -> { + for (int i = 0; i < size; i++) { + if (hashers[i] == null) { + var name = "hasher".concat(Integer.toString(i)); + names[i] = name; + var type = getters.get(i).type().returnType(); + boolean isInterface = type.isInterface(); + var typeDesc = type.describeConstable().orElseThrow(); + clb.withMethodBody(name, MethodTypeDesc.of(CD_int, typeDesc), ACC_STATIC, cob -> { + var nonNullPath = cob.newLabel(); + cob.aload(0) + .ifnonnull(nonNullPath) + .iconst_0() // null hash is 0 + .ireturn() + .labelBinding(nonNullPath) + .aload(0) // arg0.hashCode() - bytecode subject to customized profiling + .invoke(isInterface ? Opcode.INVOKEINTERFACE : Opcode.INVOKEVIRTUAL, typeDesc, "hashCode", MTD_INT, isInterface) + .ireturn(); + }); + } + } + }); + + var specializerLookup = lookup.defineHiddenClass(bytes, true, MethodHandles.Lookup.ClassOption.STRONG); + + for (int i = 0; i < size; i++) { + if (hashers[i] == null) { + var type = getters.get(i).type().returnType(); + hashers[i] = specializerLookup.findStatic(specializerLookup.lookupClass(), names[i], MethodType.methodType(int.class, type)); + } + } + } + // @@@ Use loop combinator instead? - for (MethodHandle getter : getters) { - MethodHandle hasher = hasher(getter.type().returnType()); // (T)I + for (int i = 0; i < size; i++) { + var getter = getters.get(i); + MethodHandle hasher = hashers[i]; // (T)I MethodHandle hashThisField = MethodHandles.filterArguments(hasher, 0, getter); // (R)I MethodHandle combineHashes = MethodHandles.filterArguments(HASH_COMBINER, 0, accumulator, hashThisField); // (RR)I accumulator = MethodHandles.permuteArguments(combineHashes, accumulator.type(), 0, 0); // adapt (R)I to (RR)I @@ -403,12 +531,12 @@ public final class ObjectMethods { case "equals" -> { if (methodType != null && !methodType.equals(MethodType.methodType(boolean.class, recordClass, Object.class))) throw new IllegalArgumentException("Bad method type: " + methodType); - yield makeEquals(recordClass, getterList); + yield makeEquals(lookup, recordClass, getterList); } case "hashCode" -> { if (methodType != null && !methodType.equals(MethodType.methodType(int.class, recordClass))) throw new IllegalArgumentException("Bad method type: " + methodType); - yield makeHashCode(recordClass, getterList); + yield makeHashCode(lookup, recordClass, getterList); } case "toString" -> { if (methodType != null && !methodType.equals(MethodType.methodType(String.class, recordClass))) diff --git a/test/micro/org/openjdk/bench/java/lang/runtime/RecordMethodsBenchmark.java b/test/micro/org/openjdk/bench/java/lang/runtime/RecordMethodsBenchmark.java new file mode 100644 index 00000000000..91d26601383 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/runtime/RecordMethodsBenchmark.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang.runtime; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +/// Tests the generated equals and hashCode for records. +/// There are 4 types of methods: +/// - distinct: distinct sites for type profiling +/// - polluted: megamorphic site that blocks type profiling +/// - generated: actual body generated by ObjectMethods::bootstrap +/// - specialized: generated body for non-extensible types +/// The result of generated compared to the other distinct/polluted shows +/// whether the generated code could perform type profiling. +/// Specialized is the result of distinct without trap, should be even faster. +@Fork(3) +@Warmup(iterations = 10, time = 1) +@Measurement(iterations = 5, time = 2) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@BenchmarkMode(Mode.Throughput) +public class RecordMethodsBenchmark { + + record One(int a) {} + + @State(Scope.Thread) + public static class BenchmarkState { + Key k1 = new Key(new One(1), "a"); + Key k2 = new Key(new One(1), new String("a")); + SpecializedKey sk1 = new SpecializedKey(new One(1), "a"); + SpecializedKey sk2 = new SpecializedKey(new One(1), new String("a")); + } + + @Benchmark + public int hashCodeDistinct(BenchmarkState state) { + return state.k1.hashCodeDistinct(); + } + + @Benchmark + public int hashCodePolluted(BenchmarkState state) { + return state.k1.hashCodePolluted(); + } + + @Benchmark + public int hashCodeGenerated(BenchmarkState state) { + return state.k1.hashCode(); + } + + @Benchmark + public int hashCodeSpecial(BenchmarkState state) { + return state.sk1.hashCode(); + } + + @Benchmark + public boolean equalsDistinct(BenchmarkState state) { + return state.k1.equalsDistinct(state.k2); + } + + @Benchmark + public boolean equalsPolluted(BenchmarkState state) { + return state.k1.equalsPolluted(state.k2); + } + + @Benchmark + public boolean equalsGenerated(BenchmarkState state) { + return state.k1.equals(state.k2); + } + + @Benchmark + public boolean equalsSpecial(BenchmarkState state) { + return state.sk1.equals(state.sk2); + } + + /// A key object. + /// + /// Having both field as Object pollutes Object.equals for record object + /// method MH tree. We must verify the leaf Object.equals calls don't + /// share the same profile in generated code. + record Key(Object key1, Object key2) { + /// A hashCode method which has distinct hashCode invocations + /// in bytecode for each field for type profiling. + public int hashCodeDistinct() { + final int prime = 31; + int result = 1; + result = prime * result + ((key1 == null) ? 0 : key1.hashCode()); + result = prime * result + ((key2 == null) ? 0 : key2.hashCode()); + return result; + } + + /// A hashCode method which uses a megamorphic polluted + /// Object.hashCode virtual invocation in Objects.hashCode. + public int hashCodePolluted() { + final int prime = 31; + int result = 1; + result = prime * result + Objects.hashCode(key1); + result = prime * result + Objects.hashCode(key2); + return result; + } + + /// An equals method which has distinct equals invocations + /// in bytecode for each field for type profiling. + public boolean equalsDistinct(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Key other = (Key) obj; + if (key1 == null) { + if (other.key1 != null) + return false; + } + else if (!key1.equals(other.key1)) + return false; + if (key2 == null) { + if (other.key2 != null) + return false; + } + else if (!key2.equals(other.key2)) + return false; + return true; + } + + /// An equals method which uses a megamorphic polluted + /// Object.equals virtual invocation in Objects.equals. + public boolean equalsPolluted(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Key other = (Key) obj; + return Objects.equals(key1, other.key1) && Objects.equals(key2, other.key2); + } + } + + record SpecializedKey(One key1, String key2) {} +} From aab3fc54e6689dfa90ba097847a92d508c970be6 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 21 Oct 2025 20:49:53 +0000 Subject: [PATCH 007/736] 8370207: Test sun/misc/SunMiscSignalTest.java crashes after JDK-8369631 Reviewed-by: kbarrett, coleenp --- src/hotspot/os/posix/signals_posix.cpp | 8 ++++---- test/jdk/ProblemList.txt | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 10b340214a1..5833e324070 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -357,12 +357,12 @@ static void jdk_misc_signal_init() { } void os::signal_notify(int sig) { - // Signal thread is not created with ReduceSignalUsage and jdk_misc_signal_init - // initialization isn't called. This code is also never called. - assert(!ReduceSignalUsage, "Should not reach here if ReduceSignalUsage is set"); - + // Signal thread is not created with ReduceSignalUsage and jdk_misc_signal_init + // initialization isn't called. + if (!ReduceSignalUsage) { AtomicAccess::inc(&pending_signals[sig]); sig_semaphore->signal(); + } } static int check_pending_signals() { diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index faf4c5e7a94..0e69446ae35 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -743,8 +743,6 @@ sun/tools/jstatd/TestJstatdRmiPort.java 8251259,8293577 jdk/incubator/vector/ShortMaxVectorTests.java 8306592 generic-i586 jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows-x64 -sun/misc/SunMiscSignalTest.java 8370207 generic-all - ############################################################################ # jdk_jfr From cac2519fc6552b6187d6f94db1ed33d9186d95cf Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Tue, 21 Oct 2025 21:34:38 +0000 Subject: [PATCH 008/736] 8356578: Test --mac-entitlements Reviewed-by: asemenyuk --- .../jdk/jpackage/test/LauncherVerifier.java | 15 ++- .../jpackage/macosx/EntitlementsTest.java | 124 ++++++++++++++++++ 2 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 test/jdk/tools/jpackage/macosx/EntitlementsTest.java diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java index 87dc203daa1..55cb38f21cf 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java @@ -339,9 +339,20 @@ public final class LauncherVerifier { TKit.assertTrue(entitlements.isPresent(), String.format("Check [%s] launcher is signed with entitlements", name)); + var customFile = Optional.ofNullable(cmd.getArgumentValue("--mac-entitlements")).map(Path::of); + if (customFile.isEmpty()) { + // Try from the resource dir. + var resourceDirFile = Optional.ofNullable(cmd.getArgumentValue("--resource-dir")).map(Path::of).map(resourceDir -> { + return resourceDir.resolve(cmd.name() + ".entitlements"); + }).filter(Files::exists); + if (resourceDirFile.isPresent()) { + customFile = resourceDirFile; + } + } + Map expected; - if (cmd.hasArgument("--mac-entitlements")) { - expected = new PListReader(Files.readAllBytes(Path.of(cmd.getArgumentValue("--mac-entitlements")))).toMap(true); + if (customFile.isPresent()) { + expected = new PListReader(Files.readAllBytes(customFile.orElseThrow())).toMap(true); } else if (cmd.hasArgument("--mac-app-store")) { expected = DefaultEntitlements.APP_STORE; } else { diff --git a/test/jdk/tools/jpackage/macosx/EntitlementsTest.java b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java new file mode 100644 index 00000000000..1d6d86118a6 --- /dev/null +++ b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import static jdk.jpackage.internal.util.PListWriter.writeDict; +import static jdk.jpackage.internal.util.PListWriter.writePList; +import static jdk.jpackage.internal.util.PListWriter.writeBoolean; +import static jdk.jpackage.internal.util.XmlUtils.createXml; +import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Date; + +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.TKit; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Annotations.Parameter; + +/* + * Test generates signed app-image with custom entitlements file from the + * "--mac-entitlements" parameter and the resource directory. Following cases + * are covered: + * - Custom entitlements file in the resource directory. + * - Custom entitlements file specified with the "--mac-entitlements" parameter. + * - Custom entitlements file in the resource directory and specified with the + * "--mac-entitlements" parameter. + */ + +/* + * @test + * @summary jpackage with --type app-image "--mac-entitlements" parameter + * @library /test/jdk/tools/jpackage/helpers + * @library base + * @build SigningBase + * @build jdk.jpackage.test.* + * @build EntitlementsTest + * @requires (jpackage.test.MacSignTests == "run") + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=EntitlementsTest + * --jpt-before-run=SigningBase.verifySignTestEnvReady + */ +public class EntitlementsTest { + + void createEntitlementsFile(Path file, boolean microphone) throws IOException { + createXml(file, xml -> { + writePList(xml, toXmlConsumer(() -> { + writeDict(xml, toXmlConsumer(() -> { + writeBoolean(xml, "com.apple.security.cs.allow-jit", true); + writeBoolean(xml, "com.apple.security.cs.allow-unsigned-executable-memory", true); + writeBoolean(xml, "com.apple.security.cs.disable-library-validation", true); + writeBoolean(xml, "com.apple.security.cs.allow-dyld-environment-variables", true); + writeBoolean(xml, "com.apple.security.cs.debugger", true); + writeBoolean(xml, "com.apple.security.device.audio-input", true); + writeBoolean(xml, "com.apple.security.device.microphone", microphone); + })); + })); + }); + } + + @Test + // ({"--mac-app-store", doMacEntitlements", "doResources"}) + @Parameter({"false", "true", "false"}) + @Parameter({"false", "false", "true"}) + @Parameter({"false", "true", "true"}) + @Parameter({"true", "true", "false"}) + @Parameter({"true", "false", "true"}) + @Parameter({"true", "true", "true"}) + public void test(boolean appStore, boolean doMacEntitlements, boolean doResources) throws Exception { + final Path macEntitlementsFile; + final Path resourcesDir; + + if (doMacEntitlements) { + macEntitlementsFile = TKit.createTempFile("EntitlementsTest.plist"); + createEntitlementsFile(macEntitlementsFile, true); + } else { + macEntitlementsFile = null; + } + + if (doResources) { + resourcesDir = TKit.createTempDirectory("resources"); + createEntitlementsFile(resourcesDir.resolve("EntitlementsTest.entitlements"), false); + } else { + resourcesDir = null; + } + + JPackageCommand cmd = JPackageCommand.helloAppImage() + .addArguments("--mac-sign", "--mac-signing-keychain", + SigningBase.getKeyChain(), "--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.CertIndex.ASCII_INDEX.value())); + if (appStore) { + cmd.addArguments("--mac-app-store"); + } + if (doMacEntitlements) { + cmd.addArguments("--mac-entitlements", + macEntitlementsFile.toAbsolutePath().toString()); + } + if (doResources) { + cmd.addArguments("--resource-dir", + resourcesDir.toAbsolutePath().toString()); + } + + cmd.executeAndAssertHelloAppImageCreated(); + } +} From ed153ee2c4614c814da92c23c4741eed68ce1a0c Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 21 Oct 2025 22:10:01 +0000 Subject: [PATCH 009/736] 8369032: Add test to ensure serialized ICC_Profile stores only necessary optional data Reviewed-by: honkar --- .../color/ICC_Profile/SerializedFormSize.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 test/jdk/java/awt/color/ICC_Profile/SerializedFormSize.java diff --git a/test/jdk/java/awt/color/ICC_Profile/SerializedFormSize.java b/test/jdk/java/awt/color/ICC_Profile/SerializedFormSize.java new file mode 100644 index 00000000000..bb8d7a0ab88 --- /dev/null +++ b/test/jdk/java/awt/color/ICC_Profile/SerializedFormSize.java @@ -0,0 +1,72 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; + +/** + * @test + * @bug 8369032 + * @summary Checks the size of the serialized ICC_Profile for standard and + * non-standard profiles. + */ +public final class SerializedFormSize { + + private static final ICC_Profile[] PROFILES = { + ICC_Profile.getInstance(ColorSpace.CS_sRGB), + ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB), + ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ), + ICC_Profile.getInstance(ColorSpace.CS_PYCC), + ICC_Profile.getInstance(ColorSpace.CS_GRAY) + }; + + public static void main(String[] args) throws Exception { + for (ICC_Profile profile : PROFILES) { + byte[] data = profile.getData(); + int dataSize = data.length; + int min = 3; // At least version, name and data fields + int max = 200; // Small enough to confirm no data saved + + // Standard profile: should serialize to a small size, no data + test(profile, min, max); + // Non-standard profile: includes full data, but only once + test(ICC_Profile.getInstance(data), dataSize, dataSize + max); + } + } + + private static void test(ICC_Profile p, int min, int max) throws Exception { + try (var bos = new ByteArrayOutputStream(); + var oos = new ObjectOutputStream(bos)) + { + oos.writeObject(p); + int size = bos.size(); + if (size < min || size > max) { + System.err.println("Expected: >= " + min + " and <= " + max); + System.err.println("Actual: " + size); + throw new RuntimeException("Wrong size"); + } + } + } +} From 94c0611b9534f74b41b1f513f5c9ea96f41f83af Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Oct 2025 02:41:27 +0000 Subject: [PATCH 010/736] 8370122: jpackage test lib improvements Reviewed-by: almatvee --- .../internal/util/IdentityWrapper.java | 73 ++ .../jdk/jpackage/test/JUnitUtilsTest.java | 56 ++ .../jdk/jpackage/test/ObjectMapperTest.java | 731 ++++++++++++++++ .../jdk/jpackage/test/PackageTestTest.java | 2 +- .../jdk/jpackage/test/AdditionalLauncher.java | 2 +- .../jdk/jpackage/test/ApplicationLayout.java | 12 +- .../jpackage/test/ConfigurationTarget.java | 68 ++ .../helpers/jdk/jpackage/test/HelloApp.java | 2 + .../jdk/jpackage/test/JPackageCommand.java | 43 +- .../helpers/jdk/jpackage/test/JarBuilder.java | 21 +- .../jpackage/test/LauncherIconVerifier.java | 17 +- .../jdk/jpackage/test/LinuxHelper.java | 59 +- .../jdk/jpackage/test/ObjectMapper.java | 780 ++++++++++++++++++ .../jdk/jpackage/test/PackageTest.java | 20 +- .../helpers/jdk/jpackage/test/TKit.java | 4 +- .../internal/util/IdentityWrapperTest.java | 157 ++++ .../tools/jdk/jpackage/test/JUnitUtils.java | 139 ++++ .../jpackage/linux/ShortcutHintTest.java | 2 +- .../jpackage/share/AddLShortcutTest.java | 6 + .../tools/jpackage/share/AddLauncherTest.java | 73 +- .../jpackage/share/AppImagePackageTest.java | 102 ++- .../tools/jpackage/share/InOutPathTest.java | 4 +- .../jdk/tools/jpackage/share/LicenseTest.java | 2 +- .../jpackage/share/RuntimePackageTest.java | 6 +- 24 files changed, 2285 insertions(+), 96 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/IdentityWrapper.java create mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitUtilsTest.java create mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ObjectMapperTest.java create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ConfigurationTarget.java create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ObjectMapper.java create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/IdentityWrapperTest.java create mode 100644 test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/IdentityWrapper.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/IdentityWrapper.java new file mode 100644 index 00000000000..0a7a8cc8d4b --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/IdentityWrapper.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.util.Objects; + +/** + * Object wrapper implementing {@link Object#equals(Object)} such that it + * returns {@code true} only when the argument is another instance of this class + * wrapping the same object. + *

+ * The class guarantees that {@link Object#equals(Object)} and + * {@link Object#hashCode()} methods of the wrapped object will never be called + * inside of the class methods. + * + * @param the type of the wrapped value + */ +public final class IdentityWrapper { + + public IdentityWrapper(T value) { + this.value = Objects.requireNonNull(value); + } + + public T value() { + return value; + } + + @Override + public int hashCode() { + return System.identityHashCode(value); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if ((obj == null) || (getClass() != obj.getClass())) { + return false; + } + var other = (IdentityWrapper) obj; + return value == other.value; + } + + @Override + public String toString() { + return String.format("Identity[%s]", value); + } + + private final T value; +} diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitUtilsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitUtilsTest.java new file mode 100644 index 00000000000..28b55f98fe2 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitUtilsTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Map; +import org.junit.jupiter.api.Test; + +public class JUnitUtilsTest { + + @Test + public void test_assertArrayEquals() { + JUnitUtils.assertArrayEquals(new int[] {1, 2, 3}, new int[] {1, 2, 3}); + JUnitUtils.assertArrayEquals(new long[] {1, 2, 3}, new long[] {1, 2, 3}); + JUnitUtils.assertArrayEquals(new boolean[] {true, true}, new boolean[] {true, true}); + } + + @Test + public void test_assertArrayEquals_negative() { + assertThrows(AssertionError.class, () -> { + JUnitUtils.assertArrayEquals(new int[] {1, 2, 3}, new int[] {2, 3}); + }); + } + + @Test + public void test_exceptionAsPropertyMapWithMessageWithoutCause() { + + var ex = new Exception("foo"); + + var map = JUnitUtils.exceptionAsPropertyMap(ex); + + assertEquals(Map.of("getClass", Exception.class.getName(), "getMessage", "foo"), map); + } +} diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ObjectMapperTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ObjectMapperTest.java new file mode 100644 index 00000000000..0310d276e21 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ObjectMapperTest.java @@ -0,0 +1,731 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.math.BigInteger; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; +import org.junit.jupiter.api.Test; + +public class ObjectMapperTest { + + @Test + public void test_String() { + var om = ObjectMapper.blank().create(); + + var map = om.map("foo"); + + assertEquals("foo", map); + } + + @Test + public void test_int() { + var om = ObjectMapper.blank().create(); + + var map = om.map(100); + + assertEquals(100, map); + } + + @Test + public void test_null() { + var om = ObjectMapper.blank().create(); + + var map = om.map(null); + + assertNull(map); + } + + @Test + public void test_Object() { + var obj = new Object(); + assertSame(obj, ObjectMapper.blank().create().map(obj)); + assertSame(obj, ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_Path() { + var obj = Path.of("foo/bar"); + + assertSame(obj, ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_UUID() { + var obj = UUID.randomUUID(); + + assertSame(obj, ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_BigInteger() { + var obj = BigInteger.TEN; + + assertSame(obj, ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_Enum() { + + var expected = Map.of( + "name", TestEnum.BAR.name(), + "ordinal", TestEnum.BAR.ordinal(), + "a", "A", + "b", 123, + "num", 100 + ); + + assertEquals(expected, ObjectMapper.standard().create().map(TestEnum.BAR)); + } + + @Test + public void test_array_int() { + + var obj = new int[] { 1, 4, 5 }; + + assertSame(obj, ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_array_String() { + + var obj = new String[] { "Hello", "Bye" }; + + assertSame(obj, ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_array_empty() { + + var obj = new Thread[0]; + + assertSame(obj, ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_array_nulls() { + + var obj = new Thread[10]; + + assertSame(obj, ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_array_Path() { + + var obj = new Path[] { Path.of("foo/bar"), null, Path.of("").toAbsolutePath() }; + + assertSame(obj, ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_array_Object() { + + var obj = new Object[] { Path.of("foo/bar"), null, 145, new Simple.Stub("Hello", 738), "foo" }; + + var expected = new Object[] { Path.of("foo/bar"), null, 145, Map.of("a", "Hello", "b", 738), "foo" }; + + assertArrayEquals(expected, (Object[])ObjectMapper.standard().create().map(obj)); + } + + @Test + public void test_functional() { + assertWrappedIdentity(new Function() { + + @Override + public Integer apply(Object o) { + throw new AssertionError(); + } + + }); + + assertWrappedIdentity(new BiFunction() { + + @Override + public Integer apply(Object a, String b) { + throw new AssertionError(); + } + + }); + + assertWrappedIdentity(new Consumer<>() { + + @Override + public void accept(Object o) { + throw new AssertionError(); + } + + }); + + assertWrappedIdentity(new BiConsumer<>() { + + @Override + public void accept(Object a, Object b) { + throw new AssertionError(); + } + + }); + + assertWrappedIdentity(new Predicate<>() { + + @Override + public boolean test(Object o) { + throw new AssertionError(); + } + + }); + + assertWrappedIdentity(new Supplier<>() { + + @Override + public Object get() { + throw new AssertionError(); + } + + }); + + assertWrappedIdentity(new Runnable() { + + @Override + public void run() { + throw new AssertionError(); + } + + }); + } + + @Test + public void testIdentityWrapper() { + var om = ObjectMapper.standard().create(); + + var a = new Object() {}; + var b = new Object() {}; + + var amap = om.map(a); + var amap2 = om.map(a); + + assertEquals(amap, amap2); + assertEquals(ObjectMapper.wrapIdentity(a), amap); + + var bmap = om.map(b); + + assertNotEquals(amap, bmap); + assertEquals(ObjectMapper.wrapIdentity(b), bmap); + } + + @Test + public void test_wrapIdentity() { + + assertThrowsExactly(NullPointerException.class, () -> ObjectMapper.wrapIdentity(null)); + + var iw = ObjectMapper.wrapIdentity(new Object()); + + assertSame(iw, ObjectMapper.wrapIdentity(iw)); + + var simpleStubA = new Simple.Stub("Hello", 77); + var simpleStubB = new Simple.Stub("Hello", 77); + + assertEquals(simpleStubA, simpleStubB); + assertNotEquals(ObjectMapper.wrapIdentity(simpleStubA), ObjectMapper.wrapIdentity(simpleStubB)); + assertEquals(ObjectMapper.wrapIdentity(simpleStubA), ObjectMapper.wrapIdentity(simpleStubA)); + } + + @Test + public void test_empty_List() { + var om = ObjectMapper.blank().create(); + + var map = om.map(List.of()); + + assertEquals(List.of(), map); + } + + @Test + public void test_List() { + var om = ObjectMapper.blank().create(); + + var map = om.map(List.of(100, "foo")); + + assertEquals(List.of(100, "foo"), map); + } + + @Test + public void test_empty_Map() { + var om = ObjectMapper.blank().create(); + + var map = om.map(Map.of()); + + assertEquals(Map.of(), map); + } + + @Test + public void test_Map() { + var om = ObjectMapper.blank().create(); + + var map = om.map(Map.of(100, "foo")); + + assertEquals(Map.of(100, "foo"), map); + } + + @Test + public void test_MapSimple() { + var om = ObjectMapper.standard().create(); + + var map = om.map(Map.of(123, "foo", 321, new Simple.Stub("Hello", 567))); + + assertEquals(Map.of(123, "foo", 321, Map.of("a", "Hello", "b", 567)), map); + } + + @Test + public void test_ListSimple() { + var om = ObjectMapper.standard().create(); + + var map = om.map(List.of(100, new Simple.Stub("Hello", 567), "bar", new Simple() {})); + + assertEquals(List.of(100, Map.of("a", "Hello", "b", 567), "bar", Map.of("a", "foo", "b", 123)), map); + } + + @Test + public void test_Simple() { + var om = ObjectMapper.standard().create(); + + var map = om.map(new Simple() {}); + + assertEquals(Map.of("a", "foo", "b", 123), map); + } + + @Test + public void test_Proxy() { + var om = ObjectMapper.standard().create(); + + var map = om.map(Proxy.newProxyInstance(Simple.class.getClassLoader(), new Class[] { Simple.class }, new InvocationHandler() { + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + switch (method.getName()) { + case "a" -> { + return "Bye"; + } + case "b" -> { + return 335; + } + default -> { + throw new UnsupportedOperationException(); + } + } + } + + })); + + assertEquals(Map.of("a", "Bye", "b", 335), map); + } + + @Test + public void test_Simple_null_property() { + var om = ObjectMapper.standard().create(); + + var map = om.map(new Simple.Stub(null, 123)); + + assertEquals(Map.of("b", 123, "a", ObjectMapper.NULL), map); + } + + @Test + public void test_Optional_String() { + var om = ObjectMapper.standard().create(); + + var map = om.map(Optional.of("foo")); + + assertEquals(Map.of("get", "foo"), map); + } + + @Test + public void test_Optional_empty() { + var om = ObjectMapper.standard().create(); + + var map = om.map(Optional.empty()); + + assertEquals(Map.of("get", ObjectMapper.NULL), map); + } + + @Test + public void test_toMap() { + var om = ObjectMapper.standard().create(); + + assertNull(om.toMap(null)); + assertEquals(Map.of("value", "Hello"), om.toMap("Hello")); + assertEquals(Map.of("a", "foo", "b", 123), om.toMap(new Simple() {})); + } + + @Test + public void test_getter_throws() { + var om = ObjectMapper.blank() + .mutate(ObjectMapper.configureObject()) + .mutate(ObjectMapper.configureLeafClasses()) + .mutate(ObjectMapper.configureException()) + .create(); + + var expected = Map.of("get", om.toMap(new UnsupportedOperationException("Not for you!"))); + + var actual = om.toMap(new Supplier<>() { + @Override + public Object get() { + throw new UnsupportedOperationException("Not for you!"); + } + }); + + assertEquals(expected, actual); + } + + @Test + public void test_exception_with_message_with_cause() { + + var ex = new Exception("foo", new IllegalArgumentException("Cause", new RuntimeException("Ops!"))); + + var om = ObjectMapper.standard().create(); + + var map = om.toMap(ex); + + assertEquals(Map.of( + "getClass", Exception.class.getName(), + "getMessage", "foo", + "getCause", Map.of( + "getClass", IllegalArgumentException.class.getName(), + "getMessage", "Cause", + "getCause", Map.of( + "getClass", RuntimeException.class.getName(), + "getMessage", "Ops!" + ) + ) + ), map); + } + + @Test + public void test_exception_without_message_with_cause() { + + var ex = new RuntimeException(null, new UnknownError("Ops!")); + + var om = ObjectMapper.standard().create(); + + var map = om.toMap(ex); + + assertEquals(Map.of( + "getClass", RuntimeException.class.getName(), + "getCause", Map.of( + "getMessage", "Ops!", + "getCause", ObjectMapper.NULL + ) + ), map); + } + + @Test + public void test_exception_without_message_without_cause() { + + var ex = new UnsupportedOperationException(); + + var om = ObjectMapper.standard().create(); + + var map = om.toMap(ex); + + assertEquals(Map.of("getClass", UnsupportedOperationException.class.getName()), map); + } + + @Test + public void test_exception_CustomException() { + + var ex = new CustomException("Hello", Path.of(""), Optional.empty(), null); + + var om = ObjectMapper.standard().create(); + + var map = om.toMap(ex); + + assertEquals(Map.of( + "getClass", CustomException.class.getName(), + "getMessage", "Hello", + "op", Map.of("get", ObjectMapper.NULL), + "path2", Path.of("") + ), map); + } + + @Test + public void test_Builder_accessPackageMethods() { + + var obj = new TestType().foo("Hello").bar(81); + + var map = ObjectMapper.standard().create().toMap(obj); + + assertEquals(Map.of("foo", "Hello"), map); + + map = ObjectMapper.standard().accessPackageMethods(TestType.class.getPackage()).create().toMap(obj); + + assertEquals(Map.of("foo", "Hello", "bar", 81), map); + } + + @Test + public void test_Builder_methods_Simple() { + + var om = ObjectMapper.standard().exceptSomeMethods(Simple.class).add("a").apply().create(); + + assertEquals(Map.of("b", 123), om.toMap(new Simple() {})); + assertEquals(Map.of("b", 345), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("b", 123), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("b", 345 + 10), om.toMap(new Simple.DefaultExt("Hello", 345))); + + om = ObjectMapper.standard().exceptSomeMethods(Simple.class).add("b").apply().create(); + + assertEquals(Map.of("a", "foo"), om.toMap(new Simple() {})); + assertEquals(Map.of("a", "Hello"), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("a", "Hello"), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("a", "[Hello]"), om.toMap(new Simple.DefaultExt("Hello", 345))); + } + + @Test + public void test_Builder_methods_SimpleStub() { + + var om = ObjectMapper.standard().exceptSomeMethods(Simple.Stub.class).add("a").apply().create(); + + assertEquals(Map.of("a", "foo", "b", 123), om.toMap(new Simple() {})); + assertEquals(Map.of("b", 345), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("a", "Hello", "b", 123), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("a", "[Hello]", "b", 345 + 10), om.toMap(new Simple.DefaultExt("Hello", 345))); + + om = ObjectMapper.standard().exceptSomeMethods(Simple.Stub.class).add("b").apply().create(); + + assertEquals(Map.of("a", "foo", "b", 123), om.toMap(new Simple() {})); + assertEquals(Map.of("a", "Hello"), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("a", "Hello", "b", 123), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("a", "[Hello]", "b", 345 + 10), om.toMap(new Simple.DefaultExt("Hello", 345))); + } + + @Test + public void test_Builder_methods_SimpleDefault() { + + var om = ObjectMapper.standard().exceptSomeMethods(Simple.Default.class).add("a").apply().create(); + + assertEquals(Map.of("a", "foo", "b", 123), om.toMap(new Simple() {})); + assertEquals(Map.of("a", "Hello", "b", 345), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("b", 123), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("b", 345 + 10), om.toMap(new Simple.DefaultExt("Hello", 345))); + + om = ObjectMapper.standard().exceptSomeMethods(Simple.Default.class).add("b").apply().create(); + + assertEquals(Map.of("a", "foo"), om.toMap(new Simple() {})); + assertEquals(Map.of("a", "Hello"), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("a", "Hello"), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("a", "[Hello]"), om.toMap(new Simple.DefaultExt("Hello", 345))); + } + + @Test + public void test_Builder_methods_SimpleDefaultExt() { + + var om = ObjectMapper.standard().exceptSomeMethods(Simple.DefaultExt.class).add("a").apply().create(); + + assertEquals(Map.of("a", "foo", "b", 123), om.toMap(new Simple() {})); + assertEquals(Map.of("a", "Hello", "b", 345), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("a", "Hello", "b", 123), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("b", 345 + 10), om.toMap(new Simple.DefaultExt("Hello", 345))); + + om = ObjectMapper.standard().exceptSomeMethods(Simple.DefaultExt.class).add("b").apply().create(); + + assertEquals(Map.of("a", "foo", "b", 123), om.toMap(new Simple() {})); + assertEquals(Map.of("a", "Hello", "b", 345), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("a", "Hello", "b", 123), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("a", "[Hello]"), om.toMap(new Simple.DefaultExt("Hello", 345))); + } + + @Test + public void test_Builder_methods_SimpleStub_and_SimpleDefault() { + + var om = ObjectMapper.standard() + .exceptSomeMethods(Simple.Stub.class).add("a").apply() + .exceptSomeMethods(Simple.Default.class).add("a").apply() + .create(); + + assertEquals(Map.of("a", "foo", "b", 123), om.toMap(new Simple() {})); + assertEquals(Map.of("b", 345), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("b", 123), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("b", 345 + 10), om.toMap(new Simple.DefaultExt("Hello", 345))); + + om = ObjectMapper.standard() + .exceptSomeMethods(Simple.Stub.class).add("b").apply() + .exceptSomeMethods(Simple.Default.class).add("b").apply() + .create(); + + assertEquals(Map.of("a", "foo"), om.toMap(new Simple() {})); + assertEquals(Map.of("a", "Hello"), om.toMap(new Simple.Stub("Hello", 345))); + assertEquals(Map.of("a", "Hello"), om.toMap(new Simple.Default("Hello"))); + assertEquals(Map.of("a", "[Hello]"), om.toMap(new Simple.DefaultExt("Hello", 345))); + } + + @Test + public void test_Builder_methods_all_excluded() { + + var om = ObjectMapper.standard() + .exceptSomeMethods(Simple.class).add("a").apply() + .exceptSomeMethods(Simple.Stub.class).add("b").apply() + .create(); + + var obj = new Simple.Stub("Hello", 345); + + assertEquals(ObjectMapper.wrapIdentity(obj), om.map(obj)); + } + + interface Simple { + default String a() { + return "foo"; + } + + default int b() { + return 123; + } + + record Stub(String a, int b) implements Simple {} + + static class Default implements Simple { + Default(String a) { + this.a = a; + } + + @Override + public String a() { + return a; + } + + private final String a; + } + + static class DefaultExt extends Default { + DefaultExt(String a, int b) { + super(a); + this.b = b; + } + + @Override + public String a() { + return "[" + super.a() + "]"; + } + + @Override + public int b() { + return 10 + b; + } + + private final int b; + } + } + + final class TestType { + + public String foo() { + return foo; + } + + public TestType foo(String v) { + foo = v; + return this; + } + + int bar() { + return bar; + } + + TestType bar(int v) { + bar = v; + return this; + } + + private String foo; + private int bar; + } + + enum TestEnum implements Simple { + FOO, + BAR; + + public int num() { + return 100; + } + + public int num(int v) { + return v; + } + + @Override + public String a() { + return "A"; + } + } + + static final class CustomException extends Exception { + + CustomException(String message, Path path, Optional optional, Throwable cause) { + super(message, cause); + this.path = path; + this.optional = optional; + } + + Path path() { + return path; + } + + public Path path2() { + return path; + } + + public Optional op() { + return optional; + } + + private final Path path; + private final Optional optional; + + private static final long serialVersionUID = 1L; + + } + + private static void assertWrappedIdentity(ObjectMapper om, Object obj) { + var map = om.toMap(obj); + assertEquals(Map.of("value", ObjectMapper.wrapIdentity(obj)), map); + } + + private static void assertWrappedIdentity(Object obj) { + assertWrappedIdentity(ObjectMapper.standard().create(), obj); + } +} diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java index da94db30925..4cf89fca3cc 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java @@ -341,7 +341,7 @@ public class PackageTestTest extends JUnitAdapter { } @Override - JPackageCommand assertAppLayout() { + JPackageCommand runStandardAsserts() { return this; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index 50222d89ceb..66da89fc3f9 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -198,7 +198,7 @@ public final class AdditionalLauncher { } } - static PropertyFile getAdditionalLauncherProperties( + public static PropertyFile getAdditionalLauncherProperties( JPackageCommand cmd, String launcherName) { PropertyFile shell[] = new PropertyFile[1]; forEachAdditionalLauncher(cmd, (name, propertiesFilePath) -> { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java index 7ab3b824aa4..0701421e999 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java @@ -98,12 +98,18 @@ public record ApplicationLayout(Path launchersDirectory, Path appDirectory, throw new IllegalArgumentException("Unknown platform"); } - public static ApplicationLayout javaRuntime() { + public static ApplicationLayout platformJavaRuntime() { + Path runtime = Path.of(""); + Path runtimeHome = runtime; + if (TKit.isOSX()) { + runtimeHome = Path.of("Contents/Home"); + } + return new ApplicationLayout( null, null, - Path.of(""), - null, + runtime, + runtimeHome, null, null, null, diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ConfigurationTarget.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ConfigurationTarget.java new file mode 100644 index 00000000000..ba3131a7680 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ConfigurationTarget.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; + +/** + * Provides uniform way to configure {@code JPackageCommand} and + * {@code PackageTest} instances. + */ +public record ConfigurationTarget(Optional cmd, Optional test) { + + public ConfigurationTarget { + Objects.requireNonNull(cmd); + Objects.requireNonNull(test); + if (cmd.isEmpty() == test.isEmpty()) { + throw new IllegalArgumentException(); + } + } + + public ConfigurationTarget(JPackageCommand target) { + this(Optional.of(target), Optional.empty()); + } + + public ConfigurationTarget(PackageTest target) { + this(Optional.empty(), Optional.of(target)); + } + + public ConfigurationTarget apply(Consumer a, Consumer b) { + cmd.ifPresent(Objects.requireNonNull(a)); + test.ifPresent(Objects.requireNonNull(b)); + return this; + } + + public ConfigurationTarget addInitializer(Consumer initializer) { + cmd.ifPresent(Objects.requireNonNull(initializer)); + test.ifPresent(v -> { + v.addInitializer(initializer::accept); + }); + return this; + } + + public ConfigurationTarget add(AdditionalLauncher addLauncher) { + return apply(addLauncher::applyTo, addLauncher::applyTo); + } +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 69ea4ecfaa0..6c7b6a25255 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -125,6 +125,8 @@ public final class HelloApp { if (appDesc.isWithMainClass()) { builder.setMainClass(appDesc.className()); } + // Use an old release number to make test app classes runnable on older runtimes. + builder.setRelease(11); return builder; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 6945cd2b722..22e75a57911 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -67,9 +67,11 @@ import jdk.jpackage.internal.util.function.ThrowingSupplier; */ public class JPackageCommand extends CommandArguments { + @SuppressWarnings("this-escape") public JPackageCommand() { prerequisiteActions = new Actions(); verifyActions = new Actions(); + excludeStandardAsserts(StandardAssert.MAIN_LAUNCHER_DESCRIPTION); } private JPackageCommand(JPackageCommand cmd, boolean immutable) { @@ -85,7 +87,7 @@ public class JPackageCommand extends CommandArguments { dmgInstallDir = cmd.dmgInstallDir; prerequisiteActions = new Actions(cmd.prerequisiteActions); verifyActions = new Actions(cmd.verifyActions); - appLayoutAsserts = cmd.appLayoutAsserts; + standardAsserts = cmd.standardAsserts; readOnlyPathAsserts = cmd.readOnlyPathAsserts; outputValidators = cmd.outputValidators; executeInDirectory = cmd.executeInDirectory; @@ -459,7 +461,7 @@ public class JPackageCommand extends CommandArguments { if (layout != null) { } else if (isRuntime()) { - layout = ApplicationLayout.javaRuntime(); + layout = ApplicationLayout.platformJavaRuntime(); } else { layout = ApplicationLayout.platformAppImage(); } @@ -933,7 +935,7 @@ public class JPackageCommand extends CommandArguments { public JPackageCommand assertImageCreated() { verifyIsOfType(PackageType.IMAGE); - assertAppLayout(); + runStandardAsserts(); return this; } @@ -976,10 +978,10 @@ public class JPackageCommand extends CommandArguments { void updateAndAssert() { final var newSnapshots = createSnapshots(); for (final var a : asserts.keySet().stream().sorted().toList()) { - final var snapshopGroup = snapshots.get(a); - final var newSnapshopGroup = newSnapshots.get(a); - for (int i = 0; i < snapshopGroup.size(); i++) { - TKit.PathSnapshot.assertEquals(snapshopGroup.get(i), newSnapshopGroup.get(i), + final var snapshotGroup = snapshots.get(a); + final var newSnapshotGroup = newSnapshots.get(a); + for (int i = 0; i < snapshotGroup.size(); i++) { + snapshotGroup.get(i).assertEquals(newSnapshotGroup.get(i), String.format("Check jpackage didn't modify ${%s}=[%s]", a, asserts.get(a).get(i))); } } @@ -1094,7 +1096,7 @@ public class JPackageCommand extends CommandArguments { asSet::contains)).toArray(ReadOnlyPathAssert[]::new)); } - public static enum AppLayoutAssert { + public static enum StandardAssert { APP_IMAGE_FILE(JPackageCommand::assertAppImageFile), PACKAGE_FILE(JPackageCommand::assertPackageFile), NO_MAIN_LAUNCHER_IN_RUNTIME(cmd -> { @@ -1114,6 +1116,11 @@ public class JPackageCommand extends CommandArguments { LauncherVerifier.Action.VERIFY_MAC_ENTITLEMENTS); } }), + MAIN_LAUNCHER_DESCRIPTION(cmd -> { + if (!cmd.isRuntime()) { + new LauncherVerifier(cmd).verify(cmd, LauncherVerifier.Action.VERIFY_DESCRIPTION); + } + }), MAIN_JAR_FILE(cmd -> { Optional.ofNullable(cmd.getArgumentValue("--main-jar", () -> null)).ifPresent(mainJar -> { TKit.assertFileExists(cmd.appLayout().appDirectory().resolve(mainJar)); @@ -1138,7 +1145,7 @@ public class JPackageCommand extends CommandArguments { }), ; - AppLayoutAssert(Consumer action) { + StandardAssert(Consumer action) { this.action = action; } @@ -1156,21 +1163,21 @@ public class JPackageCommand extends CommandArguments { private final Consumer action; } - public JPackageCommand setAppLayoutAsserts(AppLayoutAssert ... asserts) { + public JPackageCommand setStandardAsserts(StandardAssert ... asserts) { verifyMutable(); - appLayoutAsserts = Set.of(asserts); + standardAsserts = Set.of(asserts); return this; } - public JPackageCommand excludeAppLayoutAsserts(AppLayoutAssert... asserts) { + public JPackageCommand excludeStandardAsserts(StandardAssert... asserts) { var asSet = Set.of(asserts); - return setAppLayoutAsserts(appLayoutAsserts.stream().filter(Predicate.not( - asSet::contains)).toArray(AppLayoutAssert[]::new)); + return setStandardAsserts(standardAsserts.stream().filter(Predicate.not( + asSet::contains)).toArray(StandardAssert[]::new)); } - JPackageCommand assertAppLayout() { - for (var appLayoutAssert : appLayoutAsserts.stream().sorted().toList()) { - appLayoutAssert.action.accept(this); + JPackageCommand runStandardAsserts() { + for (var standardAssert : standardAsserts.stream().sorted().toList()) { + standardAssert.action.accept(this); } return this; } @@ -1520,7 +1527,7 @@ public class JPackageCommand extends CommandArguments { private Path winMsiLogFile; private Path unpackedPackageDirectory; private Set readOnlyPathAsserts = Set.of(ReadOnlyPathAssert.values()); - private Set appLayoutAsserts = Set.of(AppLayoutAssert.values()); + private Set standardAsserts = Set.of(StandardAssert.values()); private List>> outputValidators = new ArrayList<>(); private static InheritableThreadLocal> defaultToolProvider = new InheritableThreadLocal<>() { @Override diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JarBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JarBuilder.java index d62575d2fef..c69c29af53a 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JarBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JarBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** @@ -48,6 +49,11 @@ public final class JarBuilder { return this; } + public JarBuilder setRelease(int v) { + release = v; + return this; + } + public JarBuilder addSourceFile(Path v) { sourceFiles.add(v); return this; @@ -61,11 +67,15 @@ public final class JarBuilder { public void create() { TKit.withTempDirectory("jar-workdir", workDir -> { if (!sourceFiles.isEmpty()) { - new Executor() + var exec = new Executor() .setToolProvider(JavaTool.JAVAC) - .addArguments("-d", workDir.toString()) - .addPathArguments(sourceFiles) - .execute(); + .addArguments("-d", workDir.toString()); + + Optional.ofNullable(release).ifPresent(r -> { + exec.addArguments("--release", r.toString()); + }); + + exec.addPathArguments(sourceFiles).execute(); } Files.createDirectories(outputJar.getParent()); @@ -92,4 +102,5 @@ public final class JarBuilder { private Path outputJar; private String mainClass; private String moduleVersion; + private Integer release; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java index 278cd569bac..79652a9828e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java @@ -25,6 +25,7 @@ package jdk.jpackage.test; import java.io.IOException; import java.nio.file.Path; +import java.util.Optional; public final class LauncherIconVerifier { public LauncherIconVerifier() { @@ -37,19 +38,33 @@ public final class LauncherIconVerifier { public LauncherIconVerifier setExpectedIcon(Path v) { expectedIcon = v; + expectedDefault = false; return this; } public LauncherIconVerifier setExpectedDefaultIcon() { + expectedIcon = null; expectedDefault = true; return this; } + public LauncherIconVerifier setExpectedNoIcon() { + return setExpectedIcon(null); + } + public LauncherIconVerifier verifyFileInAppImageOnly(boolean v) { verifyFileInAppImageOnly = true; return this; } + public boolean expectDefaultIcon() { + return expectedDefault; + } + + public Optional expectIcon() { + return Optional.ofNullable(expectedIcon); + } + public void applyTo(JPackageCommand cmd) throws IOException { final String curLauncherName; final String label; @@ -70,7 +85,7 @@ public final class LauncherIconVerifier { WinExecutableIconVerifier.verifyLauncherIcon(cmd, launcherName, expectedIcon, expectedDefault); } } else if (expectedDefault) { - TKit.assertPathExists(iconPath, true); + TKit.assertFileExists(iconPath); } else if (expectedIcon == null) { TKit.assertPathExists(iconPath, false); } else { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 3a27ae32f43..9776ab5c4c8 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -22,7 +22,11 @@ */ package jdk.jpackage.test; +import static jdk.jpackage.test.AdditionalLauncher.getAdditionalLauncherProperties; import static java.util.Collections.unmodifiableSortedSet; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; import java.io.IOException; import java.io.UncheckedIOException; @@ -45,7 +49,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; @@ -164,8 +167,7 @@ public final class LinuxHelper { switch (packageType) { case LINUX_DEB: return Stream.of(getDebBundleProperty(cmd.outputBundle(), - "Depends").split(",")).map(String::strip).collect( - Collectors.toList()); + "Depends").split(",")).map(String::strip).toList(); case LINUX_RPM: return Executor.of("rpm", "-qp", "-R") @@ -326,10 +328,9 @@ public final class LinuxHelper { if (cmd.isRuntime()) { Path runtimeDir = cmd.appRuntimeDirectory(); Set expectedCriticalRuntimePaths = CRITICAL_RUNTIME_FILES.stream().map( - runtimeDir::resolve).collect(Collectors.toSet()); + runtimeDir::resolve).collect(toSet()); Set actualCriticalRuntimePaths = getPackageFiles(cmd).filter( - expectedCriticalRuntimePaths::contains).collect( - Collectors.toSet()); + expectedCriticalRuntimePaths::contains).collect(toSet()); checkPrerequisites = expectedCriticalRuntimePaths.equals( actualCriticalRuntimePaths); } else { @@ -375,8 +376,7 @@ public final class LinuxHelper { Function, String> verifier = (lines) -> { // Lookup for xdg commands return lines.stream().filter(line -> { - Set words = Stream.of(line.split("\\s+")).collect( - Collectors.toSet()); + Set words = Stream.of(line.split("\\s+")).collect(toSet()); return words.contains("xdg-desktop-menu") || words.contains( "xdg-mime") || words.contains("xdg-icon-resource"); }).findFirst().orElse(null); @@ -454,11 +454,29 @@ public final class LinuxHelper { } private static Collection getDesktopFiles(JPackageCommand cmd) { + var unpackedDir = cmd.appLayout().desktopIntegrationDirectory(); + + return relativePackageFilesInSubdirectory(cmd, ApplicationLayout::desktopIntegrationDirectory) + .filter(path -> { + return path.getNameCount() == 1; + }) + .filter(path -> { + return ".desktop".equals(PathUtils.getSuffix(path)); + }) + .map(unpackedDir::resolve) + .toList(); + } + + private static Stream relativePackageFilesInSubdirectory( + JPackageCommand cmd, Function subdirFunc) { + + var unpackedDir = subdirFunc.apply(cmd.appLayout()); var packageDir = cmd.pathToPackageFile(unpackedDir); + return getPackageFiles(cmd).filter(path -> { - return packageDir.equals(path.getParent()) && path.getFileName().toString().endsWith(".desktop"); - }).map(Path::getFileName).map(unpackedDir::resolve).toList(); + return path.startsWith(packageDir); + }).map(packageDir::relativize); } private static String launcherNameFromDesktopFile(JPackageCommand cmd, Optional predefinedAppImage, Path desktopFile) { @@ -496,7 +514,20 @@ public final class LinuxHelper { TKit.assertTrue(mandatoryKeys.isEmpty(), String.format( "Check for missing %s keys in the file", mandatoryKeys)); - for (var e : List.of(Map.entry("Type", "Application"), Map.entry("Terminal", "false"))) { + final String launcherDescription; + if (cmd.name().equals(launcherName) || predefinedAppImage.isPresent()) { + launcherDescription = Optional.ofNullable(cmd.getArgumentValue("--description")).orElseGet(cmd::name); + } else { + launcherDescription = getAdditionalLauncherProperties(cmd, launcherName).findProperty("description").or(() -> { + return Optional.ofNullable(cmd.getArgumentValue("--description")); + }).orElseGet(cmd::name); + } + + for (var e : List.of( + Map.entry("Type", "Application"), + Map.entry("Terminal", "false"), + Map.entry("Comment", launcherDescription) + )) { String key = e.getKey(); TKit.assertEquals(e.getValue(), data.find(key).orElseThrow(), String.format( "Check value of [%s] key", key)); @@ -768,10 +799,10 @@ public final class LinuxHelper { static final Pattern RPM_HEADER_PATTERN = Pattern.compile(String.format( "(%s) scriptlet \\(using /bin/sh\\):", Stream.of(values()).map( - v -> v.rpm).collect(Collectors.joining("|")))); + v -> v.rpm).collect(joining("|")))); static final Map RPM_MAP = Stream.of(values()).collect( - Collectors.toMap(v -> v.rpm, v -> v)); + toMap(v -> v.rpm, v -> v)); } public static String getDefaultPackageArch(PackageType type) { @@ -848,7 +879,7 @@ public final class LinuxHelper { } else { return Map.entry(components[0], components[1]); } - }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); } catch (IOException ex) { throw new UncheckedIOException(ex); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ObjectMapper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ObjectMapper.java new file mode 100644 index 00000000000..f35e255951e --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ObjectMapper.java @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toSet; +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.math.BigInteger; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.IntPredicate; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.xml.stream.XMLStreamWriter; +import jdk.jpackage.internal.util.IdentityWrapper; + +public final class ObjectMapper { + + private ObjectMapper( + Predicate classFilter, + Predicate> methodFilter, + Predicate leafClassFilter, + Map> substitutes, + Map, BiConsumer>> mutators, + Set accessPackageMethods) { + + this.classFilter = Objects.requireNonNull(classFilter); + this.methodFilter = Objects.requireNonNull(methodFilter); + this.leafClassFilter = Objects.requireNonNull(leafClassFilter); + this.substitutes = Objects.requireNonNull(substitutes); + this.mutators = Objects.requireNonNull(mutators); + this.accessPackageMethods = accessPackageMethods; + } + + public static Builder blank() { + return new Builder().allowAllLeafClasses(false).exceptLeafClasses().add(Stream.of( + Object.class, + String.class, String[].class, + boolean.class, Boolean.class, boolean[].class, Boolean[].class, + byte.class, Byte.class, byte[].class, Byte[].class, + char.class, Character.class, char[].class, Character[].class, + short.class, Short.class, short[].class, Short[].class, + int.class, Integer.class, int[].class, Integer[].class, + long.class, Long.class, long[].class, Long[].class, + float.class, Float.class, float[].class, Float[].class, + double.class, Double.class, double[].class, Double[].class, + void.class, Void.class, Void[].class + ).map(Class::getName).toList()).apply(); + } + + public static Builder standard() { + return blank() + .mutate(configureObject()) + .mutate(configureLeafClasses()) + .mutate(configureOptional()) + .mutate(configureFunctionalTypes()) + .mutate(configureEnum()) + .mutate(configureException()); + } + + public static Consumer configureObject() { + // Exclude all method of Object class. + return builder -> { + builder.exceptMethods().add(OBJECT_METHODS).apply(); + }; + } + + public static Consumer configureLeafClasses() { + return builder -> { + builder.exceptLeafClasses().add(Stream.of( + IdentityWrapper.class, + Class.class, + Path.class, + Path.of("").getClass(), + UUID.class, + BigInteger.class + ).map(Class::getName).toList()).apply(); + }; + } + + public static Consumer configureOptional() { + return builder -> { + // Filter out all but "get()" methods of "Optional" class. + builder.exceptAllMethods(Optional.class).remove("get").apply(); + // Substitute "Optional.get()" with the function that will return "null" if the value is "null". + builder.subst(Optional.class, "get", opt -> { + if (opt.isPresent()) { + return opt.get(); + } else { + return null; + } + }); + }; + } + + public static Consumer configureFunctionalTypes() { + // Remove all getters from the standard functional types. + return builder -> { + builder.exceptAllMethods(Predicate.class).apply(); + builder.exceptAllMethods(Supplier.class).apply(); + }; + } + + public static Consumer configureEnum() { + return builder -> { + // Filter out "getDeclaringClass()" and "describeConstable()" methods of "Enum" class. + builder.exceptSomeMethods(Enum.class).add("getDeclaringClass", "describeConstable").apply(); + }; + } + + public static Consumer configureException() { + return builder -> { + // Include only "getMessage()" and "getCause()" methods of "Exception" class. + builder.exceptAllMethods(Exception.class).remove("getMessage", "getCause").apply(); + builder.mutator(Exception.class, (ex, map) -> { + var eit = map.entrySet().iterator(); + while (eit.hasNext()) { + var e = eit.next(); + if (e.getValue() == NULL) { + // Remove property with the "null" value. + eit.remove(); + } + } + map.put("getClass", ex.getClass().getName()); + }); + }; + } + + public static String lookupFullMethodName(Method m) { + return lookupFullMethodName(m.getDeclaringClass(), m.getName()); + } + + public static String lookupFullMethodName(Class c, String m) { + return Objects.requireNonNull(c).getName() + lookupMethodName(m); + } + + public static String lookupMethodName(Method m) { + return lookupMethodName(m.getName()); + } + + public static String lookupMethodName(String m) { + return "#" + Objects.requireNonNull(m); + } + + public static Object wrapIdentity(Object v) { + if (v instanceof IdentityWrapper wrapper) { + return wrapper; + } else { + return new IdentityWrapper(v); + } + } + + public static void store(Map map, XMLStreamWriter xml) { + XmlWriter.writePropertyMap(map, xml); + } + + @SuppressWarnings("unchecked") + public static Optional findNonNullProperty(Map map, String propertyName) { + Objects.requireNonNull(propertyName); + Objects.requireNonNull(map); + + return Optional.ofNullable(map.get(propertyName)).filter(Predicate.not(NULL::equals)).map(v -> { + return (T)v; + }); + } + + public Object map(Object obj) { + if (obj != null) { + return mapObject(obj).orElseGet(Map::of); + } else { + return null; + } + } + + @SuppressWarnings("unchecked") + public Map toMap(Object obj) { + if (obj == null) { + return null; + } else { + var mappedObj = map(obj); + if (mappedObj instanceof Map m) { + return (Map)m; + } else { + return Map.of("value", mappedObj); + } + } + } + + public Optional mapObject(Object obj) { + if (obj == null) { + return Optional.empty(); + } + + if (leafClassFilter.test(obj.getClass().getName())) { + return Optional.of(obj); + } + + if (!filter(obj.getClass())) { + return Optional.empty(); + } + + if (obj instanceof Iterable col) { + return Optional.of(mapIterable(col)); + } + + if (obj instanceof Map map) { + return Optional.of(mapMap(map)); + } + + if (obj.getClass().isArray()) { + return Optional.of(mapArray(obj)); + } + + var theMap = getMethods(obj).map(m -> { + final Object propertyValue; + final var subst = substitutes.get(m); + if (subst != null) { + propertyValue = applyGetter(obj, subst); + } else { + propertyValue = invoke(m, obj); + } + return Map.entry(m.getName(), mapObject(propertyValue).orElse(NULL)); + }).collect(toMutableMap(Map.Entry::getKey, Map.Entry::getValue)); + + mutators.entrySet().stream().filter(m -> { + return m.getKey().isInstance(obj); + }).findFirst().ifPresent(m -> { + m.getValue().accept(obj, theMap); + }); + + if (theMap.isEmpty()) { + return Optional.of(wrapIdentity(obj)); + } + + return Optional.of(theMap); + } + + private Object invoke(Method m, Object obj) { + try { + return m.invoke(obj); + } catch (IllegalAccessException ex) { + throw rethrowUnchecked(ex); + } catch (InvocationTargetException ex) { + return map(ex.getTargetException()); + } + } + + private Collection mapIterable(Iterable col) { + final List list = new ArrayList<>(); + for (var obj : col) { + list.add(mapObject(obj).orElse(NULL)); + } + return list; + } + + private Map mapMap(Map map) { + return map.entrySet().stream().collect(toMutableMap(e -> { + return mapObject(e.getKey()).orElse(NULL); + }, e -> { + return mapObject(e.getValue()).orElse(NULL); + })); + } + + private Object mapArray(Object arr) { + final var len = Array.getLength(arr); + + if (len == 0) { + return arr; + } + + Object[] buf = null; + + for (int i = 0; i != len; i++) { + var from = Array.get(arr, i); + if (from != null) { + var to = mapObject(from).orElseThrow(); + if (from != to || buf != null) { + if (buf == null) { + buf = (Object[])Array.newInstance(Object.class, len); + System.arraycopy(arr, 0, buf, 0, i); + } + buf[i] = to; + } + } + } + + return Optional.ofNullable((Object)buf).orElse(arr); + } + + @SuppressWarnings("unchecked") + private static Object applyGetter(Object obj, Function getter) { + return getter.apply((T)obj); + } + + private boolean filter(Class type) { + return classFilter.test(type.getName()); + } + + private boolean filter(Method m) { + return methodFilter.test(List.of(lookupMethodName(m), lookupFullMethodName(m))); + } + + private Stream getMethods(Object obj) { + return MethodGroups.create(obj.getClass(), accessPackageMethods).filter(this::filter).map(MethodGroup::callable); + } + + private static boolean defaultFilter(Method m) { + if (Modifier.isStatic(m.getModifiers()) || (m.getParameterCount() > 0) || void.class.equals(m.getReturnType())) { + return false; + } + return true; + } + + private static + Collector> toMutableMap(Function keyMapper, + Function valueMapper) { + return Collectors.toMap(keyMapper, valueMapper, (x , y) -> { + throw new UnsupportedOperationException( + String.format("Entries with the same key and different values [%s] and [%s]", x, y)); + }, HashMap::new); + } + + public static final class Builder { + + private Builder() { + allowAllClasses(); + allowAllLeafClasses(); + allowAllMethods(); + } + + public ObjectMapper create() { + return new ObjectMapper( + classFilter.createPredicate(), + methodFilter.createMultiPredicate(), + leafClassFilter.createPredicate(), + Map.copyOf(substitutes), + Map.copyOf(mutators), + accessPackageMethods); + } + + + public final class NamePredicateBuilder { + + NamePredicateBuilder(Filter sink) { + this.sink = Objects.requireNonNull(sink); + } + + public Builder apply() { + sink.addAll(items); + return Builder.this; + } + + public NamePredicateBuilder add(String... v) { + return add(List.of(v)); + } + + public NamePredicateBuilder add(Collection v) { + items.addAll(v); + return this; + } + + private final Filter sink; + private final Set items = new HashSet<>(); + } + + + public final class AllMethodPredicateBuilder { + + AllMethodPredicateBuilder(Class type) { + impl = new MethodPredicateBuilder(type, false); + } + + public AllMethodPredicateBuilder remove(String... v) { + return remove(List.of(v)); + } + + public AllMethodPredicateBuilder remove(Collection v) { + impl.add(v); + return this; + } + + public Builder apply() { + return impl.apply(); + } + + private final MethodPredicateBuilder impl; + } + + + public final class SomeMethodPredicateBuilder { + + SomeMethodPredicateBuilder(Class type) { + impl = new MethodPredicateBuilder(type, true); + } + + public SomeMethodPredicateBuilder add(String... v) { + return add(List.of(v)); + } + + public SomeMethodPredicateBuilder add(Collection v) { + impl.add(v); + return this; + } + + public Builder apply() { + return impl.apply(); + } + + private final MethodPredicateBuilder impl; + } + + + public Builder allowAllClasses(boolean v) { + classFilter.negate(v); + return this; + } + + public Builder allowAllClasses() { + return allowAllClasses(true); + } + + public Builder allowAllMethods(boolean v) { + methodFilter.negate(v); + return this; + } + + public Builder allowAllMethods() { + return allowAllMethods(true); + } + + public Builder allowAllLeafClasses(boolean v) { + leafClassFilter.negate(v); + return this; + } + + public Builder allowAllLeafClasses() { + return allowAllLeafClasses(true); + } + + public NamePredicateBuilder exceptClasses() { + return new NamePredicateBuilder(classFilter); + } + + public AllMethodPredicateBuilder exceptAllMethods(Class type) { + return new AllMethodPredicateBuilder(type); + } + + public SomeMethodPredicateBuilder exceptSomeMethods(Class type) { + return new SomeMethodPredicateBuilder(type); + } + + public NamePredicateBuilder exceptMethods() { + return new NamePredicateBuilder(methodFilter); + } + + public NamePredicateBuilder exceptLeafClasses() { + return new NamePredicateBuilder(leafClassFilter); + } + + public Builder subst(Method target, Function substitute) { + substitutes.put(Objects.requireNonNull(target), Objects.requireNonNull(substitute)); + return this; + } + + public Builder subst(Class targetClass, String targetMethodName, Function substitute) { + var method = toSupplier(() -> targetClass.getMethod(targetMethodName)).get(); + return subst(method, substitute); + } + + public Builder mutator(Class targetClass, BiConsumer> mutator) { + mutators.put(Objects.requireNonNull(targetClass), Objects.requireNonNull(mutator)); + return this; + } + + public Builder mutate(Consumer mutator) { + mutator.accept(this); + return this; + } + + public Builder accessPackageMethods(Package... packages) { + Stream.of(packages).map(Package::getName).forEach(accessPackageMethods::add); + return this; + } + + + private final class MethodPredicateBuilder { + + MethodPredicateBuilder(Class type, boolean negate) { + this.type = Objects.requireNonNull(type); + buffer.negate(negate); + } + + void add(Collection v) { + buffer.addAll(v); + } + + Builder apply() { + var pred = buffer.createPredicate(); + + var items = MethodGroups.create(type, accessPackageMethods).groups().stream().map(MethodGroup::primary).filter(m -> { + return !OBJECT_METHODS.contains(ObjectMapper.lookupMethodName(m)); + }).filter(m -> { + return !pred.test(m.getName()); + }).map(ObjectMapper::lookupFullMethodName).toList(); + + return exceptMethods().add(items).apply(); + } + + private final Class type; + private final Filter buffer = new Filter(); + } + + + private static final class Filter { + Predicate> createMultiPredicate() { + if (items.isEmpty()) { + var match = negate; + return v -> match; + } else if (negate) { + return v -> { + return v.stream().noneMatch(Set.copyOf(items)::contains); + }; + } else { + return v -> { + return v.stream().anyMatch(Set.copyOf(items)::contains); + }; + } + } + + Predicate createPredicate() { + if (items.isEmpty()) { + var match = negate; + return v -> match; + } else if (negate) { + return Predicate.not(Set.copyOf(items)::contains); + } else { + return Set.copyOf(items)::contains; + } + } + + void addAll(Collection v) { + items.addAll(v); + } + + void negate(boolean v) { + negate = v; + } + + private boolean negate; + private final Set items = new HashSet<>(); + } + + + private final Filter classFilter = new Filter(); + private final Filter methodFilter = new Filter(); + private final Filter leafClassFilter = new Filter(); + private final Map> substitutes = new HashMap<>(); + private final Map, BiConsumer>> mutators = new HashMap<>(); + private final Set accessPackageMethods = new HashSet<>(); + } + + + private record MethodGroup(List methods) { + + MethodGroup { + Objects.requireNonNull(methods); + + if (methods.isEmpty()) { + throw new IllegalArgumentException(); + } + + methods.stream().map(Method::getName).reduce((a, b) -> { + if (!a.equals(b)) { + throw new IllegalArgumentException(); + } else { + return a; + } + }); + } + + Method callable() { + var primary = primary(); + if (!primary.getDeclaringClass().isInterface()) { + primary = methods.stream().filter(m -> { + return m.getDeclaringClass().isInterface(); + }).findFirst().orElse(primary); + } + return primary; + } + + Method primary() { + return methods.getFirst(); + } + + boolean match(Predicate predicate) { + Objects.requireNonNull(predicate); + return methods.stream().allMatch(predicate); + } + } + + + private record MethodGroups(Collection groups) { + + MethodGroups { + Objects.requireNonNull(groups); + } + + Stream filter(Predicate predicate) { + Objects.requireNonNull(predicate); + + return groups.stream().filter(g -> { + return g.match(predicate); + }); + } + + static MethodGroups create(Class type, Set accessPackageMethods) { + List> types = new ArrayList<>(); + + collectSuperclassAndInterfaces(type, types::add); + + final var methodGroups = types.stream() + .map(c -> { + if (accessPackageMethods.contains(c.getPackageName())) { + return PUBLIC_AND_PACKAGE_METHODS_GETTER.apply(c); + } else { + return PUBLIC_METHODS_GETTER.apply(c); + } + }) + .flatMap(x -> x) + .filter(ObjectMapper::defaultFilter) + .collect(groupingBy(Method::getName)); + + return new MethodGroups(methodGroups.values().stream().distinct().map(MethodGroup::new).toList()); + } + + private static void collectSuperclassAndInterfaces(Class type, Consumer> sink) { + Objects.requireNonNull(type); + Objects.requireNonNull(sink); + + for (; type != null; type = type.getSuperclass()) { + sink.accept(type); + for (var i : type.getInterfaces()) { + collectSuperclassAndInterfaces(i, sink); + } + } + } + } + + + private static final class XmlWriter { + static void write(Object obj, XMLStreamWriter xml) { + if (obj instanceof Map map) { + writePropertyMap(map, xml); + } else if (obj instanceof Collection col) { + writeCollection(col, xml); + } else if (obj.getClass().isArray()) { + writeArray(obj, xml); + } else { + toRunnable(() -> xml.writeCharacters(obj.toString())).run(); + } + } + + private static void writePropertyMap(Map map, XMLStreamWriter xml) { + map.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey().toString())).forEach(toConsumer(e -> { + xml.writeStartElement("property"); + xml.writeAttribute("name", e.getKey().toString()); + write(e.getValue(), xml); + xml.writeEndElement(); + })); + } + + private static void writeCollection(Collection col, XMLStreamWriter xml) { + try { + xml.writeStartElement("collection"); + xml.writeAttribute("size", Integer.toString(col.size())); + for (var item : col) { + xml.writeStartElement("item"); + write(item, xml); + xml.writeEndElement(); + } + xml.writeEndElement(); + } catch (Exception ex) { + rethrowUnchecked(ex); + } + } + + private static void writeArray(Object arr, XMLStreamWriter xml) { + var len = Array.getLength(arr); + try { + xml.writeStartElement("array"); + xml.writeAttribute("size", Integer.toString(len)); + for (int i = 0; i != len; i++) { + xml.writeStartElement("item"); + write(Array.get(arr, i), xml); + xml.writeEndElement(); + } + xml.writeEndElement(); + } catch (Exception ex) { + rethrowUnchecked(ex); + } + } + } + + + private final Predicate classFilter; + private final Predicate> methodFilter; + private final Predicate leafClassFilter; + private final Map> substitutes; + private final Map, BiConsumer>> mutators; + private final Set accessPackageMethods; + + static final Object NULL = new Object() { + @Override + public String toString() { + return ""; + } + }; + + private static final Set OBJECT_METHODS = + Stream.of(Object.class.getMethods()).map(ObjectMapper::lookupMethodName).collect(toSet()); + + private static final Function, Stream> PUBLIC_METHODS_GETTER = type -> { + return Stream.of(type.getMethods()); + }; + + private static final Function, Stream> PUBLIC_AND_PACKAGE_METHODS_GETTER = type -> { + return Stream.of(type.getDeclaredMethods()).filter(m -> { + return Stream.of(Modifier::isPrivate, Modifier::isProtected).map(p -> { + return p.test(m.getModifiers()); + }).allMatch(v -> !v); + }).map(m -> { + m.setAccessible(true); + return m; + }); + }; +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index 84453038cd2..3226811fe36 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -39,7 +39,6 @@ import java.nio.file.Path; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -318,6 +317,11 @@ public final class PackageTest extends RunnablePackageTest { return this; } + public PackageTest mutate(Consumer mutator) { + mutator.accept(this); + return this; + } + public PackageTest forTypes(Collection types, Runnable action) { final var oldTypes = Set.of(currentTypes.toArray(PackageType[]::new)); try { @@ -334,7 +338,11 @@ public final class PackageTest extends RunnablePackageTest { } public PackageTest forTypes(PackageType type, Consumer action) { - return forTypes(List.of(type), () -> action.accept(this)); + return forTypes(List.of(type), action); + } + + public PackageTest forTypes(Collection types, Consumer action) { + return forTypes(types, () -> action.accept(this)); } public PackageTest notForTypes(Collection types, Runnable action) { @@ -348,7 +356,11 @@ public final class PackageTest extends RunnablePackageTest { } public PackageTest notForTypes(PackageType type, Consumer action) { - return notForTypes(List.of(type), () -> action.accept(this)); + return notForTypes(List.of(type), action); + } + + public PackageTest notForTypes(Collection types, Consumer action) { + return notForTypes(types, () -> action.accept(this)); } public PackageTest configureHelloApp() { @@ -780,7 +792,7 @@ public final class PackageTest extends RunnablePackageTest { LauncherAsServiceVerifier.verify(cmd); } - cmd.assertAppLayout(); + cmd.runStandardAsserts(); installVerifiers.forEach(v -> v.accept(cmd)); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index bdf9fb85672..a19b3697a81 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -1260,8 +1260,8 @@ public final class TKit { this(hashRecursive(path)); } - public static void assertEquals(PathSnapshot a, PathSnapshot b, String msg) { - assertStringListEquals(a.contentHashes(), b.contentHashes(), msg); + public void assertEquals(PathSnapshot other, String msg) { + assertStringListEquals(contentHashes(), other.contentHashes(), msg); } private static List hashRecursive(Path path) { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/IdentityWrapperTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/IdentityWrapperTest.java new file mode 100644 index 00000000000..471a7cb55a9 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/IdentityWrapperTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + + +public class IdentityWrapperTest { + + @Test + public void test_null() { + assertThrows(NullPointerException.class, () -> identityOf(null)); + } + + @Test + public void test_equals() { + var obj = new TestRecord(10); + assertEquals(identityOf(obj), identityOf(obj)); + } + + @Test + public void test_not_equals() { + var identity = identityOf(new TestRecord(10)); + var identity2 = identityOf(new TestRecord(10)); + assertNotEquals(identity, identity2); + assertEquals(identity.value(), identity2.value()); + } + + @Test + public void test_Foo() { + var foo = new Foo(10); + assertFalse(foo.accessed()); + + foo.hashCode(); + assertTrue(foo.accessed()); + assertTrue(foo.hashCodeCalled()); + assertFalse(foo.equalsCalled()); + + foo = new Foo(1); + foo.equals(null); + assertTrue(foo.accessed()); + assertFalse(foo.hashCodeCalled()); + assertTrue(foo.equalsCalled()); + } + + @Test + public void test_wrappedValue_not_accessed() { + var identity = identityOf(new Foo(10)); + var identity2 = identityOf(new Foo(10)); + assertNotEquals(identity, identity2); + + assertFalse(identity.value().accessed()); + assertFalse(identity2.value().accessed()); + + assertEquals(identity.value(), identity2.value()); + assertEquals(identity2.value(), identity.value()); + + assertTrue(identity.value().accessed()); + assertTrue(identity2.value().accessed()); + } + + @Test + public void test_wrappedValue_not_accessed_in_set() { + var identitySet = Set.of(identityOf(new Foo(10)), identityOf(new Foo(10)), identityOf(new Foo(10))); + assertEquals(3, identitySet.size()); + + var valueSet = identitySet.stream().peek(identity -> { + assertFalse(identity.value().accessed()); + }).map(IdentityWrapper::value).collect(Collectors.toSet()); + + assertEquals(1, valueSet.size()); + } + + private static IdentityWrapper identityOf(T obj) { + return new IdentityWrapper<>(obj); + } + + private record TestRecord(int v) {} + + private final static class Foo { + + Foo(int v) { + this.v = v; + } + + @Override + public int hashCode() { + try { + return Objects.hash(v); + } finally { + hashCodeCalled = true; + } + } + + @Override + public boolean equals(Object obj) { + try { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Foo other = (Foo) obj; + return v == other.v; + } finally { + equalsCalled = true; + } + } + + boolean equalsCalled() { + return equalsCalled; + } + + boolean hashCodeCalled() { + return hashCodeCalled; + } + + boolean accessed() { + return equalsCalled() || hashCodeCalled(); + } + + private final int v; + private boolean equalsCalled; + private boolean hashCodeCalled; + } +} diff --git a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java new file mode 100644 index 00000000000..c91b178cb10 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.util.Map; +import java.util.Objects; +import org.junit.jupiter.api.Assertions; + + +public final class JUnitUtils { + + /** + * Convenience adapter for {@link Assertions#assertArrayEquals(byte[], byte[])}, + * {@link Assertions#assertArrayEquals(int[], int[])}, + * {@link Assertions#assertArrayEquals(Object[], Object[])}, etc. methods. + * + * @param expected the expected array to test for equality + * @param actual the actual array to test for equality + */ + public static void assertArrayEquals(Object expected, Object actual) { + ARRAY_ASSERTERS.getOrDefault(expected.getClass().componentType(), OBJECT_ARRAY_ASSERTER).acceptUnchecked(expected, actual); + } + + /** + * Converts the given exception object to a property map. + *

+ * Values returned by public getters are added to the map. Names of getters are + * the keys in the returned map. The values are property map representations of + * the objects returned by the getters. Only {@link Throwable#getMessage()} and + * {@link Throwable#getCause()} getters are picked for the property map by + * default. If the exception class has additional getters, they will be added to + * the map. {@code null} is permitted. + * + * @param ex the exception to convert into a property map + * @return the property map view of the given exception object + */ + public static Map exceptionAsPropertyMap(Exception ex) { + return EXCEPTION_OM.toMap(ex); + } + + + public static final class ExceptionPattern { + + public ExceptionPattern() { + } + + public boolean match(Exception ex) { + Objects.requireNonNull(ex); + + if (expectedType != null && !expectedType.isInstance(ex)) { + return false; + } + + if (expectedMessage != null && !expectedMessage.equals(ex.getMessage())) { + return false; + } + + if (expectedCauseType != null && !expectedCauseType.isInstance(ex.getCause())) { + return false; + } + + return true; + } + + public ExceptionPattern hasMessage(String v) { + expectedMessage = v; + return this; + } + + public ExceptionPattern isInstanceOf(Class v) { + expectedType = v; + return this; + } + + public ExceptionPattern isCauseInstanceOf(Class v) { + expectedCauseType = v; + return this; + } + + public ExceptionPattern hasCause(boolean v) { + return isCauseInstanceOf(v ? Exception.class : null); + } + + public ExceptionPattern hasCause() { + return hasCause(true); + } + + private String expectedMessage; + private Class expectedType; + private Class expectedCauseType; + } + + + @FunctionalInterface + private interface ArrayEqualsAsserter { + void accept(T expected, T actual); + + @SuppressWarnings("unchecked") + default void acceptUnchecked(Object expected, Object actual) { + accept((T)expected, (T)actual); + } + } + + + private static final Map, ArrayEqualsAsserter> ARRAY_ASSERTERS = Map.of( + boolean.class, (ArrayEqualsAsserter)Assertions::assertArrayEquals, + byte.class, (ArrayEqualsAsserter)Assertions::assertArrayEquals, + char.class, (ArrayEqualsAsserter)Assertions::assertArrayEquals, + double.class, (ArrayEqualsAsserter)Assertions::assertArrayEquals, + float.class, (ArrayEqualsAsserter)Assertions::assertArrayEquals, + int.class, (ArrayEqualsAsserter)Assertions::assertArrayEquals, + long.class, (ArrayEqualsAsserter)Assertions::assertArrayEquals, + short.class, (ArrayEqualsAsserter)Assertions::assertArrayEquals + ); + + private static final ArrayEqualsAsserter OBJECT_ARRAY_ASSERTER = Assertions::assertArrayEquals; + + private static final ObjectMapper EXCEPTION_OM = ObjectMapper.standard().create(); +} diff --git a/test/jdk/tools/jpackage/linux/ShortcutHintTest.java b/test/jdk/tools/jpackage/linux/ShortcutHintTest.java index 4d3b33bcd6b..8d373cb2b86 100644 --- a/test/jdk/tools/jpackage/linux/ShortcutHintTest.java +++ b/test/jdk/tools/jpackage/linux/ShortcutHintTest.java @@ -164,7 +164,7 @@ public class ShortcutHintTest { "Exec=APPLICATION_LAUNCHER", "Terminal=false", "Type=Application", - "Comment=", + "Comment=APPLICATION_DESCRIPTION", "Icon=APPLICATION_ICON", "Categories=DEPLOY_BUNDLE_CATEGORY", expectedVersionString diff --git a/test/jdk/tools/jpackage/share/AddLShortcutTest.java b/test/jdk/tools/jpackage/share/AddLShortcutTest.java index 9c50c6ffc98..f000e79227e 100644 --- a/test/jdk/tools/jpackage/share/AddLShortcutTest.java +++ b/test/jdk/tools/jpackage/share/AddLShortcutTest.java @@ -118,6 +118,12 @@ public class AddLShortcutTest { HelloApp.createBundle(JavaAppDesc.parse(addLauncherApp + "*another.jar:Welcome"), cmd.inputDir()); }); + if (RunnablePackageTest.hasAction(RunnablePackageTest.Action.INSTALL)) { + // Ensure launchers are executable because the output bundle will be installed + // and launchers will be attempted to be executed through their shortcuts. + packageTest.addInitializer(JPackageCommand::ignoreFakeRuntime); + } + new FileAssociations(packageName).applyTo(packageTest); new AdditionalLauncher("Foo") diff --git a/test/jdk/tools/jpackage/share/AddLauncherTest.java b/test/jdk/tools/jpackage/share/AddLauncherTest.java index a7bfbf376ed..21f475cbd78 100644 --- a/test/jdk/tools/jpackage/share/AddLauncherTest.java +++ b/test/jdk/tools/jpackage/share/AddLauncherTest.java @@ -21,18 +21,22 @@ * questions. */ -import java.nio.file.Path; -import java.util.Map; import java.lang.invoke.MethodHandles; -import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.FileAssociations; +import java.nio.file.Path; +import java.util.function.Consumer; +import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.AdditionalLauncher; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.CfgFile; +import jdk.jpackage.test.ConfigurationTarget; +import jdk.jpackage.test.FileAssociations; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JavaAppDesc; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.RunnablePackageTest.Action; import jdk.jpackage.test.TKit; -import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; -import jdk.jpackage.test.CfgFile; /** * Test --add-launcher parameter. Output of the test should be @@ -233,6 +237,61 @@ public class AddLauncherTest { "Check app.classpath value in ModularAppLauncher cfg file"); } + /** + * Test --description option + */ + @Test(ifNotOS = OperatingSystem.MACOS) // Don't run on macOS as launcher description is ignored on this platform + @Parameter("true") + @Parameter("fase") + public void testDescription(boolean withPredefinedAppImage) { + + ConfigurationTarget target; + if (TKit.isWindows() || withPredefinedAppImage) { + target = new ConfigurationTarget(JPackageCommand.helloAppImage()); + } else { + target = new ConfigurationTarget(new PackageTest().configureHelloApp()); + } + + target.addInitializer(cmd -> { + cmd.setArgumentValue("--name", "Foo").setArgumentValue("--description", "Hello"); + cmd.setFakeRuntime(); + cmd.setStandardAsserts(JPackageCommand.StandardAssert.MAIN_LAUNCHER_DESCRIPTION); + }); + + target.add(new AdditionalLauncher("x")); + target.add(new AdditionalLauncher("bye").setProperty("description", "Bye")); + + target.test().ifPresent(test -> { + // Make all launchers have shortcuts and thus .desktop files. + // Launcher description is recorded in a desktop file and verified automatically. + test.mutate(addLinuxShortcuts()); + }); + + target.cmd().ifPresent(withPredefinedAppImage ? JPackageCommand::execute : JPackageCommand::executeAndAssertImageCreated); + target.test().ifPresent(test -> { + test.run(Action.CREATE_AND_UNPACK); + }); + + if (withPredefinedAppImage) { + new PackageTest().addInitializer(cmd -> { + cmd.setArgumentValue("--name", "Bar"); + // Should not have impact of launcher descriptions, but it does. + cmd.setArgumentValue("--description", "Installer"); + cmd.removeArgumentWithValue("--input").setArgumentValue("--app-image", target.cmd().orElseThrow().outputBundle()); + }).mutate(addLinuxShortcuts()).run(Action.CREATE_AND_UNPACK); + } + } + + private static Consumer addLinuxShortcuts() { + return test -> { + test.forTypes(PackageType.LINUX, () -> { + test.addInitializer(cmd -> { + cmd.addArgument("--linux-shortcut"); + }); + }); + }; + } + private static final Path GOLDEN_ICON = TKit.TEST_SRC_ROOT.resolve(Path.of( "resources", "icon" + TKit.ICON_SUFFIX)); } diff --git a/test/jdk/tools/jpackage/share/AppImagePackageTest.java b/test/jdk/tools/jpackage/share/AppImagePackageTest.java index 34a418c6f9e..aacb76b122b 100644 --- a/test/jdk/tools/jpackage/share/AppImagePackageTest.java +++ b/test/jdk/tools/jpackage/share/AppImagePackageTest.java @@ -21,20 +21,21 @@ * questions. */ -import java.nio.file.Path; -import java.nio.file.Files; import java.io.IOException; -import java.util.List; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.function.Predicate; import jdk.jpackage.internal.util.XmlUtils; -import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.CannedFormattedString; -import jdk.jpackage.test.TKit; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageCommand.StandardAssert; import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.RunnablePackageTest.Action; -import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.TKit; /** * Test --app-image parameter. The output installer should provide the same @@ -55,56 +56,86 @@ import jdk.jpackage.test.Annotations.Test; */ public class AppImagePackageTest { + /** + * Create a native bundle from a valid predefined app image produced by jpackage. + */ @Test public static void test() { - Path appimageOutput = TKit.workDir().resolve("appimage"); - JPackageCommand appImageCmd = JPackageCommand.helloAppImage() - .setArgumentValue("--dest", appimageOutput); + var appImageCmd = JPackageCommand.helloAppImage() + .setArgumentValue("--dest", TKit.createTempDirectory("appimage")); new PackageTest() - .addRunOnceInitializer(() -> appImageCmd.execute()) + .addRunOnceInitializer(appImageCmd::execute) .addInitializer(cmd -> { cmd.addArguments("--app-image", appImageCmd.outputBundle()); cmd.removeArgumentWithValue("--input"); }).addBundleDesktopIntegrationVerifier(false).run(); } + /** + * Create a native bundle from a predefined app image not produced by jpackage + * but having a valid ".jpackage.xml" file. + * + * @param withIcon {@code true} if jpackage command line should have "--icon" + * option + */ @Test @Parameter("true") @Parameter("false") public static void testEmpty(boolean withIcon) throws IOException { - final String name = "EmptyAppImagePackageTest"; - final String imageName = name + (TKit.isOSX() ? ".app" : ""); - Path appImageDir = TKit.createTempDirectory("appimage").resolve(imageName); - Files.createDirectories(appImageDir.resolve("bin")); - Path libDir = Files.createDirectories(appImageDir.resolve("lib")); - TKit.createTextFile(libDir.resolve("README"), - List.of("This is some arbitrary text for the README file\n")); + var appImageCmd = JPackageCommand.helloAppImage() + .setFakeRuntime() + .setArgumentValue("--name", "EmptyAppImagePackageTest") + .setArgumentValue("--dest", TKit.createTempDirectory("appimage")); new PackageTest() + .addRunOnceInitializer(appImageCmd::execute) + .addRunOnceInitializer(() -> { + var layout = appImageCmd.appLayout(); + if (!TKit.isOSX()) { + // Delete the launcher if not on macOS. + // On macOS, deleting the launcher will render the app bundle invalid. + TKit.deleteIfExists(appImageCmd.appLauncherPath()); + } + // Delete the runtime. + TKit.deleteDirectoryRecursive(layout.runtimeDirectory()); + // Delete the "app" dir. + TKit.deleteDirectoryRecursive(layout.appDirectory()); + + new AppImageFile(appImageCmd.name(), "PhonyMainClass").save(appImageCmd.outputBundle()); + var appImageDir = appImageCmd.outputBundle(); + + TKit.trace(String.format("Files in [%s] app image:", appImageDir)); + try (var files = Files.walk(appImageDir)) { + files.sequential() + .filter(Predicate.isEqual(appImageDir).negate()) + .map(path -> String.format("[%s]", appImageDir.relativize(path))) + .forEachOrdered(TKit::trace); + TKit.trace("Done"); + } + }) .addInitializer(cmd -> { - cmd.addArguments("--app-image", appImageDir); + cmd.addArguments("--app-image", appImageCmd.outputBundle()); if (withIcon) { cmd.addArguments("--icon", iconPath("icon")); } cmd.removeArgumentWithValue("--input"); - new AppImageFile("EmptyAppImagePackageTest", "Hello").save(appImageDir); - // on mac, with --app-image and without --mac-package-identifier, - // will try to infer it from the image, so foreign image needs it. - if (TKit.isOSX()) { - cmd.addArguments("--mac-package-identifier", name); - } + cmd.excludeStandardAsserts( + StandardAssert.MAIN_JAR_FILE, + StandardAssert.MAIN_LAUNCHER_FILES, + StandardAssert.MAC_BUNDLE_STRUCTURE, + StandardAssert.RUNTIME_DIRECTORY); }) - // On macOS we always signing app image and signing will fail, since - // test produces invalid app bundle. - .setExpectedExitCode(TKit.isOSX() ? 1 : 0) - .run(Action.CREATE, Action.UNPACK); - // default: {CREATE, UNPACK, VERIFY}, but we can't verify foreign image + .run(Action.CREATE_AND_UNPACK); } + /** + * Bad predefined app image - not an output of jpackage. + * jpackage command using the bad predefined app image doesn't have "--name" option. + */ @Test public static void testBadAppImage() throws IOException { Path appImageDir = TKit.createTempDirectory("appimage"); @@ -114,6 +145,9 @@ public class AppImagePackageTest { }).run(Action.CREATE); } + /** + * Bad predefined app image - not an output of jpackage. + */ @Test public static void testBadAppImage2() throws IOException { Path appImageDir = TKit.createTempDirectory("appimage"); @@ -121,8 +155,11 @@ public class AppImagePackageTest { configureBadAppImage(appImageDir).run(Action.CREATE); } + /** + * Bad predefined app image - valid app image missing ".jpackage.xml" file. + */ @Test - public static void testBadAppImage3() throws IOException { + public static void testBadAppImage3() { Path appImageDir = TKit.createTempDirectory("appimage"); JPackageCommand appImageCmd = JPackageCommand.helloAppImage(). @@ -134,8 +171,11 @@ public class AppImagePackageTest { }).run(Action.CREATE); } + /** + * Bad predefined app image - valid app image with invalid ".jpackage.xml" file. + */ @Test - public static void testBadAppImageFile() throws IOException { + public static void testBadAppImageFile() { final var appImageRoot = TKit.createTempDirectory("appimage"); final var appImageCmd = JPackageCommand.helloAppImage(). diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index f7c597d2ed3..d36731c2960 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -38,7 +38,7 @@ import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.JPackageCommand.AppLayoutAssert; +import jdk.jpackage.test.JPackageCommand.StandardAssert; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; @@ -177,7 +177,7 @@ public final class InOutPathTest { if (!isAppImageValid(cmd)) { // Standard asserts for .jpackage.xml fail in messed up app image. Disable them. // Other standard asserts for app image contents should pass. - cmd.excludeAppLayoutAsserts(AppLayoutAssert.APP_IMAGE_FILE); + cmd.excludeStandardAsserts(StandardAssert.APP_IMAGE_FILE); } }; diff --git a/test/jdk/tools/jpackage/share/LicenseTest.java b/test/jdk/tools/jpackage/share/LicenseTest.java index c9e3c8508aa..1c6bfd51b62 100644 --- a/test/jdk/tools/jpackage/share/LicenseTest.java +++ b/test/jdk/tools/jpackage/share/LicenseTest.java @@ -208,7 +208,7 @@ public class LicenseTest { private static void verifyLicenseFileInLinuxPackage(JPackageCommand cmd, Path expectedLicensePath) { TKit.assertTrue(LinuxHelper.getPackageFiles(cmd).filter(path -> path.equals( - expectedLicensePath)).findFirst().orElse(null) != null, + expectedLicensePath)).findFirst().isPresent(), String.format("Check license file [%s] is in %s package", expectedLicensePath, LinuxHelper.getPackageName(cmd))); } diff --git a/test/jdk/tools/jpackage/share/RuntimePackageTest.java b/test/jdk/tools/jpackage/share/RuntimePackageTest.java index f66f774b227..caa129713b4 100644 --- a/test/jdk/tools/jpackage/share/RuntimePackageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimePackageTest.java @@ -135,11 +135,7 @@ public class RuntimePackageTest { }) .addInstallVerifier(cmd -> { var src = TKit.assertDirectoryContentRecursive(inputRuntimeDir(cmd)).items(); - Path dest = cmd.appRuntimeDirectory(); - if (TKit.isOSX()) { - dest = dest.resolve("Contents/Home"); - } - + var dest = cmd.appLayout().runtimeHomeDirectory(); TKit.assertDirectoryContentRecursive(dest).match(src); }) .forTypes(PackageType.LINUX_DEB, test -> { From 70e786154fae78c0dacaa3e29c7aa4d3d14b892b Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 22 Oct 2025 06:01:11 +0000 Subject: [PATCH 011/736] 8370248: AOTMapLogger should check if pointer is in AOTMetaspace Reviewed-by: kvn, adinn --- src/hotspot/share/cds/aotMapLogger.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp index b0e410b5cf1..151c15048c2 100644 --- a/src/hotspot/share/cds/aotMapLogger.cpp +++ b/src/hotspot/share/cds/aotMapLogger.cpp @@ -135,12 +135,14 @@ public: virtual bool do_unique_ref(Ref* ref, bool read_only) { ArchivedObjInfo info; - info._src_addr = ref->obj(); - info._buffered_addr = ref->obj(); - info._requested_addr = ref->obj(); - info._bytes = ref->size() * BytesPerWord; - info._type = ref->msotype(); - _objs.append(info); + if (AOTMetaspace::in_aot_cache(ref->obj())) { + info._src_addr = ref->obj(); + info._buffered_addr = ref->obj(); + info._requested_addr = ref->obj(); + info._bytes = ref->size() * BytesPerWord; + info._type = ref->msotype(); + _objs.append(info); + } return true; // keep iterating } From eff4b1103396dc8e383d86472435ff983e298b61 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Wed, 22 Oct 2025 07:45:40 +0000 Subject: [PATCH 012/736] 8369322: Implement native stack printing for Windows-AArch64 Reviewed-by: dholmes, karianna --- src/hotspot/os/windows/os_windows.cpp | 103 ++++++++++++++++++ .../os_windows_aarch64.inline.hpp | 7 ++ .../os_cpu/windows_x86/os_windows_x86.cpp | 92 ---------------- 3 files changed, 110 insertions(+), 92 deletions(-) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index ba05d390c9f..7934c9d6ffb 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -6259,3 +6259,106 @@ const void* os::get_saved_assert_context(const void** sigInfo) { *sigInfo = nullptr; return nullptr; } + +/* + * Windows/x64 does not use stack frames the way expected by Java: + * [1] in most cases, there is no frame pointer. All locals are addressed via RSP + * [2] in rare cases, when alloca() is used, a frame pointer is used, but this may + * not be RBP. + * See http://msdn.microsoft.com/en-us/library/ew5tede7.aspx + * + * So it's not possible to print the native stack using the + * while (...) {... fr = os::get_sender_for_C_frame(&fr); } + * loop in vmError.cpp. We need to roll our own loop. + * This approach works for Windows AArch64 as well. + */ +bool os::win32::platform_print_native_stack(outputStream* st, const void* context, + char* buf, int buf_size, address& lastpc) +{ + CONTEXT ctx; + if (context != nullptr) { + memcpy(&ctx, context, sizeof(ctx)); + } else { + RtlCaptureContext(&ctx); + } + + st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); + + DWORD machine_type; + STACKFRAME stk; + memset(&stk, 0, sizeof(stk)); + stk.AddrStack.Mode = AddrModeFlat; + stk.AddrFrame.Mode = AddrModeFlat; + stk.AddrPC.Mode = AddrModeFlat; + +#if defined(_M_AMD64) + stk.AddrStack.Offset = ctx.Rsp; + stk.AddrFrame.Offset = ctx.Rbp; + stk.AddrPC.Offset = ctx.Rip; + machine_type = IMAGE_FILE_MACHINE_AMD64; +#elif defined(_M_ARM64) + stk.AddrStack.Offset = ctx.Sp; + stk.AddrFrame.Offset = ctx.Fp; + stk.AddrPC.Offset = ctx.Pc; + machine_type = IMAGE_FILE_MACHINE_ARM64; +#else + #error unknown architecture +#endif + + // Ensure we consider dynamically loaded DLLs + SymbolEngine::refreshModuleList(); + + int count = 0; + address lastpc_internal = 0; + while (count++ < StackPrintLimit) { + intptr_t* sp = (intptr_t*)stk.AddrStack.Offset; + intptr_t* fp = (intptr_t*)stk.AddrFrame.Offset; // NOT necessarily the same as ctx.Rbp! + address pc = (address)stk.AddrPC.Offset; + + if (pc != nullptr) { + if (count == 2 && lastpc_internal == pc) { + // Skip it -- StackWalk64() may return the same PC + // (but different SP) on the first try. + } else { + // Don't try to create a frame(sp, fp, pc) -- on WinX64, stk.AddrFrame + // may not contain what Java expects, and may cause the frame() constructor + // to crash. Let's just print out the symbolic address. + frame::print_C_frame(st, buf, buf_size, pc); + // print source file and line, if available + char buf[128]; + int line_no; + if (SymbolEngine::get_source_info(pc, buf, sizeof(buf), &line_no)) { + st->print(" (%s:%d)", buf, line_no); + } else { + st->print(" (no source info available)"); + } + st->cr(); + } + lastpc_internal = pc; + } + + PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset); + if (p == nullptr) { + // StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash. + lastpc = lastpc_internal; + break; + } + + BOOL result = WindowsDbgHelp::stackWalk64( + machine_type, // __in DWORD MachineType, + GetCurrentProcess(), // __in HANDLE hProcess, + GetCurrentThread(), // __in HANDLE hThread, + &stk, // __inout LP STACKFRAME64 StackFrame, + &ctx); // __inout PVOID ContextRecord, + + if (!result) { + break; + } + } + if (count > StackPrintLimit) { + st->print_cr("......"); + } + st->cr(); + + return true; +} diff --git a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.inline.hpp b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.inline.hpp index 794aa12155b..568b6e3938e 100644 --- a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.inline.hpp @@ -26,10 +26,17 @@ #define OS_CPU_WINDOWS_AARCH64_OS_WINDOWS_AARCH64_INLINE_HPP #include "runtime/os.hpp" +#include "os_windows.hpp" inline bool os::register_code_area(char *low, char *high) { // Using Vectored Exception Handling return true; } +#define HAVE_PLATFORM_PRINT_NATIVE_STACK 1 +inline bool os::platform_print_native_stack(outputStream* st, const void* context, + char *buf, int buf_size, address& lastpc) { + return os::win32::platform_print_native_stack(st, context, buf, buf_size, lastpc); +} + #endif // OS_CPU_WINDOWS_AARCH64_OS_WINDOWS_AARCH64_INLINE_HPP diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index c188919595c..53f96479832 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -197,98 +197,6 @@ bool handle_FLT_exception(struct _EXCEPTION_POINTERS* exceptionInfo) { } #endif -#ifdef HAVE_PLATFORM_PRINT_NATIVE_STACK -/* - * Windows/x64 does not use stack frames the way expected by Java: - * [1] in most cases, there is no frame pointer. All locals are addressed via RSP - * [2] in rare cases, when alloca() is used, a frame pointer is used, but this may - * not be RBP. - * See http://msdn.microsoft.com/en-us/library/ew5tede7.aspx - * - * So it's not possible to print the native stack using the - * while (...) {... fr = os::get_sender_for_C_frame(&fr); } - * loop in vmError.cpp. We need to roll our own loop. - */ -bool os::win32::platform_print_native_stack(outputStream* st, const void* context, - char *buf, int buf_size, address& lastpc) -{ - CONTEXT ctx; - if (context != nullptr) { - memcpy(&ctx, context, sizeof(ctx)); - } else { - RtlCaptureContext(&ctx); - } - - st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); - - STACKFRAME stk; - memset(&stk, 0, sizeof(stk)); - stk.AddrStack.Offset = ctx.Rsp; - stk.AddrStack.Mode = AddrModeFlat; - stk.AddrFrame.Offset = ctx.Rbp; - stk.AddrFrame.Mode = AddrModeFlat; - stk.AddrPC.Offset = ctx.Rip; - stk.AddrPC.Mode = AddrModeFlat; - - // Ensure we consider dynamically loaded dll's - SymbolEngine::refreshModuleList(); - - int count = 0; - address lastpc_internal = 0; - while (count++ < StackPrintLimit) { - intptr_t* sp = (intptr_t*)stk.AddrStack.Offset; - intptr_t* fp = (intptr_t*)stk.AddrFrame.Offset; // NOT necessarily the same as ctx.Rbp! - address pc = (address)stk.AddrPC.Offset; - - if (pc != nullptr) { - if (count == 2 && lastpc_internal == pc) { - // Skip it -- StackWalk64() may return the same PC - // (but different SP) on the first try. - } else { - // Don't try to create a frame(sp, fp, pc) -- on WinX64, stk.AddrFrame - // may not contain what Java expects, and may cause the frame() constructor - // to crash. Let's just print out the symbolic address. - frame::print_C_frame(st, buf, buf_size, pc); - // print source file and line, if available - char buf[128]; - int line_no; - if (SymbolEngine::get_source_info(pc, buf, sizeof(buf), &line_no)) { - st->print(" (%s:%d)", buf, line_no); - } else { - st->print(" (no source info available)"); - } - st->cr(); - } - lastpc_internal = pc; - } - - PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset); - if (!p) { - // StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash. - lastpc = lastpc_internal; - break; - } - - BOOL result = WindowsDbgHelp::stackWalk64( - IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType, - GetCurrentProcess(), // __in HANDLE hProcess, - GetCurrentThread(), // __in HANDLE hThread, - &stk, // __inout LP STACKFRAME64 StackFrame, - &ctx); // __inout PVOID ContextRecord, - - if (!result) { - break; - } - } - if (count > StackPrintLimit) { - st->print_cr("......"); - } - st->cr(); - - return true; -} -#endif // HAVE_PLATFORM_PRINT_NATIVE_STACK - address os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { From 8d9b2fa6af5d0f601168abbc24510a4e9eed785b Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Wed, 22 Oct 2025 07:50:38 +0000 Subject: [PATCH 013/736] 8365072: Refactor tests to use PEM API (Phase 2) Reviewed-by: ascarpino --- .../cert/CertPathBuilder/NoExtensions.java | 27 +- .../selfIssued/StatusLoopDependency.java | 98 +++-- .../indirectCRL/CircularCRLTwoLevel.java | 77 ++-- .../CircularCRLTwoLevelRevoked.java | 79 ++-- .../ssl/ServerName/SSLSocketSNISensitive.java | 375 +++++++++--------- .../ClientHelloBufferUnderflowException.java | 3 +- .../ssl/interop/ClientHelloChromeInterOp.java | 3 +- .../net/ssl/interop/ClientHelloInterOp.java | 69 ++-- .../CPValidatorTrustAnchor.java | 59 +-- .../sun/security/rsa/InvalidBitString.java | 33 +- .../ssl/ClientHandshaker/RSAExport.java | 86 ++-- .../BasicConstraints.java | 212 ++++------ .../X509TrustManagerImpl/ComodoHacker.java | 50 +-- .../sun/security/x509/X509CRLImpl/Verify.java | 36 +- 14 files changed, 560 insertions(+), 647 deletions(-) diff --git a/test/jdk/java/security/cert/CertPathBuilder/NoExtensions.java b/test/jdk/java/security/cert/CertPathBuilder/NoExtensions.java index 7109d310d51..e38d18dc943 100644 --- a/test/jdk/java/security/cert/CertPathBuilder/NoExtensions.java +++ b/test/jdk/java/security/cert/CertPathBuilder/NoExtensions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,10 @@ * @test * @bug 4519462 * @summary Verify Sun CertPathBuilder implementation handles certificates with no extensions + * @enablePreview */ +import java.security.PEMDecoder; import java.security.cert.X509Certificate; import java.security.cert.TrustAnchor; import java.security.cert.CollectionCertStoreParameters; @@ -35,16 +37,15 @@ import java.security.cert.X509CertSelector; import java.security.cert.CertPathBuilder; import java.security.cert.PKIXBuilderParameters; import java.security.cert.CertPathBuilderResult; -import java.security.cert.CertificateFactory; -import java.security.cert.CRL; import java.security.cert.CertPath; import java.util.HashSet; import java.util.ArrayList; -import java.io.ByteArrayInputStream; // Test based on user code submitted with bug by daniel.boggs@compass.net public class NoExtensions { + private static final PEMDecoder pemDecoder = PEMDecoder.of(); + public static void main(String[] args) { try { NoExtensions certs = new NoExtensions(); @@ -92,7 +93,7 @@ public class NoExtensions { // System.out.println(certPath.toString()); } - private static X509Certificate getTrustedCertificate() throws Exception { + private static X509Certificate getTrustedCertificate() { String sCert = "-----BEGIN CERTIFICATE-----\n" + "MIIBezCCASWgAwIBAgIQyWD8dLUoqpJFyDxrfRlrsTANBgkqhkiG9w0BAQQFADAW\n" @@ -104,12 +105,10 @@ public class NoExtensions { + "AKoAZIoRz7jUqlw19DANBgkqhkiG9w0BAQQFAANBACJxAfP57yqaT9N+nRgAOugM\n" + "JG0aN3/peCIvL3p29epRL2xoWFvxpUUlsH2I39OZ6b8+twWCebhkv1I62segXAk=\n" + "-----END CERTIFICATE-----"; - CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream bytes = new ByteArrayInputStream(sCert.getBytes()); - return (X509Certificate)certFactory.generateCertificate(bytes); + return pemDecoder.decode(sCert, X509Certificate.class); } - private static X509Certificate getUserCertificate1() throws Exception { + private static X509Certificate getUserCertificate1() { // this certificate includes an extension String sCert = "-----BEGIN CERTIFICATE-----\n" @@ -123,12 +122,10 @@ public class NoExtensions { + "CxeUaYlXmvbxVNkxM65Pplsj3h4ntfZaynmlhahH3YsnnA8wk6xPt04LjSId12RB\n" + "PeuO\n" + "-----END CERTIFICATE-----"; - CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream bytes = new ByteArrayInputStream(sCert.getBytes()); - return (X509Certificate)certFactory.generateCertificate(bytes); + return pemDecoder.decode(sCert, X509Certificate.class); } - private static X509Certificate getUserCertificate2() throws Exception { + private static X509Certificate getUserCertificate2() { // this certificate does not include any extensions String sCert = "-----BEGIN CERTIFICATE-----\n" @@ -140,8 +137,6 @@ public class NoExtensions { + "BAUAA0EAQmj9SFHEx66JyAps3ew4pcSS3QvfVZ/6qsNUYCG75rFGcTUPHcXKql9y\n" + "qBT83iNLJ//krjw5Ju0WRPg/buHSww==\n" + "-----END CERTIFICATE-----"; - CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream bytes = new ByteArrayInputStream(sCert.getBytes()); - return (X509Certificate)certFactory.generateCertificate(bytes); + return pemDecoder.decode(sCert, X509Certificate.class); } } diff --git a/test/jdk/java/security/cert/CertPathBuilder/selfIssued/StatusLoopDependency.java b/test/jdk/java/security/cert/CertPathBuilder/selfIssued/StatusLoopDependency.java index 65242394162..2a1514fae8a 100644 --- a/test/jdk/java/security/cert/CertPathBuilder/selfIssued/StatusLoopDependency.java +++ b/test/jdk/java/security/cert/CertPathBuilder/selfIssued/StatusLoopDependency.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,18 +33,31 @@ * @summary PIT b61: PKI test suite fails because self signed certificates * are being rejected * @modules java.base/sun.security.util + * @enablePreview * @run main/othervm StatusLoopDependency subca * @run main/othervm StatusLoopDependency subci * @run main/othervm StatusLoopDependency alice - * @author Xuelei Fan */ -import java.io.*; -import java.net.SocketException; -import java.util.*; +import java.security.DEREncodable; +import java.security.PEMDecoder; import java.security.Security; -import java.security.cert.*; -import java.security.cert.CertPathValidatorException.BasicReason; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertStore; +import java.security.cert.Certificate; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathBuilderResult; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + import sun.security.util.DerInputStream; /** @@ -183,61 +196,46 @@ public final class StatusLoopDependency { "N9AvUXxGxU4DruoJuFPcrCI=\n" + "-----END X509 CRL-----"; - private static Set generateTrustAnchors() - throws CertificateException { - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + private static final PEMDecoder pemDecoder = PEMDecoder.of(); - ByteArrayInputStream is = - new ByteArrayInputStream(selfSignedCertStr.getBytes()); - Certificate selfSignedCert = cf.generateCertificate(is); + private static Set generateTrustAnchors() { + X509Certificate selfSignedCert = pemDecoder.decode(selfSignedCertStr, X509Certificate.class); // generate a trust anchor TrustAnchor anchor = - new TrustAnchor((X509Certificate)selfSignedCert, null); + new TrustAnchor(selfSignedCert, null); return Collections.singleton(anchor); } private static CertStore generateCertificateStore() throws Exception { - Collection entries = new HashSet(); - // generate certificate from certificate string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Collection entries = new HashSet<>(); - ByteArrayInputStream is; - - is = new ByteArrayInputStream(targetCertStr.getBytes()); - Certificate cert = cf.generateCertificate(is); + DEREncodable cert = pemDecoder.decode(targetCertStr, X509Certificate.class); entries.add(cert); - is = new ByteArrayInputStream(subCaCertStr.getBytes()); - cert = cf.generateCertificate(is); + cert = pemDecoder.decode(subCaCertStr, X509Certificate.class); entries.add(cert); - is = new ByteArrayInputStream(selfSignedCertStr.getBytes()); - cert = cf.generateCertificate(is); + cert = pemDecoder.decode(selfSignedCertStr, X509Certificate.class); entries.add(cert); - is = new ByteArrayInputStream(topCrlIssuerCertStr.getBytes()); - cert = cf.generateCertificate(is); + cert = pemDecoder.decode(topCrlIssuerCertStr, X509Certificate.class); entries.add(cert); - is = new ByteArrayInputStream(subCrlIssuerCertStr.getBytes()); - cert = cf.generateCertificate(is); + cert = pemDecoder.decode(subCrlIssuerCertStr, X509Certificate.class); entries.add(cert); // generate CRL from CRL string - is = new ByteArrayInputStream(topCrlStr.getBytes()); - Collection mixes = cf.generateCRLs(is); - entries.addAll(mixes); + DEREncodable mixes = pemDecoder.decode(topCrlStr, X509CRL.class); + entries.add(mixes); - is = new ByteArrayInputStream(subCrlStr.getBytes()); - mixes = cf.generateCRLs(is); - entries.addAll(mixes); + mixes = pemDecoder.decode(subCrlStr, X509CRL.class); + entries.add(mixes); return CertStore.getInstance("Collection", - new CollectionCertStoreParameters(entries)); + new CollectionCertStoreParameters(entries)); } private static X509CertSelector generateSelector(String name) @@ -245,17 +243,16 @@ public final class StatusLoopDependency { X509CertSelector selector = new X509CertSelector(); // generate certificate from certificate string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream is = null; + String cert; if (name.equals("subca")) { - is = new ByteArrayInputStream(subCaCertStr.getBytes()); + cert = subCaCertStr; } else if (name.equals("subci")) { - is = new ByteArrayInputStream(subCrlIssuerCertStr.getBytes()); + cert = subCrlIssuerCertStr; } else { - is = new ByteArrayInputStream(targetCertStr.getBytes()); + cert = targetCertStr; } - X509Certificate target = (X509Certificate)cf.generateCertificate(is); + X509Certificate target = pemDecoder.decode(cert, X509Certificate.class); byte[] extVal = target.getExtensionValue("2.5.29.14"); if (extVal != null) { DerInputStream in = new DerInputStream(extVal); @@ -269,21 +266,18 @@ public final class StatusLoopDependency { return selector; } - private static boolean match(String name, Certificate cert) - throws Exception { - X509CertSelector selector = new X509CertSelector(); + private static boolean match(String name, Certificate cert) { // generate certificate from certificate string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream is = null; + String newCert; if (name.equals("subca")) { - is = new ByteArrayInputStream(subCaCertStr.getBytes()); + newCert = subCaCertStr; } else if (name.equals("subci")) { - is = new ByteArrayInputStream(subCrlIssuerCertStr.getBytes()); + newCert = subCrlIssuerCertStr; } else { - is = new ByteArrayInputStream(targetCertStr.getBytes()); + newCert = targetCertStr; } - X509Certificate target = (X509Certificate)cf.generateCertificate(is); + X509Certificate target = pemDecoder.decode(newCert, X509Certificate.class); return target.equals(cert); } diff --git a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevel.java b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevel.java index d67db44e396..c83f1bc1f5d 100644 --- a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevel.java +++ b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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,16 +32,34 @@ * * @bug 6720721 * @summary CRL check with circular depency support needed + * @enablePreview * @run main/othervm CircularCRLTwoLevel * @author Xuelei Fan */ -import java.io.*; -import java.net.SocketException; -import java.util.*; +import java.security.DEREncodable; +import java.security.PEMDecoder; import java.security.Security; -import java.security.cert.*; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException.BasicReason; +import java.security.cert.CertStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class CircularCRLTwoLevel { @@ -149,25 +167,19 @@ public class CircularCRLTwoLevel { "ARGr6Qu68MYGtLMC6ZqP3u0=\n" + "-----END X509 CRL-----"; + private static final PEMDecoder pemDecoder = PEMDecoder.of(); + private static CertPath generateCertificatePath() throws CertificateException { // generate certificate from cert strings CertificateFactory cf = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream is; - - is = new ByteArrayInputStream(targetCertStr.getBytes()); - Certificate targetCert = cf.generateCertificate(is); - - is = new ByteArrayInputStream(subCaCertStr.getBytes()); - Certificate subCaCert = cf.generateCertificate(is); - - is = new ByteArrayInputStream(selfSignedCertStr.getBytes()); - Certificate selfSignedCert = cf.generateCertificate(is); + Certificate targetCert = pemDecoder.decode(targetCertStr, X509Certificate.class); + Certificate subCaCert = pemDecoder.decode(subCaCertStr, X509Certificate.class); + Certificate selfSignedCert = pemDecoder.decode(selfSignedCertStr, X509Certificate.class); // generate certification path - List list = Arrays.asList(new Certificate[] { - targetCert, subCaCert, selfSignedCert}); + List list = Arrays.asList(targetCert, subCaCert, selfSignedCert); return cf.generateCertPath(list); } @@ -175,42 +187,33 @@ public class CircularCRLTwoLevel { private static Set generateTrustAnchors() throws CertificateException { // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream is = - new ByteArrayInputStream(selfSignedCertStr.getBytes()); - Certificate selfSignedCert = cf.generateCertificate(is); + final X509Certificate selfSignedCert = pemDecoder.decode(selfSignedCertStr, X509Certificate.class); // generate a trust anchor TrustAnchor anchor = - new TrustAnchor((X509Certificate)selfSignedCert, null); + new TrustAnchor(selfSignedCert, null); return Collections.singleton(anchor); } private static CertStore generateCertificateStore() throws Exception { - Collection entries = new HashSet(); + Collection entries = new HashSet<>(); // generate CRL from CRL string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream is = - new ByteArrayInputStream(topCrlStr.getBytes()); - Collection mixes = cf.generateCRLs(is); - entries.addAll(mixes); + DEREncodable mixes = pemDecoder.decode(topCrlStr, X509CRL.class); + entries.add(mixes); - is = new ByteArrayInputStream(subCrlStr.getBytes()); - mixes = cf.generateCRLs(is); - entries.addAll(mixes); + mixes = pemDecoder.decode(subCrlStr, X509CRL.class); + entries.add(mixes); // intermediate certs - is = new ByteArrayInputStream(topCrlIssuerCertStr.getBytes()); - mixes = cf.generateCertificates(is); - entries.addAll(mixes); + mixes = pemDecoder.decode(topCrlIssuerCertStr, X509Certificate.class); + entries.add(mixes); - is = new ByteArrayInputStream(subCrlIssuerCertStr.getBytes()); - mixes = cf.generateCertificates(is); - entries.addAll(mixes); + mixes = pemDecoder.decode(subCrlIssuerCertStr, X509Certificate.class); + entries.add(mixes); return CertStore.getInstance("Collection", new CollectionCertStoreParameters(entries)); diff --git a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevelRevoked.java b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevelRevoked.java index e67934b8a19..7ac63072737 100644 --- a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevelRevoked.java +++ b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevelRevoked.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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,16 +32,34 @@ * * @bug 6720721 * @summary CRL check with circular depency support needed + * @enablePreview * @run main/othervm CircularCRLTwoLevelRevoked * @author Xuelei Fan */ -import java.io.*; -import java.net.SocketException; -import java.util.*; +import java.security.DEREncodable; +import java.security.PEMDecoder; import java.security.Security; -import java.security.cert.*; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException.BasicReason; +import java.security.cert.CertStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class CircularCRLTwoLevelRevoked { @@ -150,25 +168,19 @@ public class CircularCRLTwoLevelRevoked { "ARGr6Qu68MYGtLMC6ZqP3u0=\n" + "-----END X509 CRL-----"; + private static final PEMDecoder pemDecoder = PEMDecoder.of(); + private static CertPath generateCertificatePath() throws CertificateException { // generate certificate from cert strings CertificateFactory cf = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream is; - - is = new ByteArrayInputStream(targetCertStr.getBytes()); - Certificate targetCert = cf.generateCertificate(is); - - is = new ByteArrayInputStream(subCaCertStr.getBytes()); - Certificate subCaCert = cf.generateCertificate(is); - - is = new ByteArrayInputStream(selfSignedCertStr.getBytes()); - Certificate selfSignedCert = cf.generateCertificate(is); + Certificate targetCert = pemDecoder.decode(targetCertStr, X509Certificate.class); + Certificate subCaCert = pemDecoder.decode(subCaCertStr, X509Certificate.class); + Certificate selfSignedCert = pemDecoder.decode(selfSignedCertStr, X509Certificate.class); // generate certification path - List list = Arrays.asList(new Certificate[] { - targetCert, subCaCert, selfSignedCert}); + List list = Arrays.asList(targetCert, subCaCert, selfSignedCert); return cf.generateCertPath(list); } @@ -176,45 +188,36 @@ public class CircularCRLTwoLevelRevoked { private static Set generateTrustAnchors() throws CertificateException { // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - ByteArrayInputStream is = - new ByteArrayInputStream(selfSignedCertStr.getBytes()); - Certificate selfSignedCert = cf.generateCertificate(is); + final X509Certificate selfSignedCert = pemDecoder.decode(selfSignedCertStr, X509Certificate.class); // generate a trust anchor TrustAnchor anchor = - new TrustAnchor((X509Certificate)selfSignedCert, null); + new TrustAnchor(selfSignedCert, null); return Collections.singleton(anchor); } private static CertStore generateCertificateStore() throws Exception { - Collection entries = new HashSet(); + Collection entries = new HashSet<>(); // generate CRL from CRL string CertificateFactory cf = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream is = - new ByteArrayInputStream(topCrlStr.getBytes()); - Collection mixes = cf.generateCRLs(is); - entries.addAll(mixes); + DEREncodable mixes = pemDecoder.decode(topCrlStr, X509CRL.class); + entries.add(mixes); - is = new ByteArrayInputStream(subCrlStr.getBytes()); - mixes = cf.generateCRLs(is); - entries.addAll(mixes); + mixes = pemDecoder.decode(subCrlStr, X509CRL.class); + entries.add(mixes); // intermediate certs - is = new ByteArrayInputStream(topCrlIssuerCertStr.getBytes()); - mixes = cf.generateCertificates(is); - entries.addAll(mixes); + mixes = pemDecoder.decode(topCrlIssuerCertStr, X509Certificate.class); + entries.add(mixes); - is = new ByteArrayInputStream(subCrlIssuerCertStr.getBytes()); - mixes = cf.generateCertificates(is); - entries.addAll(mixes); + mixes = pemDecoder.decode(subCrlIssuerCertStr, X509Certificate.class); + entries.add(mixes); return CertStore.getInstance("Collection", - new CollectionCertStoreParameters(entries)); + new CollectionCertStoreParameters(entries)); } public static void main(String args[]) throws Exception { diff --git a/test/jdk/javax/net/ssl/ServerName/SSLSocketSNISensitive.java b/test/jdk/javax/net/ssl/ServerName/SSLSocketSNISensitive.java index 45593b9129e..fd1569b4eea 100644 --- a/test/jdk/javax/net/ssl/ServerName/SSLSocketSNISensitive.java +++ b/test/jdk/javax/net/ssl/ServerName/SSLSocketSNISensitive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +30,7 @@ * @test * @bug 7068321 * @summary Support TLS Server Name Indication (SNI) Extension in JSSE Server + * @enablePreview * @run main/othervm SSLSocketSNISensitive PKIX www.example.com * @run main/othervm SSLSocketSNISensitive SunX509 www.example.com * @run main/othervm SSLSocketSNISensitive PKIX www.example.net @@ -38,19 +39,31 @@ * @run main/othervm SSLSocketSNISensitive SunX509 www.invalid.com */ -import java.net.*; -import java.util.*; -import java.io.*; -import javax.net.ssl.*; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.PEMDecoder; +import java.security.PEMEncoder; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIServerName; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; import java.security.Security; import java.security.KeyStore; import java.security.KeyFactory; import java.security.cert.Certificate; import java.security.cert.X509Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; +import java.util.ArrayList; import java.util.Base64; +import java.util.List; // Note: this test case works only on TLS 1.2 and prior versions because of // the use of MD5withRSA signed certificate. @@ -74,159 +87,167 @@ public class SSLSocketSNISensitive { */ // Certificates and key used in the test. static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTIwNDE3MTIwNjA3WhcNMzMwMzI4MTIwNjA3WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + - "KoZIhvcNAQEBBQADgY0AMIGJAoGBANY+7Enp+1S566kLcKk+qe4Ki6BxaHGZ+v7r\n" + - "vLksx9IQZCbAEf4YLbrZhKzKD3SPIJXyxPFwknAknIh3Knk8mViOZks7T8L3GnJr\n" + - "TBaVvDyTzDJum/QYiahfO2qpfN/Oya2UILmqsBAeLyWpzbQsAyWBXfoUtkOUgnzK\n" + - "fk6QAKYrAgMBAAGjgaUwgaIwHQYDVR0OBBYEFEtmQi7jT1ijXOafPsfkrLwSVu9e\n" + - "MGMGA1UdIwRcMFqAFEtmQi7jT1ijXOafPsfkrLwSVu9eoT+kPTA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + - "BQADgYEAkKWxMc4+ODk5WwLXXweB8/IKfVfrizNn0KLEgsZ6xNXFIXDpiPGAFcgl\n" + - "MzFO424JgyvUulsUc/X16Cnuwwntkk6KUG7vEV7h4o9sAV7Cax3gfQE/EZFb4ybn\n" + - "aBm1UsujMKd/ovqbbbxJbmOWzCeo0QfIGleDEyh3NBBZ0i11Kiw=\n" + - "-----END CERTIFICATE-----"; + "-----BEGIN CERTIFICATE-----\n" + + "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTIwNDE3MTIwNjA3WhcNMzMwMzI4MTIwNjA3WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + + "KoZIhvcNAQEBBQADgY0AMIGJAoGBANY+7Enp+1S566kLcKk+qe4Ki6BxaHGZ+v7r\n" + + "vLksx9IQZCbAEf4YLbrZhKzKD3SPIJXyxPFwknAknIh3Knk8mViOZks7T8L3GnJr\n" + + "TBaVvDyTzDJum/QYiahfO2qpfN/Oya2UILmqsBAeLyWpzbQsAyWBXfoUtkOUgnzK\n" + + "fk6QAKYrAgMBAAGjgaUwgaIwHQYDVR0OBBYEFEtmQi7jT1ijXOafPsfkrLwSVu9e\n" + + "MGMGA1UdIwRcMFqAFEtmQi7jT1ijXOafPsfkrLwSVu9eoT+kPTA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + + "BQADgYEAkKWxMc4+ODk5WwLXXweB8/IKfVfrizNn0KLEgsZ6xNXFIXDpiPGAFcgl\n" + + "MzFO424JgyvUulsUc/X16Cnuwwntkk6KUG7vEV7h4o9sAV7Cax3gfQE/EZFb4ybn\n" + + "aBm1UsujMKd/ovqbbbxJbmOWzCeo0QfIGleDEyh3NBBZ0i11Kiw=\n" + + "-----END CERTIFICATE-----"; // web server certificate, www.example.com static String targetCertStr_A = - "-----BEGIN CERTIFICATE-----\n" + - "MIICVTCCAb6gAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTIwNDE3MTIwNjA4WhcNMzIwMTAzMTIwNjA4WjBVMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" + - "BAMTD3d3dy5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + - "4zFp3PZNzsd3ZwG6FNNWO9eSN+UBymlf8oCwpKJM2tIinmMWvWIXnlx/2UXIfSAq\n" + - "QEG3aXkAFyEiGGpQlBbqcfrESsHsiz2pnnm5dG2v/eS0Bwz1jmcuNmwnh3UQw2Vl\n" + - "+BLk8ukdrLjiCT8jARiHExYf1Xg+wUqQ9y8NV26hdaUCAwEAAaNPME0wCwYDVR0P\n" + - "BAQDAgPoMB0GA1UdDgQWBBQwtx+gqzn2w4y82brXlp7tqBYEZDAfBgNVHSMEGDAW\n" + - "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQAJWo8B6Ud+\n" + - "/OU+UcZLihlfMX02OSlK2ZB7mfqpj2G3JT9yb0A+VbY3uuajmaYYIIxl3kXGz/n8\n" + - "M2Q/Ux/MDxG+IFKHC26Kuj4dAQgzjq2pILVPTE2QnaQTNCsgVZtTaC47SG9FRSoC\n" + - "qvnIvn/oTpKSqus76I1cR4joDtiV2OEuVw==\n" + - "-----END CERTIFICATE-----"; + "-----BEGIN CERTIFICATE-----\n" + + "MIICVTCCAb6gAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTIwNDE3MTIwNjA4WhcNMzIwMTAzMTIwNjA4WjBVMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" + + "BAMTD3d3dy5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + + "4zFp3PZNzsd3ZwG6FNNWO9eSN+UBymlf8oCwpKJM2tIinmMWvWIXnlx/2UXIfSAq\n" + + "QEG3aXkAFyEiGGpQlBbqcfrESsHsiz2pnnm5dG2v/eS0Bwz1jmcuNmwnh3UQw2Vl\n" + + "+BLk8ukdrLjiCT8jARiHExYf1Xg+wUqQ9y8NV26hdaUCAwEAAaNPME0wCwYDVR0P\n" + + "BAQDAgPoMB0GA1UdDgQWBBQwtx+gqzn2w4y82brXlp7tqBYEZDAfBgNVHSMEGDAW\n" + + "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQAJWo8B6Ud+\n" + + "/OU+UcZLihlfMX02OSlK2ZB7mfqpj2G3JT9yb0A+VbY3uuajmaYYIIxl3kXGz/n8\n" + + "M2Q/Ux/MDxG+IFKHC26Kuj4dAQgzjq2pILVPTE2QnaQTNCsgVZtTaC47SG9FRSoC\n" + + "qvnIvn/oTpKSqus76I1cR4joDtiV2OEuVw==\n" + + "-----END CERTIFICATE-----"; // Private key in the format of PKCS#8 static String targetPrivateKey_A = - "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOMxadz2Tc7Hd2cB\n" + - "uhTTVjvXkjflAcppX/KAsKSiTNrSIp5jFr1iF55cf9lFyH0gKkBBt2l5ABchIhhq\n" + - "UJQW6nH6xErB7Is9qZ55uXRtr/3ktAcM9Y5nLjZsJ4d1EMNlZfgS5PLpHay44gk/\n" + - "IwEYhxMWH9V4PsFKkPcvDVduoXWlAgMBAAECgYAqX2nuIyXp3fvgA0twXOYlbRRB\n" + - "Rn3qAXM6qFPJsNeCrFR2k+aG1cev6nKR1FkLNTeMGnWZv06MAcr5IML8i7WXyG4C\n" + - "LY/C0gedn94FDKFlln+bTENwQTGjn4lKysDA+IuNpasTeMCajbic+dPByhIdTOjZ\n" + - "iMCyxbLfpk40zQopVQJBAPyfGmkeHB3GjdbdgujWCGKb2UxBa4O8dy3O4l2yizTn\n" + - "uUqMGcwGY4ciNSVvZQ7jKo4vDmkSuYib4/woPChaNfMCQQDmO0BQuSWYGNtSwV35\n" + - "lafZfX1dNCLKm1iNA6A12evXgvQiE9WT4mqionig0VZW16HtiY4/BkHOcos/K9Um\n" + - "ARQHAkA8mkaRtSF1my5nv1gqVz5Hua+VdZQ/VDUbDiiL5cszc+ulkJqXsWirAG/T\n" + - "fTe3LJQG7A7+8fkEZrF4yoY0AAA1AkEAotokezULj5N9iAL5SzL9wIzQYV4ggfny\n" + - "YATBjXXxKccakwQ+ndWZIiMUeoS4ssLialhTgucVI0fIkU2a/r/ifwJAc6e+5Pvh\n" + - "MghQj/U788Od/v6rgqz/NGsduZ7uilCMcWiwA73OR2MHMH/OIuoofuEPrfuV9isV\n" + - "xVXhgpKfP/pdOA=="; + "-----BEGIN PRIVATE KEY-----\n" + + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOMxadz2Tc7Hd2cB\n" + + "uhTTVjvXkjflAcppX/KAsKSiTNrSIp5jFr1iF55cf9lFyH0gKkBBt2l5ABchIhhq\n" + + "UJQW6nH6xErB7Is9qZ55uXRtr/3ktAcM9Y5nLjZsJ4d1EMNlZfgS5PLpHay44gk/\n" + + "IwEYhxMWH9V4PsFKkPcvDVduoXWlAgMBAAECgYAqX2nuIyXp3fvgA0twXOYlbRRB\n" + + "Rn3qAXM6qFPJsNeCrFR2k+aG1cev6nKR1FkLNTeMGnWZv06MAcr5IML8i7WXyG4C\n" + + "LY/C0gedn94FDKFlln+bTENwQTGjn4lKysDA+IuNpasTeMCajbic+dPByhIdTOjZ\n" + + "iMCyxbLfpk40zQopVQJBAPyfGmkeHB3GjdbdgujWCGKb2UxBa4O8dy3O4l2yizTn\n" + + "uUqMGcwGY4ciNSVvZQ7jKo4vDmkSuYib4/woPChaNfMCQQDmO0BQuSWYGNtSwV35\n" + + "lafZfX1dNCLKm1iNA6A12evXgvQiE9WT4mqionig0VZW16HtiY4/BkHOcos/K9Um\n" + + "ARQHAkA8mkaRtSF1my5nv1gqVz5Hua+VdZQ/VDUbDiiL5cszc+ulkJqXsWirAG/T\n" + + "fTe3LJQG7A7+8fkEZrF4yoY0AAA1AkEAotokezULj5N9iAL5SzL9wIzQYV4ggfny\n" + + "YATBjXXxKccakwQ+ndWZIiMUeoS4ssLialhTgucVI0fIkU2a/r/ifwJAc6e+5Pvh\n" + + "MghQj/U788Od/v6rgqz/NGsduZ7uilCMcWiwA73OR2MHMH/OIuoofuEPrfuV9isV\n" + + "xVXhgpKfP/pdOA==\n" + + "-----END PRIVATE KEY-----"; // web server certificate, www.example.net static String targetCertStr_B = - "-----BEGIN CERTIFICATE-----\n" + - "MIICVTCCAb6gAwIBAgIBBDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTIwNDE3MTIwNjA5WhcNMzIwMTAzMTIwNjA5WjBVMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" + - "BAMTD3d3dy5leGFtcGxlLm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + - "2VlzF1fvWYczDChrUeJiLJ1M/dIShCaOTfYGiXfQGEZCAWTacUclwr+rVMnZ75/c\n" + - "wwg5pNdXRijxMil8DBTS1gFcIFQhosLHvzIAe6ULlg/xB+/L6KBz+NTWfo/2KF6t\n" + - "xatmcToNrCcwi7eUOfbzQje65Tizs56jJYem2m7Rk0ECAwEAAaNPME0wCwYDVR0P\n" + - "BAQDAgPoMB0GA1UdDgQWBBQT/FR0cAWcZQ7h0X79KGki34OSQjAfBgNVHSMEGDAW\n" + - "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQB67cPIT6fz\n" + - "6Ws8fBpYgW2ad4ci66i1WduBD9CpGFE+jRK2feRj6hvYBXocKj0AMWUFIEB2E3hA\n" + - "oIjxcf1GxIpHVl9DjlhxqXbA0Ktl7/NGNRlDSLTizOTl3FB1mMTlOGvXDVmpcFhl\n" + - "HuoP1hYvhTsBwPx5igGNchuPtDIUzL2mXw==\n" + - "-----END CERTIFICATE-----"; + "-----BEGIN CERTIFICATE-----\n" + + "MIICVTCCAb6gAwIBAgIBBDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTIwNDE3MTIwNjA5WhcNMzIwMTAzMTIwNjA5WjBVMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" + + "BAMTD3d3dy5leGFtcGxlLm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + + "2VlzF1fvWYczDChrUeJiLJ1M/dIShCaOTfYGiXfQGEZCAWTacUclwr+rVMnZ75/c\n" + + "wwg5pNdXRijxMil8DBTS1gFcIFQhosLHvzIAe6ULlg/xB+/L6KBz+NTWfo/2KF6t\n" + + "xatmcToNrCcwi7eUOfbzQje65Tizs56jJYem2m7Rk0ECAwEAAaNPME0wCwYDVR0P\n" + + "BAQDAgPoMB0GA1UdDgQWBBQT/FR0cAWcZQ7h0X79KGki34OSQjAfBgNVHSMEGDAW\n" + + "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQB67cPIT6fz\n" + + "6Ws8fBpYgW2ad4ci66i1WduBD9CpGFE+jRK2feRj6hvYBXocKj0AMWUFIEB2E3hA\n" + + "oIjxcf1GxIpHVl9DjlhxqXbA0Ktl7/NGNRlDSLTizOTl3FB1mMTlOGvXDVmpcFhl\n" + + "HuoP1hYvhTsBwPx5igGNchuPtDIUzL2mXw==\n" + + "-----END CERTIFICATE-----"; static String targetPrivateKey_B = - "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANlZcxdX71mHMwwo\n" + - "a1HiYiydTP3SEoQmjk32Bol30BhGQgFk2nFHJcK/q1TJ2e+f3MMIOaTXV0Yo8TIp\n" + - "fAwU0tYBXCBUIaLCx78yAHulC5YP8Qfvy+igc/jU1n6P9ihercWrZnE6DawnMIu3\n" + - "lDn280I3uuU4s7OeoyWHptpu0ZNBAgMBAAECgYEAl19H26sfhD+32rDPxZCgBShs\n" + - "dZ33zVe45i0Bcn4iTLWpxKTDyf7eGps4rO2DvfKdYqt40ggzvSZIjUH9JcDe8GmG\n" + - "d3m0ILB7pg4jsFlpyeHpTO8grPLxA1G9s3o0DoFpz/rooqgFfe/DrRDmRoOSkgfV\n" + - "/gseIbgJHRO/Ctyvdh0CQQD6uFd0HxhH1jl/JzvPzIH4LSnPcdEh9zsMEb6uzh75\n" + - "9qL+IHD5N2I/pYZTKqDFIwhJf701+LKag55AX/zrDt7rAkEA3e00AbnwanDMa6Wj\n" + - "+gFekUQveSVra38LiihzCkyVvQpFjbiF1rUhSNQ0dpU5/hmrYF0C6H9VXAesfkUY\n" + - "WhpDgwJAYjgZOop77piDycZK7isFt32p5XSHIzFBVocVFlH1XKM8UyXOXDNQL/Le\n" + - "XnJSrSf+NRzvuNcG0PVC56Ey6brXpQJAY4M4vcltt5zq3R5CQBmbGRJ1IyKXX3Vx\n" + - "bDslEqoyvri7ZYgnY5aG3UxiVgYmIf3KrgQnCLAIS6MZQumiuMxsFwJAK5pEG063\n" + - "9ngUof4fDMvZphqZjZR1zMKz/V/9ge0DWBINaqFgsgebNu+MyImsC8C6WKjGmV/2\n" + - "f1MY0D7sC2vU/Q=="; + "-----BEGIN PRIVATE KEY-----\n" + + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANlZcxdX71mHMwwo\n" + + "a1HiYiydTP3SEoQmjk32Bol30BhGQgFk2nFHJcK/q1TJ2e+f3MMIOaTXV0Yo8TIp\n" + + "fAwU0tYBXCBUIaLCx78yAHulC5YP8Qfvy+igc/jU1n6P9ihercWrZnE6DawnMIu3\n" + + "lDn280I3uuU4s7OeoyWHptpu0ZNBAgMBAAECgYEAl19H26sfhD+32rDPxZCgBShs\n" + + "dZ33zVe45i0Bcn4iTLWpxKTDyf7eGps4rO2DvfKdYqt40ggzvSZIjUH9JcDe8GmG\n" + + "d3m0ILB7pg4jsFlpyeHpTO8grPLxA1G9s3o0DoFpz/rooqgFfe/DrRDmRoOSkgfV\n" + + "/gseIbgJHRO/Ctyvdh0CQQD6uFd0HxhH1jl/JzvPzIH4LSnPcdEh9zsMEb6uzh75\n" + + "9qL+IHD5N2I/pYZTKqDFIwhJf701+LKag55AX/zrDt7rAkEA3e00AbnwanDMa6Wj\n" + + "+gFekUQveSVra38LiihzCkyVvQpFjbiF1rUhSNQ0dpU5/hmrYF0C6H9VXAesfkUY\n" + + "WhpDgwJAYjgZOop77piDycZK7isFt32p5XSHIzFBVocVFlH1XKM8UyXOXDNQL/Le\n" + + "XnJSrSf+NRzvuNcG0PVC56Ey6brXpQJAY4M4vcltt5zq3R5CQBmbGRJ1IyKXX3Vx\n" + + "bDslEqoyvri7ZYgnY5aG3UxiVgYmIf3KrgQnCLAIS6MZQumiuMxsFwJAK5pEG063\n" + + "9ngUof4fDMvZphqZjZR1zMKz/V/9ge0DWBINaqFgsgebNu+MyImsC8C6WKjGmV/2\n" + + "f1MY0D7sC2vU/Q==\n" + + "-----END PRIVATE KEY-----"; // web server certificate, www.invalid.com static String targetCertStr_C = - "-----BEGIN CERTIFICATE-----\n" + - "MIICVTCCAb6gAwIBAgIBAzANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTIwNDE3MTIwNjA5WhcNMzIwMTAzMTIwNjA5WjBVMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" + - "BAMTD3d3dy5pbnZhbGlkLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + - "q6MyQwzCr2nJ41l0frmHL0qULSyW51MhevBC+1W28i0LE/efrmpwV3LdnlQEGFak\n" + - "DLDwtnff3iru8dSMcA7KdWVkivsE7ZTP+qFDaWBAy7XXiSsv6yZ2Nh4jJb0YcD28\n" + - "45zk2nAl5Az1/PuoTi1vpQxzFZKuBm1HGgz3MEZvBvMCAwEAAaNPME0wCwYDVR0P\n" + - "BAQDAgPoMB0GA1UdDgQWBBRRMifrND015Nm8N6gV5X7cg1YjjjAfBgNVHSMEGDAW\n" + - "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQBjkUO6Ri/B\n" + - "uDC2gDMIyL5+NTe/1dPPQYM4HhCNa/KQYvU5lzCKO9Vpa+i+nyrUNNXUu8Tkyq4Y\n" + - "A+aGSm6+FT/i9rFwkYUdorBtD3KfQiwTIWrVERXBkWI5iZNaVZhx0TFy4vUpf65d\n" + - "QtwkbHpC66fdKc2EdLXkuY9KkmtZZJJ7YA==\n" + - "-----END CERTIFICATE-----"; + "-----BEGIN CERTIFICATE-----\n" + + "MIICVTCCAb6gAwIBAgIBAzANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTIwNDE3MTIwNjA5WhcNMzIwMTAzMTIwNjA5WjBVMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" + + "BAMTD3d3dy5pbnZhbGlkLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + + "q6MyQwzCr2nJ41l0frmHL0qULSyW51MhevBC+1W28i0LE/efrmpwV3LdnlQEGFak\n" + + "DLDwtnff3iru8dSMcA7KdWVkivsE7ZTP+qFDaWBAy7XXiSsv6yZ2Nh4jJb0YcD28\n" + + "45zk2nAl5Az1/PuoTi1vpQxzFZKuBm1HGgz3MEZvBvMCAwEAAaNPME0wCwYDVR0P\n" + + "BAQDAgPoMB0GA1UdDgQWBBRRMifrND015Nm8N6gV5X7cg1YjjjAfBgNVHSMEGDAW\n" + + "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQBjkUO6Ri/B\n" + + "uDC2gDMIyL5+NTe/1dPPQYM4HhCNa/KQYvU5lzCKO9Vpa+i+nyrUNNXUu8Tkyq4Y\n" + + "A+aGSm6+FT/i9rFwkYUdorBtD3KfQiwTIWrVERXBkWI5iZNaVZhx0TFy4vUpf65d\n" + + "QtwkbHpC66fdKc2EdLXkuY9KkmtZZJJ7YA==\n" + + "-----END CERTIFICATE-----"; static String targetPrivateKey_C = - "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKujMkMMwq9pyeNZ\n" + - "dH65hy9KlC0sludTIXrwQvtVtvItCxP3n65qcFdy3Z5UBBhWpAyw8LZ3394q7vHU\n" + - "jHAOynVlZIr7BO2Uz/qhQ2lgQMu114krL+smdjYeIyW9GHA9vOOc5NpwJeQM9fz7\n" + - "qE4tb6UMcxWSrgZtRxoM9zBGbwbzAgMBAAECgYASJDK40Y12Wvki1Z6xkkyOnBRj\n" + - "XfYpRykfxGtgA2RN3qLwHlk7Zzaul46DIKA6LlYynTUkJDF+Ww1cdDnP0lBlwcmM\n" + - "iD0ck3zYyYBLhQHuVbkK3SYE+ANRhM0icvvqANP2at/U4awQcPNEae/KCiecLNu3\n" + - "CJGqyhPDdrEAqPuJGQJBAN46pQC6l3yrcSYE2s53jSmsm2HVVOFlFXjU6k/RMTxG\n" + - "FfDJtGUAOQ37rPQ06ugr/gjLAmmPp+FXozaBdA32D80CQQDFuGRgv3WYqbglIcRL\n" + - "JRs6xlj9w1F97s/aiUenuwhIPNiUoRbV7mnNuZ/sGF0svOVE7SazRjuFX6UqL9Y9\n" + - "HzG/AkEA170pCI8cl4w8eUNHRB9trGKEKjMXhwVCFh7lJf2ZBcGodSzr8w2HVhrZ\n" + - "Ke7hiemDYffrbJ1oxmv05+o+x3r0lQJBAL6adVm2+FyFMFnLZXmzeb59O4jWY5bt\n" + - "Qz6/HG6bpO5OidMuP99YCHMkQQDOs/PO3Y5GuAoW6IY4n/Y9S2B80+0CQBl1/H9/\n" + - "0n/vrb6vW6Azds49tuS82RFAnOhtwTyBEajs08WF8rZQ3WD2RHJnH0+jjfL0anIp\n" + - "dQBSeNN7s7b6rRk="; + "-----BEGIN PRIVATE KEY-----\n" + + "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKujMkMMwq9pyeNZ\n" + + "dH65hy9KlC0sludTIXrwQvtVtvItCxP3n65qcFdy3Z5UBBhWpAyw8LZ3394q7vHU\n" + + "jHAOynVlZIr7BO2Uz/qhQ2lgQMu114krL+smdjYeIyW9GHA9vOOc5NpwJeQM9fz7\n" + + "qE4tb6UMcxWSrgZtRxoM9zBGbwbzAgMBAAECgYASJDK40Y12Wvki1Z6xkkyOnBRj\n" + + "XfYpRykfxGtgA2RN3qLwHlk7Zzaul46DIKA6LlYynTUkJDF+Ww1cdDnP0lBlwcmM\n" + + "iD0ck3zYyYBLhQHuVbkK3SYE+ANRhM0icvvqANP2at/U4awQcPNEae/KCiecLNu3\n" + + "CJGqyhPDdrEAqPuJGQJBAN46pQC6l3yrcSYE2s53jSmsm2HVVOFlFXjU6k/RMTxG\n" + + "FfDJtGUAOQ37rPQ06ugr/gjLAmmPp+FXozaBdA32D80CQQDFuGRgv3WYqbglIcRL\n" + + "JRs6xlj9w1F97s/aiUenuwhIPNiUoRbV7mnNuZ/sGF0svOVE7SazRjuFX6UqL9Y9\n" + + "HzG/AkEA170pCI8cl4w8eUNHRB9trGKEKjMXhwVCFh7lJf2ZBcGodSzr8w2HVhrZ\n" + + "Ke7hiemDYffrbJ1oxmv05+o+x3r0lQJBAL6adVm2+FyFMFnLZXmzeb59O4jWY5bt\n" + + "Qz6/HG6bpO5OidMuP99YCHMkQQDOs/PO3Y5GuAoW6IY4n/Y9S2B80+0CQBl1/H9/\n" + + "0n/vrb6vW6Azds49tuS82RFAnOhtwTyBEajs08WF8rZQ3WD2RHJnH0+jjfL0anIp\n" + + "dQBSeNN7s7b6rRk=\n" + + "-----END PRIVATE KEY-----"; // This is a certificate for client - static String targetCertStr_D= - "-----BEGIN CERTIFICATE-----\n" + - "MIICVDCCAb2gAwIBAgIBBTANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTIwNDE3MTIwNjEwWhcNMzIwMTAzMTIwNjEwWjBUMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxFzAVBgNV\n" + - "BAMTDkludGVyT3AgVGVzdGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDo\n" + - "Q/KoAIAC2ljFfW2KwjnxTzi4NQJeUuk2seqKpsAY8x4O5dvixzUl6142zmljapqi\n" + - "bJloQVpfB+CEc5/l4h5gzGRVzkuqP1oPzDrpZ5GsvmvuHenV/TzCIgX1cLETzQVt\n" + - "6Rk06okoBPnw3hDJEJiEc1Rv7HCE8p/p+SaiHrskwwIDAQABo08wTTALBgNVHQ8E\n" + - "BAMCA+gwHQYDVR0OBBYEFPr91O33RIGfFSqza2AwQIgE4QswMB8GA1UdIwQYMBaA\n" + - "FEtmQi7jT1ijXOafPsfkrLwSVu9eMA0GCSqGSIb3DQEBBAUAA4GBANIDFYgAhoj3\n" + - "B8u1YpqeoEp2Lt9TwrYBshaIrbmBPCwCGio0JIsoov3n8BCSg5F+8MnOtPl+TjeO\n" + - "0Ug+7guPdCk/wg8YNxLHgSsQlpcNJDjWiErqmUPVrg5BPPQb65qMund6KTmMN0y6\n" + - "4EbSmxRpZO/N0/5oK4umTk0EeXKNekBj\n" + - "-----END CERTIFICATE-----"; + static String targetCertStr_D = + "-----BEGIN CERTIFICATE-----\n" + + "MIICVDCCAb2gAwIBAgIBBTANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTIwNDE3MTIwNjEwWhcNMzIwMTAzMTIwNjEwWjBUMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxFzAVBgNV\n" + + "BAMTDkludGVyT3AgVGVzdGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDo\n" + + "Q/KoAIAC2ljFfW2KwjnxTzi4NQJeUuk2seqKpsAY8x4O5dvixzUl6142zmljapqi\n" + + "bJloQVpfB+CEc5/l4h5gzGRVzkuqP1oPzDrpZ5GsvmvuHenV/TzCIgX1cLETzQVt\n" + + "6Rk06okoBPnw3hDJEJiEc1Rv7HCE8p/p+SaiHrskwwIDAQABo08wTTALBgNVHQ8E\n" + + "BAMCA+gwHQYDVR0OBBYEFPr91O33RIGfFSqza2AwQIgE4QswMB8GA1UdIwQYMBaA\n" + + "FEtmQi7jT1ijXOafPsfkrLwSVu9eMA0GCSqGSIb3DQEBBAUAA4GBANIDFYgAhoj3\n" + + "B8u1YpqeoEp2Lt9TwrYBshaIrbmBPCwCGio0JIsoov3n8BCSg5F+8MnOtPl+TjeO\n" + + "0Ug+7guPdCk/wg8YNxLHgSsQlpcNJDjWiErqmUPVrg5BPPQb65qMund6KTmMN0y6\n" + + "4EbSmxRpZO/N0/5oK4umTk0EeXKNekBj\n" + + "-----END CERTIFICATE-----"; static String targetPrivateKey_D = - "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOhD8qgAgALaWMV9\n" + - "bYrCOfFPOLg1Al5S6Tax6oqmwBjzHg7l2+LHNSXrXjbOaWNqmqJsmWhBWl8H4IRz\n" + - "n+XiHmDMZFXOS6o/Wg/MOulnkay+a+4d6dX9PMIiBfVwsRPNBW3pGTTqiSgE+fDe\n" + - "EMkQmIRzVG/scITyn+n5JqIeuyTDAgMBAAECgYBw37yIKp4LRONJLnhSq6sO+0n8\n" + - "Mz6waiiN/Q6XTQwj09pysQAYCGlqwSRrDAqpVsBJWO+Ae+oYLrLMi4hUZnwN75v3\n" + - "pe1nXlrD11RmPLXwBxqFxNSvAs2FgLHZEtwHI7Bn8KybT/8bGkQ8csLceInYtMDD\n" + - "MuTyy2KRk/pj60zIKQJBAPgebQiAH6viFQ88AwHaNvQhlUfwmSC1i6f8LVoeqaHC\n" + - "lnP0LJBwlyDeeEInhHrCR2ibnCB6I/Pig+49XQgabK8CQQDvpJwuGEbsOO+3rkJJ\n" + - "OpOw4toG0QJZdRnT6l8I6BlboQRZSfFh+lGGahvFXkxc4KdUpJ7QPtXU7HHk6Huk\n" + - "8RYtAkA9CW8VGj+wTuuTVdX/jKjcIa7RhbSFwWNbrcOSWdys+Gt+luCnn6rt4QyA\n" + - "aaxDbquWZkFgE+voQR7nap0KM0XtAkAznd0WAJymHM1lXt9gLoHJQ9N6TGKZKiPa\n" + - "BU1a+cMcfV4WbVrUo7oTnZ9Fr73681iXXq3mZOJh7lvJ1llreZIxAkBEnbiTgEf4\n" + - "tvku68jHcRbRPmdS7CBSWNEBaHLOm4pUSTcxVTKKMHw7vmM5/UYUxJ8QNKCYxn6O\n" + - "+vtiBwBawwzN"; + "-----BEGIN PRIVATE KEY-----\n" + + "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOhD8qgAgALaWMV9\n" + + "bYrCOfFPOLg1Al5S6Tax6oqmwBjzHg7l2+LHNSXrXjbOaWNqmqJsmWhBWl8H4IRz\n" + + "n+XiHmDMZFXOS6o/Wg/MOulnkay+a+4d6dX9PMIiBfVwsRPNBW3pGTTqiSgE+fDe\n" + + "EMkQmIRzVG/scITyn+n5JqIeuyTDAgMBAAECgYBw37yIKp4LRONJLnhSq6sO+0n8\n" + + "Mz6waiiN/Q6XTQwj09pysQAYCGlqwSRrDAqpVsBJWO+Ae+oYLrLMi4hUZnwN75v3\n" + + "pe1nXlrD11RmPLXwBxqFxNSvAs2FgLHZEtwHI7Bn8KybT/8bGkQ8csLceInYtMDD\n" + + "MuTyy2KRk/pj60zIKQJBAPgebQiAH6viFQ88AwHaNvQhlUfwmSC1i6f8LVoeqaHC\n" + + "lnP0LJBwlyDeeEInhHrCR2ibnCB6I/Pig+49XQgabK8CQQDvpJwuGEbsOO+3rkJJ\n" + + "OpOw4toG0QJZdRnT6l8I6BlboQRZSfFh+lGGahvFXkxc4KdUpJ7QPtXU7HHk6Huk\n" + + "8RYtAkA9CW8VGj+wTuuTVdX/jKjcIa7RhbSFwWNbrcOSWdys+Gt+luCnn6rt4QyA\n" + + "aaxDbquWZkFgE+voQR7nap0KM0XtAkAznd0WAJymHM1lXt9gLoHJQ9N6TGKZKiPa\n" + + "BU1a+cMcfV4WbVrUo7oTnZ9Fr73681iXXq3mZOJh7lvJ1llreZIxAkBEnbiTgEf4\n" + + "tvku68jHcRbRPmdS7CBSWNEBaHLOm4pUSTcxVTKKMHw7vmM5/UYUxJ8QNKCYxn6O\n" + + "+vtiBwBawwzN\n" + + "-----END PRIVATE KEY-----"; static String[] serverCerts = {targetCertStr_A, targetCertStr_B, targetCertStr_C}; @@ -235,7 +256,7 @@ public class SSLSocketSNISensitive { static String[] clientCerts = {targetCertStr_D}; static String[] clientKeys = {targetPrivateKey_D}; - static char passphrase[] = "passphrase".toCharArray(); + static char[] passphrase = "passphrase".toCharArray(); /* * Is the server ready to serve? @@ -245,7 +266,7 @@ public class SSLSocketSNISensitive { /* * Turn on SSL debugging? */ - static boolean debug = false; + static boolean debug = Boolean.getBoolean("test.debug"); /* * Define the server side of the test. @@ -362,19 +383,16 @@ public class SSLSocketSNISensitive { private static SSLContext generateSSLContext(boolean isClient) throws Exception { - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + final PEMDecoder pemDecoder = PEMDecoder.of(); // create a key store KeyStore ks = KeyStore.getInstance("JKS"); ks.load(null, null); - // import the trused cert - ByteArrayInputStream is = - new ByteArrayInputStream(trustedCertStr.getBytes()); - Certificate trusedCert = cf.generateCertificate(is); - is.close(); + // generate certificate from cert string + Certificate trusedCert = pemDecoder.decode(trustedCertStr, X509Certificate.class); + // import the trused cert ks.setCertificateEntry("RSA Export Signer", trusedCert); String[] certStrs = null; @@ -390,17 +408,14 @@ public class SSLSocketSNISensitive { for (int i = 0; i < certStrs.length; i++) { // generate the private key. String keySpecStr = keyStrs[i]; - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keySpecStr)); + PKCS8EncodedKeySpec priKeySpec = pemDecoder.decode(keySpecStr, PKCS8EncodedKeySpec.class); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); // generate certificate chain String keyCertStr = certStrs[i]; - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); + Certificate keyCert = pemDecoder.decode(keyCertStr, X509Certificate.class); Certificate[] chain = new Certificate[2]; chain[0] = keyCert; @@ -521,22 +536,20 @@ public class SSLSocketSNISensitive { void startServer(boolean newThread) throws Exception { if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died, because of " + e); - serverReady = true; - serverException = e; - } + serverThread = new Thread(() -> { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died, because of " + e); + serverReady = true; + serverException = e; } - }; + }); serverThread.start(); } else { try { @@ -551,19 +564,17 @@ public class SSLSocketSNISensitive { void startClient(boolean newThread) throws Exception { if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died, because of " + e); - clientException = e; - } + clientThread = new Thread(() -> { + try { + doClientSide(); + } catch (Exception e) { + /* + * Our client thread just died. + */ + System.err.println("Client died, because of " + e); + clientException = e; } - }; + }); clientThread.start(); } else { try { diff --git a/test/jdk/javax/net/ssl/interop/ClientHelloBufferUnderflowException.java b/test/jdk/javax/net/ssl/interop/ClientHelloBufferUnderflowException.java index ca5742f37b2..0b030c71459 100644 --- a/test/jdk/javax/net/ssl/interop/ClientHelloBufferUnderflowException.java +++ b/test/jdk/javax/net/ssl/interop/ClientHelloBufferUnderflowException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * @test * @bug 8215790 8219389 * @summary Verify exception + * @enablePreview * @library /test/lib * @modules java.base/sun.security.util * @run main/othervm ClientHelloBufferUnderflowException diff --git a/test/jdk/javax/net/ssl/interop/ClientHelloChromeInterOp.java b/test/jdk/javax/net/ssl/interop/ClientHelloChromeInterOp.java index f426cce33e3..bcdfa270394 100644 --- a/test/jdk/javax/net/ssl/interop/ClientHelloChromeInterOp.java +++ b/test/jdk/javax/net/ssl/interop/ClientHelloChromeInterOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * @test * @bug 8169362 * @summary Interop automated testing with Chrome + * @enablePreview * @library /test/lib * @modules jdk.crypto.ec * java.base/sun.security.util diff --git a/test/jdk/javax/net/ssl/interop/ClientHelloInterOp.java b/test/jdk/javax/net/ssl/interop/ClientHelloInterOp.java index c6bf74bd533..808d137223e 100644 --- a/test/jdk/javax/net/ssl/interop/ClientHelloInterOp.java +++ b/test/jdk/javax/net/ssl/interop/ClientHelloInterOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,17 +21,22 @@ * questions. */ -import javax.net.ssl.*; -import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.nio.*; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManagerFactory; +import java.nio.ByteBuffer; import java.security.KeyStore; +import java.security.PEMDecoder; +import java.security.PEMRecord; import java.security.PrivateKey; -import java.security.KeyFactory; import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.util.Base64; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.RSAPrivateKey; public abstract class ClientHelloInterOp { @@ -138,13 +143,16 @@ public abstract class ClientHelloInterOp { // // EC private key related to cert endEntityCertStrs[0]. // + "-----BEGIN PRIVATE KEY-----\n" + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgA3pmS+OrIjGyUv2F\n" + "K/PkyayJIePM2RTFYxNoQqmJGnihRANCAASHi9c1QnNQurh7t8A68XRaJZTpyWU4\n" + - "Ay6zUapMW9ydE84KGXyy5my+Sw7QKlmoveGNeZVf12nUVX+tQEYujVob", + "Ay6zUapMW9ydE84KGXyy5my+Sw7QKlmoveGNeZVf12nUVX+tQEYujVob\n" + + "-----END PRIVATE KEY-----", // // RSA private key related to cert endEntityCertStrs[1]. // + "-----BEGIN PRIVATE KEY-----\n" + "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfq0lpd8nYH8AW\n" + "8RL62e57JA9I0AFW72d8x1T40Q9qYn4UftwQXxnVKmvW+VCA3MKkNRWt+eZPvmsJ\n" + "qmDPmV0D37L7eF19TIeNkHPN/H7oYdcsHi7p5TY0BNru+pIs1twtx9nv9CaQWqDg\n" + @@ -170,8 +178,9 @@ public abstract class ClientHelloInterOp { "sZ2JRtyK3OV9RtL/MYmYzPLqm1Ah02+GXLVNnvKWmwKBgE8Ble8CzrXYuuPdGxXz\n" + "BZU6HnXQrmTUcgeze0tj8SDHzCfsGsaG6pHrVNkT7CKsRuCHTZLM0kXmUijLFKuP\n" + "5xyE257z4IbbEbs+tcbB3p28n4/47MzZkSR3kt8+FrsEMZq5oOHbFTGzgp9dhZCC\n" + - "dKUqlw5BPHdbxoWB/JpSHGCV" - }; + "dKUqlw5BPHdbxoWB/JpSHGCV\n" + + "-----END PRIVATE KEY-----" + }; // Private key names of endEntityPrivateKeys. private final static String[] endEntityPrivateKeyNames = { @@ -179,6 +188,8 @@ public abstract class ClientHelloInterOp { "RSA" }; + private static final PEMDecoder pemDecoder = PEMDecoder.of(); + /* * Run the test case. */ @@ -251,13 +262,9 @@ public abstract class ClientHelloInterOp { KeyStore ts = null; // trust store KeyStore ks = null; // key store - char passphrase[] = "passphrase".toCharArray(); - - // Generate certificate from cert string. - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + char[] passphrase = "passphrase".toCharArray(); // Import the trused certs. - ByteArrayInputStream is; if (trustedMaterials != null && trustedMaterials.length != 0) { ts = KeyStore.getInstance("JKS"); ts.load(null, null); @@ -266,13 +273,8 @@ public abstract class ClientHelloInterOp { new Certificate[trustedMaterials.length]; for (int i = 0; i < trustedMaterials.length; i++) { String trustedCertStr = trustedMaterials[i]; - - is = new ByteArrayInputStream(trustedCertStr.getBytes()); - try { - trustedCert[i] = cf.generateCertificate(is); - } finally { - is.close(); - } + // Generate certificate from cert string. + trustedCert[i] = pemDecoder.decode(trustedCertStr, X509Certificate.class); ts.setCertificateEntry("trusted-cert-" + i, trustedCert[i]); } @@ -295,21 +297,14 @@ public abstract class ClientHelloInterOp { String keyCertStr = keyMaterialCerts[i]; // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(keyMaterialKeys[i])); - KeyFactory kf = - KeyFactory.getInstance(keyMaterialKeyAlgs[i]); - PrivateKey priKey = kf.generatePrivate(priKeySpec); + PrivateKey priKey = switch (keyMaterialKeyAlgs[i]) { + case "RSA" -> pemDecoder.decode(keyMaterialKeys[i], RSAPrivateKey.class); + case "EC" -> pemDecoder.decode(keyMaterialKeys[i], ECPrivateKey.class); + default -> pemDecoder.decode(keyMaterialKeys[i], PrivateKey.class); + }; // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = null; - try { - keyCert = cf.generateCertificate(is); - } finally { - is.close(); - } - + Certificate keyCert = pemDecoder.decode(keyCertStr, X509Certificate.class); Certificate[] chain = new Certificate[] { keyCert }; // import the key entry. diff --git a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java index 63eaa12b00c..d74d712d8d7 100644 --- a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java +++ b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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,19 +31,35 @@ * @summary Disable MD2 support * new CertPathValidatorException.BasicReason enum constant for * constrained algorithm + * @enablePreview * @run main/othervm CPValidatorTrustAnchor * @author Xuelei Fan */ -import java.io.*; -import java.net.SocketException; -import java.util.*; +import java.io.ByteArrayInputStream; +import java.security.PEMDecoder; import java.security.Security; -import java.security.cert.*; -import java.security.cert.CertPathValidatorException.*; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorException.BasicReason; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Set; public class CPValidatorTrustAnchor { + private static final PEMDecoder pemDecoder = java.security.PEMDecoder.of(); + static String selfSignedCertStr = null; // SHA1withRSA 1024 @@ -104,33 +120,26 @@ public class CPValidatorTrustAnchor { private static CertPath generateCertificatePath() throws CertificateException { - // generate certificate from cert strings + CertificateFactory cf = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream is; - - is = new ByteArrayInputStream(selfSignedCertStr.getBytes()); - Certificate selfSignedCert = cf.generateCertificate(is); + // generate certificate from cert strings + Certificate selfSignedCert = pemDecoder.decode(selfSignedCertStr, X509Certificate.class); // generate certification path - List list = Arrays.asList(new Certificate[] { - selfSignedCert}); + List list = Collections.singletonList(selfSignedCert); return cf.generateCertPath(list); } - private static Set generateTrustAnchors() - throws CertificateException { - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + private static Set generateTrustAnchors() { - ByteArrayInputStream is = - new ByteArrayInputStream(selfSignedCertStr.getBytes()); - Certificate selfSignedCert = cf.generateCertificate(is); + // generate certificate from cert string + X509Certificate selfSignedCert = pemDecoder.decode(selfSignedCertStr, X509Certificate.class); // generate a trust anchor TrustAnchor anchor = - new TrustAnchor((X509Certificate)selfSignedCert, null); + new TrustAnchor(selfSignedCert, null); return Collections.singleton(anchor); } @@ -164,7 +173,7 @@ public class CPValidatorTrustAnchor { } private static void validate(String trustAnchor) - throws CertPathValidatorException, Exception { + throws Exception { selfSignedCertStr = trustAnchor; CertPath path = generateCertificatePath(); @@ -176,7 +185,11 @@ public class CPValidatorTrustAnchor { params.setRevocationEnabled(false); // set the validation time - params.setDate(new Date(109, 9, 1)); // 2009-09-01 + final Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, 2009); + calendar.set(Calendar.MONTH, 9); + calendar.set(Calendar.DATE, 1); + params.setDate(calendar.getTime()); // 2009-09-01 CertPathValidator validator = CertPathValidator.getInstance("PKIX"); diff --git a/test/jdk/sun/security/rsa/InvalidBitString.java b/test/jdk/sun/security/rsa/InvalidBitString.java index be9e42ca544..7f8408f35f0 100644 --- a/test/jdk/sun/security/rsa/InvalidBitString.java +++ b/test/jdk/sun/security/rsa/InvalidBitString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,15 @@ /* @test * @summary Validation of signatures succeed when it should fail + * @enablePreview * @bug 6896700 */ -import java.io.InputStream; -import java.io.ByteArrayInputStream; +import java.security.PEMDecoder; import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; import java.security.PublicKey; import java.security.SignatureException; +import java.security.cert.X509Certificate; public class InvalidBitString { @@ -87,16 +87,16 @@ public class InvalidBitString { "ZAM6mgkuSY7/vdnsiJtU\n" + "-----END CERTIFICATE-----\n"; - public static void main(String args[]) throws Exception { - - Certificate signer = generate(signerCertStr); + public static void main(String[] args) throws Exception { + final PEMDecoder pemDecoder = PEMDecoder.of(); + Certificate signer = pemDecoder.decode(signerCertStr, X509Certificate.class); // the valid certificate - Certificate normal = generate(normalCertStr); + Certificate normal = pemDecoder.decode(normalCertStr, X509Certificate.class); // the invalid certificate with extra signature bits - Certificate longer = generate(longerCertStr); + Certificate longer = pemDecoder.decode(longerCertStr, X509Certificate.class); // the invalid certificate without enough signature bits - Certificate shorter = generate(shorterCertStr); + Certificate shorter = pemDecoder.decode(shorterCertStr, X509Certificate.class); if (!test(normal, signer, " normal", true) || !test(longer, signer, " longer", false) || @@ -105,19 +105,6 @@ public class InvalidBitString { } } - private static Certificate generate(String certStr) throws Exception { - InputStream is = null; - try { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - is = new ByteArrayInputStream(certStr.getBytes()); - return cf.generateCertificate(is); - } finally { - if (is != null) { - is.close(); - } - } - } - private static boolean test(Certificate target, Certificate signer, String title, boolean expected) throws Exception { System.out.print("Checking " + title + ": expected: " + diff --git a/test/jdk/sun/security/ssl/ClientHandshaker/RSAExport.java b/test/jdk/sun/security/ssl/ClientHandshaker/RSAExport.java index 698bbdf88b1..26d5c69e219 100644 --- a/test/jdk/sun/security/ssl/ClientHandshaker/RSAExport.java +++ b/test/jdk/sun/security/ssl/ClientHandshaker/RSAExport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ /* * @test * @bug 6690018 + * @enablePreview * @summary RSAClientKeyExchange NullPointerException * @run main/othervm RSAExport */ @@ -197,17 +198,24 @@ * */ -import java.io.*; -import java.net.*; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.PEMDecoder; import java.security.Security; import java.security.KeyStore; import java.security.KeyFactory; import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; -import javax.net.ssl.*; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; import java.math.BigInteger; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.RSAPrivateKeySpec; public class RSAExport { @@ -312,7 +320,7 @@ public class RSAExport { /* * Turn on SSL debugging? */ - static boolean debug = false; + static boolean debug = Boolean.getBoolean("test.debug"); /* * If the client or server is doing some kind of object creation @@ -386,7 +394,7 @@ public class RSAExport { // Enable RSA_EXPORT cipher suites only. try { - String enabledSuites[] = { + String[] enabledSuites = { "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"}; sslSocket.setEnabledCipherSuites(enabledSuites); @@ -471,22 +479,20 @@ public class RSAExport { void startServer(boolean newThread) throws Exception { if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..." + e); - serverReady = true; - serverException = e; - } + serverThread = new Thread(() -> { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died..." + e); + serverReady = true; + serverException = e; } - }; + }); serverThread.start(); } else { doServerSide(); @@ -495,19 +501,17 @@ public class RSAExport { void startClient(boolean newThread) throws Exception { if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } + clientThread = new Thread(() -> { + try { + doClientSide(); + } catch (Exception e) { + /* + * Our client thread just died. + */ + System.err.println("Client died..."); + clientException = e; } - }; + }); clientThread.start(); } else { doClientSide(); @@ -517,11 +521,10 @@ public class RSAExport { // Get the SSL context private SSLContext getSSLContext(boolean authnRequired) throws Exception { // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream is = - new ByteArrayInputStream(trusedCertStr.getBytes()); - Certificate trustedCert = cf.generateCertificate(is); + final PEMDecoder pemDecoder = PEMDecoder.of(); + + Certificate trustedCert = pemDecoder.decode(trusedCertStr, X509Certificate.class); // create a key store KeyStore ks = KeyStore.getInstance("JKS"); @@ -540,8 +543,7 @@ public class RSAExport { (RSAPrivateKey)kf.generatePrivate(priKeySpec); // generate certificate chain - is = new ByteArrayInputStream(serverCertStr.getBytes()); - Certificate serverCert = cf.generateCertificate(is); + Certificate serverCert = pemDecoder.decode(serverCertStr, X509Certificate.class); Certificate[] chain = new Certificate[2]; chain[0] = serverCert; diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java index 7f9573a8eeb..051c940b3b0 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * 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,20 +31,33 @@ * @bug 7166570 * @summary JSSE certificate validation has started to fail for * certificate chains + * @enablePreview * @run main/othervm BasicConstraints PKIX * @run main/othervm BasicConstraints SunX509 */ -import java.util.*; -import java.io.*; -import javax.net.ssl.*; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.PEMDecoder; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.PKIXParameters; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; import java.security.KeyStore; import java.security.KeyFactory; -import java.security.cert.*; -import java.security.spec.*; -import java.security.interfaces.*; -import java.util.Base64; +import java.util.Arrays; public class BasicConstraints { @@ -96,33 +109,6 @@ public class BasicConstraints { "cwIDUWqQda62xV7ChkTh7ia3uvBXob2iiB0aI3gVTTqDfK9F5XXtW4BXfqx0hvwB\n" + "6JzgmNyDQos=\n" + "-----END CERTIFICATE-----"; - static String trustedPrivateKey = // Private key in the format of PKCS#8 - "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDUJ3hT/9jY/i8i\n" + - "70EEaL6mbrhhdg/Ys1E0r97n+dZaY0olqkIBhh1r8UkKWtvOkj8WBFQ0sz0HhSjT\n" + - "rkVEisGLW+7zPJiDBPtQrRawvCDpnzUofnQ98zQKUTHji1OqhxgNzsKCy9vIh5Mh\n" + - "tX0CdGUScEDXlYUkAkxMKCVo2V5dRn34D+1rNGEeWxGnQ5vyPi0IwlpEOkYxhPLV\n" + - "dsb5aoLzBc/rdrrdzCM+svm7O38LhbVuA0F9NHAgdJRKE2F91ztkk1KvY0U9zCh1\n" + - "3u5WV7kl481qDujKGM4UURoEarbV2Xr+jNVGSpJZYCLU/sxFrL15iPeYtmJlovo2\n" + - "VbFed/NXAgMBAAECggEAUZvlQ5q1VbNhenTCc+m+/NK2hncd3WQNJtFIU7/dXuO2\n" + - "0ApQXbmzc6RbTmppB2tmbRe5NJSGM3BbpiHxb05Y6TyyDEsQ98Vgz0Xl5pJXrsaZ\n" + - "cjxChtoY+KcHI9qikoRpElaoqBu3LcpJJLxlnB4eCxu3NbbEgneH1fvTeCO1kvcp\n" + - "i3DDdyfY7WB9RW1yWAveiuqvtnbsPfJJLKEhFvZL2ArYCRTm/oIw64yukNe/QLR5\n" + - "bGzEJMT2ZNQMld1f+CW9tOrUKrnnPCGfMa351T5we+8B6sujWfftPutgEVx5TmHs\n" + - "AOW1SntMapbgg46K9EC/C5YQa5D1aNOH9ZTEMkgUMQKBgQDrpPQIHFozeeyZ0iiq\n" + - "HtReLPcqpkwr/9ELc3SjgUypSvpu0l/m++um0yLinlXMn25km/BP6Mv3t/+1uzAc\n" + - "qpopkcyek8X1hzNRhDkWuMv4KDOKk5c6qLx8FGSm6q8PYm5KbsiyeCM7CJoeoqJ5\n" + - "74IZjOIw7UrYLckCb6W8xGQLIwKBgQDmew3vGRR3JmCCSumtJQOqhF6bBYrNb6Qc\n" + - "r4vrng+QhNIquwGqHKPorAI1J8J1jOS+dkDWTxSz2xQKQ83nsOspzVPskpDh5mWL\n" + - "gGk5QCkX87jFsXfhvZFLksZMbIdpWze997Zs2fe/PWfPaH6o3erqo2zAhQV0eA9q\n" + - "C7tfImREPQKBgQDi2Xq/8CN52M9IScQx+dnyC5Gqckt0NCKXxn8sBIa7l129oDMI\n" + - "187FXA8CYPEyOu14V5KiKvdos66s0daAUlB04lI8+v+g3ZYuzH50/FQHwxPTPUBi\n" + - "DRzeyncXJWiAA/8vErWM8hDgfOh5w5Fsl4EEfdcmyNm7gWA4Qyknr1ysRwKBgQDC\n" + - "JSPepUy09VHUTxA59nT5HRmoEeoTFRizxTfi2LkZrphuwCotxoRXiRUu+3f1lyJU\n" + - "Qb5qCCFTQ5bE8squgTwGcVxhajC66V3ePePlAuPatkWN2ek28X1DoLaDR+Rk3h69\n" + - "Wb2EQbNMl4grkUUoMA8jaVhBb4vhyQSK+qjyAUFerQKBgQDXZPuflfsjH/d/O2yw\n" + - "qZbssKe9AKORjv795teblAc3vmsSlNwwVnPdS2aq1LHyoNbetc/OaZV151hTQ/9z\n" + - "bsA48oOojgrDD07Ovg3uDcNEIufxR0aGeSSvqhElp1r7wAYj8bAr6W/RH6MS16WW\n" + - "dRd+PH6hsap8BD2RlVCnrT3vIQ=="; // Certificate information: // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce @@ -156,33 +142,6 @@ public class BasicConstraints { "P0QqaqP+xJIY+sRrzdckxSfS9AOOrJk2VXY8qEoxCN4wCvHJWuHEAF/Lm65d/hq3\n" + "2Uh8P+QHLeuEwF8RoTpjiGM9dXvaqcQz7w5G\n" + "-----END CERTIFICATE-----"; - static String caSignerPrivateKey = // Private key in the format of PKCS#8 - "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDAvGeLKlW1ljae\n" + - "eu8NvDCjfW5BNK2c0C4ry7Is+1mM4PC7FA4bRpMaQHKIjLsZ5D1hoA9183cv3p1a\n" + - "P75/ZYMOyx1id/hXmbd3jp8BR0wbvrKxa53+4lO0S5AL5dOpU2AVhcdeQ7+DwoL6\n" + - "iAuHqNcABg3CijrIcFeZHcPMwaZMd9YxJG6YrnNHMWjbXTGKpma02NMB1UnRxsdN\n" + - "phqfRt2gkUs18l6697sSJ7eblvSWEWw1Bmtrg9No28UUsiF8q0m9i/G0QzYOrS6v\n" + - "ghum5bpHAixxfA9Z/ozHrN8gf8gNDTRnG6phDwVb1Uj9nO2f9yTArx7Kz5EtRNmD\n" + - "x9SNMS9rAgMBAAECggEAZk6cF/8s5+sIqy9OXdgbaW1XbT1tOuQ23gCOX9o8Os/c\n" + - "eTG4GzpnM3QqV9l8J85D1uKD0nSeO8bLd/CGSlG0M9IVkwNjy/xIqyoFtUQHXmLn\n" + - "r84UXAv/qqDBoc8pf6RGSKZuodcMfgBuTlaQ6D3zgou0GiQN9//KP/jQyouwnr3A\n" + - "LyXQekxriwPuSYAPak8s5XLfugOebbSRm2UdGEgX3yrT9FVu9rtgeMKdRaCOU8T4\n" + - "G2UdpGaiDfm5yrR+2XEIv4oaH3WFxmmfQCxVcOFJ1iRvfKBbLb1UCgtJuCBD067y\n" + - "dq5PrwUTeAvd7hwZd0lxCSnWY7VvYFNr7iJfyElowQKBgQD8eosot+Th03hpkYDs\n" + - "BIVsw7oqhJmcrPV1bSZ+aQwqqrOGypNmb7nLGTC8Cj1sT+EzfGs7GqxiLOEn4NXr\n" + - "TYV//RUPBSEXVp2y+2dot1a9oq0BJ8FwGTYL0qSwJrIXJfkQFrYhVVz3JLIWJbwV\n" + - "cy4YCQr094BhXTS7joJOUDRsYwKBgQDDbI3Lv+bBK8lLfIBll1RY1k5Gqy/H+qxp\n" + - "sMN8FmadmIGzHhe9xml6b5EfAZphAUF4vZJhQXloT5Wm+NNIAf6X6dRjvzyw7N9B\n" + - "d48EFJF4ChqNGBocsQRNr2wPRzQ+k2caw9YyYMIjbhktDzO1U/FJGYW6/Vgr2v4K\n" + - "siROnXfLWQKBgBOVAZQP5z2opC8z7NbhZuPPrnG7xRpEw+jupUyqoxnwEWqD7bjF\n" + - "M5jQBFqhRLBQ5buTi9GSuQoIRxJLuuu8IH2TyH1YvX9M5YBLRXL2vVCJ/HcZeURT\n" + - "gECcfs92wNtQw6d+y3N8ZnB4tSNIm/Th8RJGKUZkp91lWECvxeWDDP3XAoGASfNq\n" + - "NRAJYlAPfGFAtTDu2i8+r79X9XUGiXg6gVp4umpbqkxY75eFkq9lWzZgFRVEkUwr\n" + - "eGIubyquluDSEw2uKg5yMMzNSqZYVY3IsOKXqbUpFvtn5jOWTU90tNNdEdD100sI\n" + - "Y0f6Ly4amNKH3rZFOERQNtJn6zCTsbh3xMgR7QECgYBhQTqxLU5eIu38MKobzRue\n" + - "RoUkMcoY3DePkKPSYjilFhkUDozIXf/xUGnB8kERZKO+44wUkuPGljiFL1/P/RO9\n" + - "zhHAV94Kw2ddtfxy05GVtUZ99miBmsMb2m8vumGJqfR8h2xpfc1Ra0zfrsPgLNru\n" + - "xDTDW+bNbM7XyPvg9mOf7Q=="; // Certificate information: // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce, CN=casigner @@ -216,33 +175,6 @@ public class BasicConstraints { "zr4da2aIg9CKrH2QWoMkDfRKkJvrU3/VhVfVWpNbXFE2xZXftQl3hpFCJ3FkpciA\n" + "l3hKeq4byY3LXxhAClHpk1KkXJkMnQdOfA5aGekj/Cjuaz1/iKYAG2vRq7YcuM/o\n" + "-----END CERTIFICATE-----"; - static String certIssuerPrivateKey = // Private key in the format of PKCS#8 - "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC1lDVpzmzwbKOL\n" + - "yFWkjPjqtX9xLMq7SVqobvhBv+VChMGGjQbNQPbtczOcXNOcuMFyXxY++eXY7c37\n" + - "MzhbdZHv4Y4aWEn+A3EiX2/fTAbxx165qxKiHbD2EmlKk/Q6yIvi9M9EXXr/viEC\n" + - "Y4/Sdtd4KYtfETa0FpfF5/ZpZMYQo8I9RqBQOmhfvXL1l/Lodla5elZtvIUyp5k2\n" + - "nRQe58AxeP5hrilbIgfmEySf9mOkaTalRf2epBE/wRNA7Qi5Sr2O4pY2x3PPdmMy\n" + - "NL4cZaOJTgdyeDYbEMSW6vpiJW26ma/qeFgPIXZ8COFJZLSOEu310M4QOdSR1Y2c\n" + - "l3/V2E0VAgMBAAECggEBAJjfVrjl2kHwtSCSYchQB6FTfSBDnctgTrtP8iMo9FO0\n" + - "gVpOkVNtRndTbjhOzro7smIgPBJ5QlIIpErBLMmTinJza7gybNk2/KD7yKwuzgnw\n" + - "2IdoyB9E8B+8EHmBZzW2ck953KaqLUvzPsdMG2IOPAomr/gx/eRQwScVzBefiEGo\n" + - "sN+rGfUt/RNAHwWje1KuNDj21S84agQhN6hdYUnIMsvJLu/9mOwUb9ff+AzTUfFr\n" + - "zyx2MJL4Cx59DkUUMESCfinlHUc21llQjFWmX/zOoGY0X0qV/YM/GRsv1ZDFHw9o\n" + - "hQ6m8Ov7D9wB3TKZBI97sCyggjBfSeuYQlNbs99KWQECgYEA7IKNL0ME7FuIrKYu\n" + - "FCQ/Duz1N3oQXLzrTGKUSU1qSbrU2Jwk4SfJ8ZYCW1TP6vZkaQsTXmXun3yyCAqZ\n" + - "hcOtDBhI+b7Wpmmyf6nb83oYJtzHMRQZ5qS+9vOBfV9Uf1za8XI4p90EqkFHByCF\n" + - "tHfjVbjK39zN4CvaO3tqpOaYtL0CgYEAxIrTAhGWy9nBsxf8QeqDou0rV5Cw50Kl\n" + - "kQsE7KLmjvrMaFFpUc5lgWoC+pm/69VpNBUuN/38YozwxVjVi/nMJuuK150mhdWI\n" + - "B28FI7ORnFmVeSvTrP4mBX1ct2Tny9zpchXn3rpHR5NZUs7oBhjudHSfRMrHxeBs\n" + - "Kv2pr2s6uzkCgYAtrEh3iAm7WzHZpX3ghd9nknsIa5odTp5h8eeRAFI2Ss4vxneY\n" + - "w4ZMERwDZy1/wnVBk9H5uNWMFxiKVQGww0j3vPjawe/R0zeVT8gaDMn9N0WARNF7\n" + - "qPT3265196LptZTSa6xlPllYR6LfzXgEkeJk+3qyIIHheJZ8RikiDyYOQQKBgQC/\n" + - "rxlegiMNC4KDldf7vanGxAKqcz5lPbXWQOX7mGC+f9HNx+Cs3VxYHDltiXgJnOju\n" + - "191s1HRK9WR5REt5KhY2uzB9WxJQItJ5VYiwqhhQYXqLY/gdVv1kC0DayDndtMWk\n" + - "88JhklGkeAv83DikgbpGr9sJr6+oyFkWkLDmmfD82QKBgQCMgkZJzrdSNNlB0n5x\n" + - "xC3MzlsQ5aBJuUctnMfuyDi+11yLAuP1oLzGEJ7qEfFoGRO0V8zJWmHAfNhmVYEX\n" + - "ow5g0WbPT16GoRCiOAzq+ewH+TEELMF6HWqnDuTnCg28Jg0dw2kdVTqeyzKOQlLG\n" + - "ua9c2DY3PUTXQPNqLVhz+XxZKA=="; // Certificate information: // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce, CN=certissuer @@ -277,6 +209,7 @@ public class BasicConstraints { "u/inkyf8NcG7zLBJJyuKfUXO/OzGPD5QMviVc+PCGTY=\n" + "-----END CERTIFICATE-----"; static String serverPrivateKey = // Private key in the format of PKCS#8 + "-----BEGIN PRIVATE KEY-----\n" + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCaDgoxN2UQQero\n" + "oBQ4JlQP1BFaZEtIkdIU2VJs4whz85J0LSB/68iEOS5e8wCz9wiQWr4isor7sl3e\n" + "B2dnLGY28BthOTw2j/CYw/dRqyDbPZniooB233uLGarKjqQWXpRFQi6bgEQmNqWe\n" + @@ -302,7 +235,8 @@ public class BasicConstraints { "/RiupLD4/awmf21ytpfHcmOWCcdQoE4WC69a6VyVAoGAboeogM5/TRKj80rXfUH2\n" + "lFZzgX246XGwNyOVVgOuv/Oxa61b5FeeCpnFQcjpZmC5vd63X3w7oYSDe2wUt+Wh\n" + "LhYunmcCEj+yb3of33loQb/FM2OLW9UoQakB7ewio9vtw+BAnWxnHFkEaqdxMXpy\n" + - "TiSXLpQ1Q9GvDpzngDzJzzY="; + "TiSXLpQ1Q9GvDpzngDzJzzY=\n" + + "-----END PRIVATE KEY-----"; // Certificate information: // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce, CN=certissuer @@ -337,6 +271,7 @@ public class BasicConstraints { "tL85OZz8ov7d2jVet/w7FD4M5XfcogsNtpX4kaMsctyvQbDYRA==\n" + "-----END CERTIFICATE-----"; static String clientPrivateKey = // Private key in the format of PKCS#8 + "-----BEGIN PRIVATE KEY-----\n" + "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFwNzVfqQ58J0I\n" + "FxUO1ng7XE3uKg0FfbQ4/XEWRakF6PeAt9JZLl83R++tW2QfOAxEldKiyJOv5/g/\n" + "UjrIO0j3u7noxtuK6Yf1aTwDaz16PI8cIfylvvMtKWDYoBVGQ4vphAwDhoMqmgG2\n" + @@ -362,9 +297,10 @@ public class BasicConstraints { "cWJdYS5BrwEUen8vaQt1LhgS6lOqYsjysCxkYm078QKBgEJuq4RzecgiGx8srWDb\n" + "pQKpxrdEt82Y7OXLVj+W9vixcW/xUYhDYGsfdUigZoOjo4nV8KVmMbuI48PIYwnw\n" + "haLwWrBWlki4x9MRwuZUdewOYoo7hDZToZmIDescdiwv8CA/Dg9kOX3YYLPW+cWl\n" + - "i1pnyMPaloBOhz3Y07sWXxCz"; + "i1pnyMPaloBOhz3Y07sWXxCz\n" + + "-----END PRIVATE KEY-----"; - static char passphrase[] = "passphrase".toCharArray(); + static char[] passphrase = "passphrase".toCharArray(); /* * Is the server ready to serve? @@ -374,7 +310,7 @@ public class BasicConstraints { /* * Turn on SSL debugging? */ - static boolean debug = false; + static boolean debug = Boolean.getBoolean("test.debug"); /* * Define the server side of the test. @@ -447,48 +383,39 @@ public class BasicConstraints { // get the ssl context private static SSLContext getSSLContext(boolean isServer) throws Exception { - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + final PEMDecoder pemDecoder = PEMDecoder.of(); // create a key store KeyStore ks = KeyStore.getInstance("JKS"); ks.load(null, null); - // import the trused cert - ByteArrayInputStream is = - new ByteArrayInputStream(trusedCertStr.getBytes()); - Certificate trusedCert = cf.generateCertificate(is); - is.close(); + // generate certificate from cert string + Certificate trusedCert = pemDecoder.decode(trusedCertStr, X509Certificate.class); + + // import the trused cert ks.setCertificateEntry("SunJSSE Test Serivce", trusedCert); // import the certificate chain and key Certificate[] chain = new Certificate[3]; - is = new ByteArrayInputStream(caSignerStr.getBytes()); - Certificate caSignerCert = cf.generateCertificate(is); - is.close(); + Certificate caSignerCert =pemDecoder.decode(caSignerStr, X509Certificate.class); chain[2] = caSignerCert; - is = new ByteArrayInputStream(certIssuerStr.getBytes()); - Certificate certIssuerCert = cf.generateCertificate(is); - is.close(); + Certificate certIssuerCert =pemDecoder.decode(certIssuerStr, X509Certificate.class); chain[1] = certIssuerCert; - PKCS8EncodedKeySpec priKeySpec = null; + PKCS8EncodedKeySpec priKeySpec; + Certificate keyCert; if (isServer) { - priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(serverPrivateKey)); - is = new ByteArrayInputStream(serverCertStr.getBytes()); + priKeySpec =pemDecoder.decode(serverPrivateKey, PKCS8EncodedKeySpec.class); + keyCert = pemDecoder.decode(serverCertStr, X509Certificate.class); } else { - priKeySpec = new PKCS8EncodedKeySpec( - Base64.getMimeDecoder().decode(clientPrivateKey)); - is = new ByteArrayInputStream(clientCertStr.getBytes()); + priKeySpec = pemDecoder.decode(clientPrivateKey, PKCS8EncodedKeySpec.class); + keyCert = pemDecoder.decode(clientCertStr, X509Certificate.class); } KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); - Certificate keyCert = cf.generateCertificate(is); - is.close(); chain[0] = keyCert; ks.setKeyEntry("End Entity", priKey, passphrase, chain); @@ -496,7 +423,8 @@ public class BasicConstraints { // check the certification path PKIXParameters paras = new PKIXParameters(ks); paras.setRevocationEnabled(false); - CertPath path = cf.generateCertPath(Arrays.asList(chain)); + CertPath path = CertificateFactory.getInstance("X.509") + .generateCertPath(Arrays.asList(chain)); CertPathValidator cv = CertPathValidator.getInstance("PKIX"); cv.validate(path, paras); @@ -531,7 +459,7 @@ public class BasicConstraints { volatile Exception serverException = null; volatile Exception clientException = null; - public static void main(String args[]) throws Exception { + public static void main(String[] args) throws Exception { if (debug) System.setProperty("javax.net.debug", "all"); @@ -586,22 +514,20 @@ public class BasicConstraints { void startServer(boolean newThread) throws Exception { if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; - } + serverThread = new Thread(() -> { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died..."); + serverReady = true; + serverException = e; } - }; + }); serverThread.start(); } else { doServerSide(); @@ -610,19 +536,17 @@ public class BasicConstraints { void startClient(boolean newThread) throws Exception { if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } + clientThread = new Thread(() -> { + try { + doClientSide(); + } catch (Exception e) { + /* + * Our client thread just died. + */ + System.err.println("Client died..."); + clientException = e; } - }; + }); clientThread.start(); } else { doClientSide(); diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/ComodoHacker.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/ComodoHacker.java index 6a67364360f..f1e5415e2c3 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/ComodoHacker.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/ComodoHacker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,21 +25,18 @@ * @test * @bug 7123519 * @summary Problem with java/classes_security + * @enablePreview * @run main/othervm ComodoHacker PKIX * @run main/othervm ComodoHacker SunX509 */ -import java.net.*; -import java.util.*; -import java.io.*; -import javax.net.ssl.*; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; import java.security.KeyStore; +import java.security.PEMDecoder; import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; -import java.security.spec.*; -import java.security.interfaces.*; public class ComodoHacker { // DigiNotar Root CA, untrusted root certificate @@ -213,6 +210,8 @@ public class ComodoHacker { "baB2sVGcVNBkK55bT8gPqnx8JypubyUvayzZGg==\n" + "-----END CERTIFICATE-----"; + private static final PEMDecoder pemDecoder = PEMDecoder.of(); + private static String tmAlgorithm; // trust manager public static void main(String args[]) throws Exception { @@ -253,19 +252,15 @@ public class ComodoHacker { } private static X509TrustManager getTrustManager() throws Exception { - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); // create a key store KeyStore ks = KeyStore.getInstance("JKS"); ks.load(null, null); + // generate certificate from cert string + Certificate trustedCert = pemDecoder.decode(trustedCertStr, X509Certificate.class); // import the trusted cert - try (ByteArrayInputStream is = - new ByteArrayInputStream(trustedCertStr.getBytes())) { - Certificate trustedCert = cf.generateCertificate(is); - ks.setCertificateEntry("RSA Export Signer", trustedCert); - } + ks.setCertificateEntry("RSA Export Signer", trustedCert); // create the trust manager TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); @@ -276,28 +271,11 @@ public class ComodoHacker { private static X509Certificate[] getFraudulentChain() throws Exception { // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate[] chain = new X509Certificate[4]; - try (ByteArrayInputStream is = - new ByteArrayInputStream(targetCertStr.getBytes())) { - chain[0] = (X509Certificate)cf.generateCertificate(is); - } - - try (ByteArrayInputStream is = - new ByteArrayInputStream(intermediateCertStr.getBytes())) { - chain[1] = (X509Certificate)cf.generateCertificate(is); - } - - try (ByteArrayInputStream is = - new ByteArrayInputStream(compromisedCertStr.getBytes())) { - chain[2] = (X509Certificate)cf.generateCertificate(is); - } - - try (ByteArrayInputStream is = - new ByteArrayInputStream(untrustedCrossCertStr.getBytes())) { - chain[3] = (X509Certificate)cf.generateCertificate(is); - } + chain[0] = pemDecoder.decode(targetCertStr, X509Certificate.class); + chain[1] = pemDecoder.decode(intermediateCertStr, X509Certificate.class); + chain[2] = pemDecoder.decode(compromisedCertStr, X509Certificate.class); + chain[3] = pemDecoder.decode(untrustedCrossCertStr, X509Certificate.class); return chain; } diff --git a/test/jdk/sun/security/x509/X509CRLImpl/Verify.java b/test/jdk/sun/security/x509/X509CRLImpl/Verify.java index 911f53f5120..a10a18971d2 100644 --- a/test/jdk/sun/security/x509/X509CRLImpl/Verify.java +++ b/test/jdk/sun/security/x509/X509CRLImpl/Verify.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,19 @@ * @test * @bug 7026347 * @summary X509CRL should have verify(PublicKey key, Provider sigProvider) + * @enablePreview */ -import java.io.ByteArrayInputStream; -import java.security.*; -import java.security.cert.*; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PEMDecoder; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Security; +import java.security.SignatureException; +import java.security.cert.CRLException; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; public class Verify { @@ -144,23 +152,21 @@ public class Verify { } } - private static void setup() throws CertificateException, CRLException { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + private static void setup() { + final PEMDecoder pemDecoder = PEMDecoder.of(); /* Create CRL */ - ByteArrayInputStream inputStream = - new ByteArrayInputStream(crlStr.getBytes()); - crl = (X509CRL)cf.generateCRL(inputStream); + crl = pemDecoder.decode(crlStr, X509CRL.class); /* Get public key of the CRL issuer cert */ - inputStream = new ByteArrayInputStream(crlIssuerCertStr.getBytes()); - X509Certificate cert - = (X509Certificate)cf.generateCertificate(inputStream); - crlIssuerCertPubKey = cert.getPublicKey(); + crlIssuerCertPubKey = pemDecoder.decode(crlIssuerCertStr, X509Certificate.class) + .getPublicKey(); + /* Get public key of the self-signed Cert */ - inputStream = new ByteArrayInputStream(selfSignedCertStr.getBytes()); - selfSignedCertPubKey = cf.generateCertificate(inputStream).getPublicKey(); + selfSignedCertPubKey = pemDecoder.decode(selfSignedCertStr, X509Certificate.class) + .getPublicKey(); + } private static void verifyCRL(PublicKey key, String providerName) From 27c83c730d8b0f87bb51230c35e4fe261c9d2723 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Wed, 22 Oct 2025 08:12:10 +0000 Subject: [PATCH 014/736] 8370225: RISC-V: cleanup verify_xxx in interp_masm_riscv.hpp Reviewed-by: fyang --- src/hotspot/cpu/riscv/interp_masm_riscv.hpp | 7 ++----- .../cpu/riscv/templateInterpreterGenerator_riscv.cpp | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp index eec4f0846a5..295f1b22191 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp @@ -301,12 +301,9 @@ class InterpreterMacroAssembler: public MacroAssembler { void load_method_entry(Register cache, Register index, int bcp_offset = 1); void verify_field_offset(Register reg) NOT_DEBUG_RETURN; - -#ifdef ASSERT void verify_access_flags(Register access_flags, uint32_t flag, - const char* msg, bool stop_by_hit = true); - void verify_frame_setup(); -#endif + const char* msg, bool stop_by_hit = true) NOT_DEBUG_RETURN; + void verify_frame_setup() NOT_DEBUG_RETURN; }; #endif // CPU_RISCV_INTERP_MASM_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 61f4aa3e722..692335d8c08 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -1073,9 +1073,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { } // start execution -#ifdef ASSERT __ verify_frame_setup(); -#endif // jvmti support __ notify_method_entry(); @@ -1541,9 +1539,7 @@ address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { } // start execution -#ifdef ASSERT __ verify_frame_setup(); -#endif // jvmti support __ notify_method_entry(); From 6bf3581bbacc2ed8f6411d23a5ab332376c53c87 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 22 Oct 2025 08:35:05 +0000 Subject: [PATCH 015/736] 8369946: Bytecode rewriting causes Java heap corruption on PPC Reviewed-by: rrich, dbriemann --- src/hotspot/cpu/ppc/interp_masm_ppc.hpp | 9 ++++-- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 34 ++++++++++---------- src/hotspot/cpu/ppc/templateTable_ppc_64.cpp | 13 +++++--- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp index d3969427db3..9140dd7ca4e 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp @@ -133,8 +133,13 @@ class InterpreterMacroAssembler: public MacroAssembler { void get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size); void load_resolved_indy_entry(Register cache, Register index); - void load_field_entry(Register cache, Register index, int bcp_offset = 1); - void load_method_entry(Register cache, Register index, int bcp_offset = 1); + void load_field_or_method_entry(bool is_method, Register cache, Register index, int bcp_offset, bool for_fast_bytecode); + void load_field_entry(Register cache, Register index, int bcp_offset = 1, bool for_fast_bytecode = false) { + load_field_or_method_entry(false, cache, index, bcp_offset, for_fast_bytecode); + } + void load_method_entry(Register cache, Register index, int bcp_offset = 1, bool for_fast_bytecode = false) { + load_field_or_method_entry(true, cache, index, bcp_offset, for_fast_bytecode); + } void get_u4(Register Rdst, Register Rsrc, int offset, signedOrNot is_signed); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 8df2cc5d273..503cc259432 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -468,33 +468,33 @@ void InterpreterMacroAssembler::load_resolved_indy_entry(Register cache, Registe add(cache, cache, index); } -void InterpreterMacroAssembler::load_field_entry(Register cache, Register index, int bcp_offset) { +void InterpreterMacroAssembler::load_field_or_method_entry(bool is_method, Register cache, Register index, int bcp_offset, bool for_fast_bytecode) { + const int entry_size = is_method ? sizeof(ResolvedMethodEntry) : sizeof(ResolvedFieldEntry), + base_offset = is_method ? Array::base_offset_in_bytes() : Array::base_offset_in_bytes(), + entries_offset = is_method ? in_bytes(ConstantPoolCache::method_entries_offset()) : in_bytes(ConstantPoolCache::field_entries_offset()); + // Get index out of bytecode pointer get_cache_index_at_bcp(index, bcp_offset, sizeof(u2)); // Take shortcut if the size is a power of 2 - if (is_power_of_2(sizeof(ResolvedFieldEntry))) { + if (is_power_of_2(entry_size)) { // Scale index by power of 2 - sldi(index, index, log2i_exact(sizeof(ResolvedFieldEntry))); + sldi(index, index, log2i_exact(entry_size)); } else { // Scale the index to be the entry index * sizeof(ResolvedFieldEntry) - mulli(index, index, sizeof(ResolvedFieldEntry)); + mulli(index, index, entry_size); } // Get address of field entries array - ld_ptr(cache, in_bytes(ConstantPoolCache::field_entries_offset()), R27_constPoolCache); - addi(cache, cache, Array::base_offset_in_bytes()); + ld_ptr(cache, entries_offset, R27_constPoolCache); + addi(cache, cache, base_offset); add(cache, cache, index); -} -void InterpreterMacroAssembler::load_method_entry(Register cache, Register index, int bcp_offset) { - // Get index out of bytecode pointer - get_cache_index_at_bcp(index, bcp_offset, sizeof(u2)); - // Scale the index to be the entry index * sizeof(ResolvedMethodEntry) - mulli(index, index, sizeof(ResolvedMethodEntry)); - - // Get address of field entries array - ld_ptr(cache, ConstantPoolCache::method_entries_offset(), R27_constPoolCache); - addi(cache, cache, Array::base_offset_in_bytes()); - add(cache, cache, index); // method_entries + base_offset + scaled index + if (for_fast_bytecode) { + // Prevent speculative loading from ResolvedFieldEntry/ResolvedMethodEntry as it can miss the info written by another thread. + // TemplateTable::patch_bytecode uses release-store. + // We reached here via control dependency (Bytecode dispatch has used the rewritten Bytecode). + // So, we can use control-isync based ordering. + isync(); + } } // Load object from cpool->resolved_references(index). diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 41fbe66647e..09acd1c067d 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -148,7 +148,9 @@ void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Reg __ bind(L_fast_patch); } - // Patch bytecode. + // Patch bytecode with release store to coordinate with ResolvedFieldEntry + // and ResolvedMethodEntry loads in fast bytecode codelets. + __ release(); __ stb(Rnew_bc, 0, R14_bcp); __ bind(L_patch_done); @@ -312,6 +314,7 @@ void TemplateTable::fast_aldc(LdcType type) { // We are resolved if the resolved reference cache entry contains a // non-null object (CallSite, etc.) __ get_cache_index_at_bcp(R31, 1, index_size); // Load index. + // Only rewritten during link time. So, no need for memory barriers for accessing resolved info. __ load_resolved_reference_at_index(R17_tos, R31, R11_scratch1, R12_scratch2, &is_null); // Convert null sentinel to null @@ -3114,7 +3117,7 @@ void TemplateTable::fast_storefield(TosState state) { const ConditionRegister CR_is_vol = CR2; // Non-volatile condition register (survives runtime call in do_oop_store). // Constant pool already resolved => Load flags and offset of field. - __ load_field_entry(Rcache, Rscratch); + __ load_field_entry(Rcache, Rscratch, 1, /* for_fast_bytecode */ true); jvmti_post_field_mod(Rcache, Rscratch, false /* not static */); load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12 @@ -3195,7 +3198,7 @@ void TemplateTable::fast_accessfield(TosState state) { // R12_scratch2 used by load_field_cp_cache_entry // Constant pool already resolved. Get the field offset. - __ load_field_entry(Rcache, Rscratch); + __ load_field_entry(Rcache, Rscratch, 1, /* for_fast_bytecode */ true); load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12 // JVMTI support @@ -3334,7 +3337,7 @@ void TemplateTable::fast_xaccess(TosState state) { __ ld(Rclass_or_obj, 0, R18_locals); // Constant pool already resolved. Get the field offset. - __ load_field_entry(Rcache, Rscratch, 2); + __ load_field_entry(Rcache, Rscratch, 2, /* for_fast_bytecode */ true); load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12 // JVMTI support not needed, since we switch back to single bytecode as soon as debugger attaches. @@ -3495,7 +3498,7 @@ void TemplateTable::fast_invokevfinal(int byte_no) { assert(byte_no == f2_byte, "use this argument"); Register Rcache = R31; - __ load_method_entry(Rcache, R11_scratch1); + __ load_method_entry(Rcache, R11_scratch1, 1, /* for_fast_bytecode */ true); invokevfinal_helper(Rcache, R11_scratch1, R12_scratch2, R22_tmp2, R23_tmp3); } From bdfd5e843a7d3db50edf4375e50449b0ce528f8a Mon Sep 17 00:00:00 2001 From: Anton Seoane Ampudia Date: Wed, 22 Oct 2025 09:08:26 +0000 Subject: [PATCH 016/736] 8367690: C2: Unneeded branch in reduce_phi Reviewed-by: rcastanedalo, chagedorn --- src/hotspot/share/opto/escape.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index cbf0666c00e..a148b167ee3 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -1296,9 +1296,8 @@ void ConnectionGraph::reduce_phi(PhiNode* ophi, GrowableArray &alloc_wo castpps.push(use); } else if (use->is_AddP() || use->is_Cmp()) { others.push(use); - } else if (use->is_SafePoint()) { - // processed later } else { + // Safepoints to be processed later; other users aren't expected here assert(use->is_SafePoint(), "Unexpected user of reducible Phi %d -> %d:%s:%d", ophi->_idx, use->_idx, use->Name(), use->outcnt()); } } From b8d3c9049c2b2557e51752c4ed90d7be54731b36 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 22 Oct 2025 09:35:24 +0000 Subject: [PATCH 017/736] 8370229: Remove unused method declarations after JDK-8322630 Reviewed-by: ayang, dholmes --- src/hotspot/share/runtime/sharedRuntime.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 93cd92b3a32..f4ff51504f0 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -384,10 +384,6 @@ class SharedRuntime: AllStatic { // deopt blob static void generate_deopt_blob(void); - static bool handle_ic_miss_helper_internal(Handle receiver, nmethod* caller_nm, const frame& caller_frame, - methodHandle callee_method, Bytecodes::Code bc, CallInfo& call_info, - bool& needs_ic_stub_refill, TRAPS); - public: static DeoptimizationBlob* deopt_blob(void) { return _deopt_blob; } @@ -549,7 +545,6 @@ class SharedRuntime: AllStatic { // A compiled caller has just called the interpreter, but compiled code // exists. Patch the caller so he no longer calls into the interpreter. static void fixup_callers_callsite(Method* moop, address ret_pc); - static bool should_fixup_call_destination(address destination, address entry_point, address caller_pc, Method* moop, CodeBlob* cb); // Slow-path Locking and Unlocking static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* current); From 60104575b221eb3d78a4d56839d55953d4036c21 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Wed, 22 Oct 2025 10:36:23 +0000 Subject: [PATCH 018/736] 8370378: Some compiler tests inadvertently exclude particular platforms Reviewed-by: chagedorn, mchevalier --- test/hotspot/jtreg/compiler/c2/TestBit.java | 2 +- .../c2/irTests/RotateLeftNodeIntIdealizationTests.java | 4 ++-- .../c2/irTests/RotateLeftNodeLongIdealizationTests.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/TestBit.java b/test/hotspot/jtreg/compiler/c2/TestBit.java index b1186a85cae..01769470d78 100644 --- a/test/hotspot/jtreg/compiler/c2/TestBit.java +++ b/test/hotspot/jtreg/compiler/c2/TestBit.java @@ -33,7 +33,7 @@ import jdk.test.lib.process.ProcessTools; * @library /test/lib / * * @requires vm.flagless - * @requires os.arch=="aarch64" | os.arch=="amd64" | os.arch == "ppc64" | os.arch == "ppc64le" | os.arch == "riscv64" + * @requires os.arch == "aarch64" | os.arch == "amd64" | os.arch == "x86_64" | os.arch == "ppc64" | os.arch == "ppc64le" | os.arch == "riscv64" * @requires vm.debug == true & vm.compiler2.enabled * * @run driver compiler.c2.TestBit diff --git a/test/hotspot/jtreg/compiler/c2/irTests/RotateLeftNodeIntIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/RotateLeftNodeIntIdealizationTests.java index e3651129daa..f5225e8173c 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/RotateLeftNodeIntIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/RotateLeftNodeIntIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import compiler.lib.ir_framework.*; * @summary Test that Ideal transformations of RotateLeftNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.RotateLeftNodeIntIdealizationTests - * @requires os.arch == "x86_64" | os.arch == "aarch64" | (os.arch == "riscv64" & vm.cpu.features ~= ".*zbb.*") + * @requires os.arch == "amd64" | os.arch == "x86_64" | os.arch == "aarch64" | (os.arch == "riscv64" & vm.cpu.features ~= ".*zbb.*") */ public class RotateLeftNodeIntIdealizationTests { diff --git a/test/hotspot/jtreg/compiler/c2/irTests/RotateLeftNodeLongIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/RotateLeftNodeLongIdealizationTests.java index 190f08d348c..b28d2f6dc8b 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/RotateLeftNodeLongIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/RotateLeftNodeLongIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import compiler.lib.ir_framework.*; * @summary Test that Ideal transformations of RotateLeftNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.RotateLeftNodeLongIdealizationTests - * @requires os.arch == "x86_64" | os.arch == "aarch64" | (os.arch == "riscv64" & vm.cpu.features ~= ".*zbb.*") + * @requires os.arch == "amd64" | os.arch == "x86_64" | os.arch == "aarch64" | (os.arch == "riscv64" & vm.cpu.features ~= ".*zbb.*") */ public class RotateLeftNodeLongIdealizationTests { From 763d4252f8228adb822f6f4ad2d943e8cffb5b18 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 22 Oct 2025 11:11:42 +0000 Subject: [PATCH 019/736] 8368781: PerfMemory - make issues more transparent Reviewed-by: dholmes, goetz --- src/hotspot/os/posix/perfMemory_posix.cpp | 88 +++---- src/hotspot/os/windows/perfMemory_windows.cpp | 242 +++++------------- src/hotspot/share/runtime/perfMemory.cpp | 9 +- 3 files changed, 102 insertions(+), 237 deletions(-) diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index ed83487265c..2cc0263d291 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -26,6 +26,7 @@ #include "classfile/vmSymbols.hpp" #include "jvm_io.h" #include "logging/log.hpp" +#include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "nmt/memTracker.hpp" @@ -71,9 +72,7 @@ static char* create_standard_memory(size_t size) { // commit memory if (!os::commit_memory(mapAddress, size, !ExecMem)) { - if (PrintMiscellaneous && Verbose) { - warning("Could not commit PerfData memory\n"); - } + log_debug(perf)("could not commit PerfData memory"); os::release_memory(mapAddress, size); return nullptr; } @@ -297,11 +296,12 @@ static DIR *open_directory_secure(const char* dirname) { RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); if (result == OS_ERR) { // Directory doesn't exist or is a symlink, so there is nothing to cleanup. - if (PrintMiscellaneous && Verbose) { + if (log_is_enabled(Debug, perf)) { + LogStreamHandle(Debug, perf) log; if (errno == ELOOP) { - warning("directory %s is a symlink and is not secure\n", dirname); + log.print_cr("directory %s is a symlink and is not secure", dirname); } else { - warning("could not open directory %s: %s\n", dirname, os::strerror(errno)); + log.print_cr("could not open directory %s: %s", dirname, os::strerror(errno)); } } return dirp; @@ -371,9 +371,7 @@ static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not change to directory %s", dirname); - } + log_debug(perf)("could not change to directory %s", dirname); if (*saved_cwd_fd != -1) { ::close(*saved_cwd_fd); *saved_cwd_fd = -1; @@ -411,16 +409,12 @@ static bool is_file_secure(int fd, const char *filename) { // Determine if the file is secure. RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("fstat failed on %s: %s\n", filename, os::strerror(errno)); - } + log_debug(perf)("fstat failed on %s: %s", filename, os::strerror(errno)); return false; } if (statbuf.st_nlink > 1) { // A file with multiple links is not expected. - if (PrintMiscellaneous && Verbose) { - warning("file %s has multiple links\n", filename); - } + log_debug(perf)("file %s has multiple links", filename); return false; } return true; @@ -447,10 +441,10 @@ static char* get_user_name(uid_t uid) { int result = getpwuid_r(uid, &pwent, pwbuf, (size_t)bufsize, &p); if (result != 0 || p == nullptr || p->pw_name == nullptr || *(p->pw_name) == '\0') { - if (PrintMiscellaneous && Verbose) { + if (log_is_enabled(Debug, perf)) { + LogStreamHandle(Debug, perf) log; if (result != 0) { - warning("Could not retrieve passwd entry: %s\n", - os::strerror(result)); + log.print_cr("Could not retrieve passwd entry: %s", os::strerror(result)); } else if (p == nullptr) { // this check is added to protect against an observed problem @@ -463,13 +457,11 @@ static char* get_user_name(uid_t uid) { // message may result in an erroneous message. // Bug Id 89052 was opened with RedHat. // - warning("Could not retrieve passwd entry: %s\n", - os::strerror(errno)); + log.print_cr("Could not retrieve passwd entry: %s", os::strerror(errno)); } else { - warning("Could not determine user name: %s\n", - p->pw_name == nullptr ? "pw_name = null" : - "pw_name zero length"); + log.print_cr("Could not determine user name: %s", + p->pw_name == nullptr ? "pw_name = null" : "pw_name zero length"); } } FREE_C_HEAP_ARRAY(char, pwbuf); @@ -680,10 +672,10 @@ static void remove_file(const char* path) { // maliciously planted, the directory's presence won't hurt anything. // RESTARTABLE(::unlink(path), result); - if (PrintMiscellaneous && Verbose && result == OS_ERR) { + if (log_is_enabled(Debug, perf) && result == OS_ERR) { if (errno != ENOENT) { - warning("Could not unlink shared memory backing" - " store file %s : %s\n", path, os::strerror(errno)); + log_debug(perf)("could not unlink shared memory backing store file %s : %s", + path, os::strerror(errno)); } } } @@ -819,23 +811,16 @@ static bool make_user_tmp_dir(const char* dirname) { // The directory already exists and was probably created by another // JVM instance. However, this could also be the result of a // deliberate symlink. Verify that the existing directory is safe. - // if (!is_directory_secure(dirname)) { // directory is not secure - if (PrintMiscellaneous && Verbose) { - warning("%s directory is insecure\n", dirname); - } + log_debug(perf)("%s directory is insecure", dirname); return false; } } else { // we encountered some other failure while attempting // to create the directory - // - if (PrintMiscellaneous && Verbose) { - warning("could not create directory %s: %s\n", - dirname, os::strerror(errno)); - } + log_debug(perf)("could not create directory %s: %s", dirname, os::strerror(errno)); return false; } } @@ -872,11 +857,12 @@ static int create_sharedmem_file(const char* dirname, const char* filename, size int fd; RESTARTABLE(os::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR), fd); if (fd == OS_ERR) { - if (PrintMiscellaneous && Verbose) { + if (log_is_enabled(Debug, perf)) { + LogStreamHandle(Debug, perf) log; if (errno == ELOOP) { - warning("file %s is a symlink and is not secure\n", filename); + log.print_cr("file %s is a symlink and is not secure", filename); } else { - warning("could not create file %s: %s\n", filename, os::strerror(errno)); + log.print_cr("could not create file %s: %s", filename, os::strerror(errno)); } } // close the directory and reset the current working directory @@ -924,18 +910,14 @@ static int create_sharedmem_file(const char* dirname, const char* filename, size // truncate the file to get rid of any existing data RESTARTABLE(::ftruncate(fd, (off_t)0), result); if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not truncate shared memory file: %s\n", os::strerror(errno)); - } + log_debug(perf)("could not truncate shared memory file: %s", os::strerror(errno)); ::close(fd); return -1; } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not set shared memory file size: %s\n", os::strerror(errno)); - } + log_debug(perf)("could not set shared memory file size: %s", os::strerror(errno)); ::close(fd); return -1; } @@ -1057,9 +1039,7 @@ static char* mmap_create_shared(size_t size) { assert(result != OS_ERR, "could not close file"); if (mapAddress == MAP_FAILED) { - if (PrintMiscellaneous && Verbose) { - warning("mmap failed - %s\n", os::strerror(errno)); - } + log_debug(perf)("mmap failed - %s", os::strerror(errno)); remove_file(filename); FREE_C_HEAP_ARRAY(char, filename); return nullptr; @@ -1135,9 +1115,7 @@ static size_t sharedmem_filesize(int fd, TRAPS) { RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("fstat failed: %s\n", os::strerror(errno)); - } + log_debug(perf)("fstat failed: %s", os::strerror(errno)); THROW_MSG_0(vmSymbols::java_io_IOException(), "Could not determine PerfMemory size"); } @@ -1212,9 +1190,7 @@ static void mmap_attach_shared(int vmid, char** addr, size_t* sizep, TRAPS) { assert(result != OS_ERR, "could not close file"); if (mapAddress == MAP_FAILED) { - if (PrintMiscellaneous && Verbose) { - warning("mmap failed: %s\n", os::strerror(errno)); - } + log_debug(perf)("mmap failed: %s", os::strerror(errno)); THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Could not map PerfMemory"); } @@ -1244,13 +1220,9 @@ void PerfMemory::create_memory_region(size_t size) { else { _start = create_shared_memory(size); if (_start == nullptr) { - // creation of the shared memory region failed, attempt // to create a contiguous, non-shared memory region instead. - // - if (PrintMiscellaneous && Verbose) { - warning("Reverting to non-shared PerfMemory region.\n"); - } + log_debug(perf)("Reverting to non-shared PerfMemory region."); FLAG_SET_ERGO(PerfDisableSharedMem, true); _start = create_standard_memory(size); } diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index a9b2eebb7be..f815f3bd104 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -24,6 +24,7 @@ #include "classfile/vmSymbols.hpp" #include "logging/log.hpp" +#include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "nmt/memTracker.hpp" @@ -62,9 +63,7 @@ static char* create_standard_memory(size_t size) { // commit memory if (!os::commit_memory(mapAddress, size, !ExecMem)) { - if (PrintMiscellaneous && Verbose) { - warning("Could not commit PerfData memory\n"); - } + log_debug(perf)("could not commit PerfData memory"); os::release_memory(mapAddress, size); return nullptr; } @@ -90,25 +89,21 @@ static void delete_standard_memory(char* addr, size_t size) { static void save_memory_to_file(char* addr, size_t size) { const char* destfile = PerfMemory::get_perfdata_file_path(); - assert(destfile[0] != '\0', "invalid Perfdata file path"); + assert(destfile[0] != '\0', "invalid PerfData file path"); int fd = ::_open(destfile, _O_BINARY|_O_CREAT|_O_WRONLY|_O_TRUNC, _S_IREAD|_S_IWRITE); if (fd == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("Could not create Perfdata save file: %s: %s\n", - destfile, os::strerror(errno)); - } + log_debug(perf)("could not create PerfData save file: %s: %s", + destfile, os::strerror(errno)); } else { for (size_t remaining = size; remaining > 0;) { int nbytes = ::_write(fd, addr, (unsigned int)remaining); if (nbytes == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("Could not write Perfdata save file: %s: %s\n", - destfile, os::strerror(errno)); - } + log_debug(perf)("could not write PerfData save file: %s: %s", + destfile, os::strerror(errno)); break; } @@ -117,10 +112,8 @@ static void save_memory_to_file(char* addr, size_t size) { } int result = ::_close(fd); - if (PrintMiscellaneous && Verbose) { - if (result == OS_ERR) { - warning("Could not close %s: %s\n", destfile, os::strerror(errno)); - } + if (result == OS_ERR) { + log_debug(perf)("could not close %s: %s", destfile, os::strerror(errno)); } } @@ -220,10 +213,8 @@ static bool is_directory_secure(const char* path) { } else { // unexpected error, declare the path insecure - if (PrintMiscellaneous && Verbose) { - warning("could not get attributes for file %s: " - " lasterror = %d\n", path, lasterror); - } + log_debug(perf)("could not get attributes for file %s: lasterror = %d", + path, lasterror); return false; } } @@ -234,9 +225,7 @@ static bool is_directory_secure(const char* path) { // as some types of reparse points might be acceptable, but it // is probably more secure to avoid these conditions. // - if (PrintMiscellaneous && Verbose) { - warning("%s is a reparse point\n", path); - } + log_debug(perf)("%s is a reparse point", path); return false; } @@ -253,10 +242,8 @@ static bool is_directory_secure(const char* path) { // this is either a regular file or some other type of file, // any of which are unexpected and therefore insecure. // - if (PrintMiscellaneous && Verbose) { - warning("%s is not a directory, file attributes = " - INTPTR_FORMAT "\n", path, fa); - } + log_debug(perf)("%s is not a directory, file attributes : " + INTPTR_FORMAT, path, fa); return false; } } @@ -492,11 +479,9 @@ static void remove_file(const char* dirname, const char* filename) { strcat(path, filename); if (::unlink(path) == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - if (errno != ENOENT) { - warning("Could not unlink shared memory backing" - " store file %s : %s\n", path, os::strerror(errno)); - } + if (errno != ENOENT) { + log_debug(perf)("could not unlink shared memory backing store file %s : %s", + path, os::strerror(errno)); } } @@ -515,20 +500,16 @@ static bool is_alive(int pid) { HANDLE ph = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); if (ph == nullptr) { // the process does not exist. - if (PrintMiscellaneous && Verbose) { - DWORD lastError = GetLastError(); - if (lastError != ERROR_INVALID_PARAMETER) { - warning("OpenProcess failed: %d\n", GetLastError()); - } + DWORD lastError = GetLastError(); + if (lastError != ERROR_INVALID_PARAMETER) { + log_debug(perf)("OpenProcess failed: %d", lastError); } return false; } DWORD exit_status; if (!GetExitCodeProcess(ph, &exit_status)) { - if (PrintMiscellaneous && Verbose) { - warning("GetExitCodeProcess failed: %d\n", GetLastError()); - } + log_debug(perf)("GetExitCodeProcess failed: %d", GetLastError()); CloseHandle(ph); return false; } @@ -545,17 +526,13 @@ static bool is_filesystem_secure(const char* path) { char fs_type[MAX_PATH]; if (PerfBypassFileSystemCheck) { - if (PrintMiscellaneous && Verbose) { - warning("bypassing file system criteria checks for %s\n", path); - } + log_debug(perf)("bypassing file system criteria checks for %s", path); return true; } char* first_colon = strchr((char *)path, ':'); if (first_colon == nullptr) { - if (PrintMiscellaneous && Verbose) { - warning("expected device specifier in path: %s\n", path); - } + log_debug(perf)("expected device specifier in path: %s", path); return false; } @@ -576,29 +553,22 @@ static bool is_filesystem_secure(const char* path) { if (!GetVolumeInformation(root_path, nullptr, 0, nullptr, &maxpath, &flags, fs_type, MAX_PATH)) { // we can't get information about the volume, so assume unsafe. - if (PrintMiscellaneous && Verbose) { - warning("could not get device information for %s: " - " path = %s: lasterror = %d\n", - root_path, path, GetLastError()); - } + log_debug(perf)("could not get device information for %s: path = %s: lasterror = %d", + root_path, path, GetLastError()); return false; } if ((flags & FS_PERSISTENT_ACLS) == 0) { // file system doesn't support ACLs, declare file system unsafe - if (PrintMiscellaneous && Verbose) { - warning("file system type %s on device %s does not support" - " ACLs\n", fs_type, root_path); - } + log_debug(perf)("file system type %s on device %s does not support ACLs", + fs_type, root_path); return false; } if ((flags & FS_VOL_IS_COMPRESSED) != 0) { // file system is compressed, declare file system unsafe - if (PrintMiscellaneous && Verbose) { - warning("file system type %s on device %s is compressed\n", - fs_type, root_path); - } + log_debug(perf)("file system type %s on device %s is compressed", + fs_type, root_path); return false; } @@ -704,9 +674,7 @@ static HANDLE create_file_mapping(const char* name, HANDLE fh, LPSECURITY_ATTRIB name); /* LPCTSTR name for object */ if (fmh == nullptr) { - if (PrintMiscellaneous && Verbose) { - warning("CreateFileMapping failed, lasterror = %d\n", GetLastError()); - } + log_debug(perf)("CreateFileMapping failed, lasterror = %d", GetLastError()); return nullptr; } @@ -717,9 +685,7 @@ static HANDLE create_file_mapping(const char* name, HANDLE fh, LPSECURITY_ATTRIB // the other processes either exit or close their mapping objects // and/or mapped views of this mapping object. // - if (PrintMiscellaneous && Verbose) { - warning("file mapping already exists, lasterror = %d\n", GetLastError()); - } + log_debug(perf)("file mapping already exists, lasterror = %d", GetLastError()); CloseHandle(fmh); return nullptr; @@ -783,9 +749,7 @@ static PSID get_user_sid(HANDLE hProcess) { // get the process token if (!OpenProcessToken(hProcess, TOKEN_READ, &hAccessToken)) { - if (PrintMiscellaneous && Verbose) { - warning("OpenProcessToken failure: lasterror = %d \n", GetLastError()); - } + log_debug(perf)("OpenProcessToken failure: lasterror = %d", GetLastError()); return nullptr; } @@ -795,10 +759,8 @@ static PSID get_user_sid(HANDLE hProcess) { if (!GetTokenInformation(hAccessToken, TokenUser, nullptr, rsize, &rsize)) { DWORD lasterror = GetLastError(); if (lasterror != ERROR_INSUFFICIENT_BUFFER) { - if (PrintMiscellaneous && Verbose) { - warning("GetTokenInformation failure: lasterror = %d," - " rsize = %d\n", lasterror, rsize); - } + log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d", + lasterror, rsize); CloseHandle(hAccessToken); return nullptr; } @@ -808,10 +770,8 @@ static PSID get_user_sid(HANDLE hProcess) { // get the user token information if (!GetTokenInformation(hAccessToken, TokenUser, token_buf, rsize, &rsize)) { - if (PrintMiscellaneous && Verbose) { - warning("GetTokenInformation failure: lasterror = %d," - " rsize = %d\n", GetLastError(), rsize); - } + log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d", + GetLastError(), rsize); FREE_C_HEAP_ARRAY(char, token_buf); CloseHandle(hAccessToken); return nullptr; @@ -821,10 +781,8 @@ static PSID get_user_sid(HANDLE hProcess) { PSID pSID = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); if (!CopySid(nbytes, pSID, token_buf->User.Sid)) { - if (PrintMiscellaneous && Verbose) { - warning("GetTokenInformation failure: lasterror = %d," - " rsize = %d\n", GetLastError(), rsize); - } + log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d", + GetLastError(), rsize); FREE_C_HEAP_ARRAY(char, token_buf); FREE_C_HEAP_ARRAY(char, pSID); CloseHandle(hAccessToken); @@ -866,10 +824,8 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, // retrieve any existing access control list. if (!GetSecurityDescriptorDacl(pSD, &exists, &oldACL, &isdefault)) { - if (PrintMiscellaneous && Verbose) { - warning("GetSecurityDescriptor failure: lasterror = %d \n", - GetLastError()); - } + log_debug(perf)("GetSecurityDescriptor failure: lasterror = %d", + GetLastError()); return false; } @@ -886,10 +842,8 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, if (!GetAclInformation(oldACL, &aclinfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) { - if (PrintMiscellaneous && Verbose) { - warning("GetAclInformation failure: lasterror = %d \n", GetLastError()); - return false; - } + log_debug(perf)("GetAclInformation failure: lasterror = %d", GetLastError()); + return false; } } else { aclinfo.AceCount = 0; // assume null DACL @@ -914,9 +868,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, newACL = (PACL) NEW_C_HEAP_ARRAY(char, newACLsize, mtInternal); if (!InitializeAcl(newACL, newACLsize, ACL_REVISION)) { - if (PrintMiscellaneous && Verbose) { - warning("InitializeAcl failure: lasterror = %d \n", GetLastError()); - } + log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError()); FREE_C_HEAP_ARRAY(char, newACL); return false; } @@ -927,9 +879,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, while (ace_index < aclinfo.AceCount) { LPVOID ace; if (!GetAce(oldACL, ace_index, &ace)) { - if (PrintMiscellaneous && Verbose) { - warning("InitializeAcl failure: lasterror = %d \n", GetLastError()); - } + log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError()); FREE_C_HEAP_ARRAY(char, newACL); return false; } @@ -954,9 +904,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, if (matches == 0) { if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace, ((PACE_HEADER)ace)->AceSize)) { - if (PrintMiscellaneous && Verbose) { - warning("AddAce failure: lasterror = %d \n", GetLastError()); - } + log_debug(perf)("AddAce failure: lasterror = %d", GetLastError()); FREE_C_HEAP_ARRAY(char, newACL); return false; } @@ -969,10 +917,8 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, for (int i = 0; i < ace_count; i++) { if (!AddAccessAllowedAce(newACL, ACL_REVISION, aces[i].mask, aces[i].pSid)) { - if (PrintMiscellaneous && Verbose) { - warning("AddAccessAllowedAce failure: lasterror = %d \n", - GetLastError()); - } + log_debug(perf)("AddAccessAllowedAce failure: lasterror = %d", + GetLastError()); FREE_C_HEAP_ARRAY(char, newACL); return false; } @@ -985,17 +931,13 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, while (ace_index < aclinfo.AceCount) { LPVOID ace; if (!GetAce(oldACL, ace_index, &ace)) { - if (PrintMiscellaneous && Verbose) { - warning("InitializeAcl failure: lasterror = %d \n", GetLastError()); - } + log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError()); FREE_C_HEAP_ARRAY(char, newACL); return false; } if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace, ((PACE_HEADER)ace)->AceSize)) { - if (PrintMiscellaneous && Verbose) { - warning("AddAce failure: lasterror = %d \n", GetLastError()); - } + log_debug(perf)("AddAce failure: lasterror = %d", GetLastError()); FREE_C_HEAP_ARRAY(char, newACL); return false; } @@ -1005,10 +947,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, // add the new ACL to the security descriptor. if (!SetSecurityDescriptorDacl(pSD, TRUE, newACL, FALSE)) { - if (PrintMiscellaneous && Verbose) { - warning("SetSecurityDescriptorDacl failure:" - " lasterror = %d \n", GetLastError()); - } + log_debug(perf)("SetSecurityDescriptorDacl failure: lasterror = %d", GetLastError()); FREE_C_HEAP_ARRAY(char, newACL); return false; } @@ -1025,10 +964,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, // protected prevents that. if (!_SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { - if (PrintMiscellaneous && Verbose) { - warning("SetSecurityDescriptorControl failure:" - " lasterror = %d \n", GetLastError()); - } + log_debug(perf)("SetSecurityDescriptorControl failure: lasterror = %d", GetLastError()); FREE_C_HEAP_ARRAY(char, newACL); return false; } @@ -1057,10 +993,7 @@ static LPSECURITY_ATTRIBUTES make_security_attr(ace_data_t aces[], int count) { // initialize the security descriptor if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { - if (PrintMiscellaneous && Verbose) { - warning("InitializeSecurityDescriptor failure: " - "lasterror = %d \n", GetLastError()); - } + log_debug(perf)("InitializeSecurityDescriptor failure: lasterror = %d", GetLastError()); free_security_desc(pSD); return nullptr; } @@ -1113,11 +1046,7 @@ static LPSECURITY_ATTRIBUTES make_user_everybody_admin_security_attr( SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsSid)) { - - if (PrintMiscellaneous && Verbose) { - warning("AllocateAndInitializeSid failure: " - "lasterror = %d \n", GetLastError()); - } + log_debug(perf)("AllocateAndInitializeSid failure: lasterror = %d", GetLastError()); return nullptr; } @@ -1131,11 +1060,7 @@ static LPSECURITY_ATTRIBUTES make_user_everybody_admin_security_attr( if (!AllocateAndInitializeSid( &SIDAuthEverybody, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everybodySid)) { - - if (PrintMiscellaneous && Verbose) { - warning("AllocateAndInitializeSid failure: " - "lasterror = %d \n", GetLastError()); - } + log_debug(perf)("AllocateAndInitializeSid failure: lasterror = %d", GetLastError()); return nullptr; } @@ -1236,9 +1161,7 @@ static bool make_user_tmp_dir(const char* dirname) { // if (!is_directory_secure(dirname)) { // directory is not secure - if (PrintMiscellaneous && Verbose) { - warning("%s directory is insecure\n", dirname); - } + log_debug(perf)("%s directory is insecure", dirname); free_security_attr(pDirSA); return false; } @@ -1249,16 +1172,11 @@ static bool make_user_tmp_dir(const char* dirname) { // DACLs might fix the corrupted the DACLs. SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION; if (!SetFileSecurity(dirname, secInfo, pDirSA->lpSecurityDescriptor)) { - if (PrintMiscellaneous && Verbose) { - lasterror = GetLastError(); - warning("SetFileSecurity failed for %s directory. lasterror %d \n", - dirname, lasterror); - } + lasterror = GetLastError(); + log_debug(perf)("SetFileSecurity failed for %s directory. lasterror = %d", dirname, lasterror); } } else { - if (PrintMiscellaneous && Verbose) { - warning("CreateDirectory failed: %d\n", GetLastError()); - } + log_debug(perf)("CreateDirectory failed: %d", GetLastError()); free_security_attr(pDirSA); return false; } @@ -1325,9 +1243,7 @@ static HANDLE create_sharedmem_resources(const char* dirname, const char* filena if (fh == INVALID_HANDLE_VALUE) { DWORD lasterror = GetLastError(); - if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %d\n", filename, lasterror); - } + log_debug(perf)("could not create file %s: %d", filename, lasterror); free_security_attr(lpSmoSA); return nullptr; } @@ -1353,10 +1269,8 @@ static HANDLE create_sharedmem_resources(const char* dirname, const char* filena struct stat statbuf; int ret_code = ::stat(filename, &statbuf); if (ret_code == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("Could not get status information from file %s: %s\n", - filename, os::strerror(errno)); - } + log_debug(perf)("could not get status information from file %s: %s", + filename, os::strerror(errno)); CloseHandle(fmh); CloseHandle(fh); fh = nullptr; @@ -1369,9 +1283,7 @@ static HANDLE create_sharedmem_resources(const char* dirname, const char* filena // call it when we observe the size as zero (0). if (statbuf.st_size == 0 && FlushFileBuffers(fh) != TRUE) { DWORD lasterror = GetLastError(); - if (PrintMiscellaneous && Verbose) { - warning("could not flush file %s: %d\n", filename, lasterror); - } + log_debug(perf)("could not flush file %s: %d", filename, lasterror); CloseHandle(fmh); CloseHandle(fh); fh = nullptr; @@ -1402,10 +1314,8 @@ static HANDLE open_sharedmem_object(const char* objectname, DWORD ofm_access, TR if (fmh == nullptr) { DWORD lasterror = GetLastError(); - if (PrintMiscellaneous && Verbose) { - warning("OpenFileMapping failed for shared memory object %s:" - " lasterror = %d\n", objectname, lasterror); - } + log_debug(perf)("OpenFileMapping failed for shared memory object %s:" + " lasterror = %d", objectname, lasterror); THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Could not open PerfMemory, error %d", lasterror), INVALID_HANDLE_VALUE); @@ -1485,9 +1395,7 @@ static char* mapping_create_shared(size_t size) { (DWORD)size); /* DWORD Number of bytes to map */ if (mapAddress == nullptr) { - if (PrintMiscellaneous && Verbose) { - warning("MapViewOfFile failed, lasterror = %d\n", GetLastError()); - } + log_debug(perf)("MapViewOfFile failed, lasterror = %d", GetLastError()); CloseHandle(sharedmem_fileMapHandle); sharedmem_fileMapHandle = nullptr; return nullptr; @@ -1551,20 +1459,14 @@ static size_t sharedmem_filesize(const char* filename, TRAPS) { // inconsistencies // if (::stat(filename, &statbuf) == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("stat %s failed: %s\n", filename, os::strerror(errno)); - } + log_debug(perf)("stat %s failed: %s", filename, os::strerror(errno)); THROW_MSG_0(vmSymbols::java_io_IOException(), "Could not determine PerfMemory size"); } if ((statbuf.st_size == 0) || (statbuf.st_size % os::vm_page_size() != 0)) { - if (PrintMiscellaneous && Verbose) { - warning("unexpected file size: size = %zu\n", - statbuf.st_size); - } - THROW_MSG_0(vmSymbols::java_io_IOException(), - "Invalid PerfMemory size"); + log_debug(perf)("unexpected file size: size = %zu", statbuf.st_size); + THROW_MSG_0(vmSymbols::java_io_IOException(), "Invalid PerfMemory size"); } return statbuf.st_size; @@ -1637,9 +1539,7 @@ static void open_file_mapping(int vmid, char** addrp, size_t* sizep, TRAPS) { size); /* DWORD Number of bytes to map */ if (mapAddress == nullptr) { - if (PrintMiscellaneous && Verbose) { - warning("MapViewOfFile failed, lasterror = %d\n", GetLastError()); - } + log_debug(perf)("MapViewOfFile failed, lasterror = %d", GetLastError()); CloseHandle(fmh); THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Could not map PerfMemory"); @@ -1708,9 +1608,7 @@ void PerfMemory::create_memory_region(size_t size) { // creation of the shared memory region failed, attempt // to create a contiguous, non-shared memory region instead. // - if (PrintMiscellaneous && Verbose) { - warning("Reverting to non-shared PerfMemory region.\n"); - } + log_debug(perf)("Reverting to non-shared PerfMemory region."); FLAG_SET_ERGO(PerfDisableSharedMem, true); _start = create_standard_memory(size); } diff --git a/src/hotspot/share/runtime/perfMemory.cpp b/src/hotspot/share/runtime/perfMemory.cpp index a75a41e95a9..9594149333e 100644 --- a/src/hotspot/share/runtime/perfMemory.cpp +++ b/src/hotspot/share/runtime/perfMemory.cpp @@ -114,9 +114,7 @@ void PerfMemory::initialize() { // the warning is issued only in debug mode in order to avoid // additional output to the stdout or stderr output streams. // - if (PrintMiscellaneous && Verbose) { - warning("Could not create PerfData Memory region, reverting to malloc"); - } + log_debug(perf)("could not create PerfData Memory region, reverting to malloc"); _prologue = NEW_C_HEAP_OBJ(PerfDataPrologue, mtInternal); } @@ -250,10 +248,7 @@ char* PerfMemory::get_perfdata_file_path() { if(!Arguments::copy_expand_pid(PerfDataSaveFile, strlen(PerfDataSaveFile), dest_file, JVM_MAXPATHLEN)) { FREE_C_HEAP_ARRAY(char, dest_file); - if (PrintMiscellaneous && Verbose) { - warning("Invalid performance data file path name specified, "\ - "fall back to a default name"); - } + log_debug(perf)("invalid performance data file path name specified, fall back to a default name"); } else { return dest_file; } From cbbb0a8630c991ba3a9e703ace47b479e944ce27 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Wed, 22 Oct 2025 11:20:43 +0000 Subject: [PATCH 020/736] 8367976: Validate and clamp jdk.httpclient.bufsize Reviewed-by: dfuchs --- .../jdk/internal/net/http/common/Utils.java | 19 ++- .../share/classes/module-info.java | 4 +- .../java/net/httpclient/BufferSize1Test.java | 158 ++++++++++++++++++ .../BufferSizePropertyClampTest.java | 106 ++++++++++++ .../OfByteArrayTest.java | 7 - 5 files changed, 279 insertions(+), 15 deletions(-) create mode 100644 test/jdk/java/net/httpclient/BufferSize1Test.java create mode 100644 test/jdk/java/net/httpclient/BufferSizePropertyClampTest.java diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java index b14d76d8dba..a02506cff5c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java @@ -174,15 +174,20 @@ public final class Utils { public static final int SLICE_THRESHOLD = 32; /** - * Allocated buffer size. Must never be higher than 16K. But can be lower - * if smaller allocation units preferred. HTTP/2 mandates that all - * implementations support frame payloads of at least 16K. + * The capacity of ephemeral {@link ByteBuffer}s allocated to pass data to and from the client. + * It is ensured to have a value between 1 and 2^14 (16,384). */ - private static final int DEFAULT_BUFSIZE = 16 * 1024; - public static final int BUFSIZE = getIntegerNetProperty( - "jdk.httpclient.bufsize", DEFAULT_BUFSIZE - ); + "jdk.httpclient.bufsize", 1, + // We cap at 2^14 (16,384) for two main reasons: + // - The initial frame size is 2^14 (RFC 9113) + // - SSL record layer fragments data in chunks of 2^14 bytes or less (RFC 5246) + 1 << 14, + // We choose 2^14 (16,384) as the default, because: + // 1. It maximizes throughput within the limits described above + // 2. It is small enough to not create a GC bottleneck when it is partially filled + 1 << 14, + true); public static final BiPredicate ACCEPT_ALL = (x,y) -> true; diff --git a/src/java.net.http/share/classes/module-info.java b/src/java.net.http/share/classes/module-info.java index 392385136b0..48f23953ad0 100644 --- a/src/java.net.http/share/classes/module-info.java +++ b/src/java.net.http/share/classes/module-info.java @@ -48,7 +48,9 @@ * depending on the context. These restrictions cannot be overridden by this property. * *

  • {@systemProperty jdk.httpclient.bufsize} (default: 16384 bytes or 16 kB)
    - * The size to use for internal allocated buffers in bytes. + * The capacity of internal ephemeral buffers allocated to pass data to and from the + * client, in bytes. Valid values are in the range [1, 2^14 (16384)]. + * If an invalid value is provided, the default value is used. *

  • *
  • {@systemProperty jdk.httpclient.connectionPoolSize} (default: 0)
    * The maximum number of connections to keep in the HTTP/1.1 keep alive cache. A value of 0 diff --git a/test/jdk/java/net/httpclient/BufferSize1Test.java b/test/jdk/java/net/httpclient/BufferSize1Test.java new file mode 100644 index 00000000000..842dc06a630 --- /dev/null +++ b/test/jdk/java/net/httpclient/BufferSize1Test.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.httpclient.test.lib.common.HttpServerAdapters; +import jdk.internal.net.http.common.Utils; +import jdk.test.lib.net.SimpleSSLContext; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.Version.HTTP_1_1; +import static java.net.http.HttpClient.Version.HTTP_2; +import static java.net.http.HttpClient.Version.HTTP_3; +import static java.net.http.HttpOption.H3_DISCOVERY; +import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test id + * @bug 8367976 + * @summary Verifies that setting the `jdk.httpclient.bufsize` system property + * to its lowest possible value, 1, does not wedge the client + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * @run junit/othervm -Djdk.httpclient.bufsize=1 BufferSize1Test + */ + +class BufferSize1Test implements HttpServerAdapters { + + @BeforeAll + static void verifyBufferSize() { + assertEquals(1, Utils.BUFSIZE); + } + + static Object[][] testArgs() { + return new Object[][]{ + {HTTP_1_1, false}, + {HTTP_1_1, true}, + {HTTP_2, false}, + {HTTP_2, true}, + {HTTP_3, true} + }; + } + + @ParameterizedTest + @MethodSource("testArgs") + void test(Version version, boolean secure) throws Exception { + + // Create the server + var sslContext = secure || HTTP_3.equals(version) ? new SimpleSSLContext().get() : null; + try (var server = switch (version) { + case HTTP_1_1, HTTP_2 -> HttpTestServer.create(version, sslContext); + case HTTP_3 -> HttpTestServer.create(HTTP_3_URI_ONLY, sslContext); + }) { + + // Add the handler and start the server + var serverHandlerPath = "/" + BufferSize1Test.class.getSimpleName(); + server.addHandler(new HttpTestEchoHandler(), serverHandlerPath); + server.start(); + + // Create the client + try (var client = createClient(version, sslContext)) { + + // Create the request with body to ensure that `ByteBuffer`s + // will be used throughout the entire end-to-end interaction. + byte[] requestBodyBytes = "body".repeat(1000).getBytes(StandardCharsets.US_ASCII); + var request = createRequest(sslContext, server, serverHandlerPath, version, requestBodyBytes); + + // Execute and verify the request. + // Do it twice to cover code paths before and after a protocol upgrade. + requestAndVerify(client, request, requestBodyBytes); + requestAndVerify(client, request, requestBodyBytes); + + } + + } + + } + + private HttpClient createClient(Version version, SSLContext sslContext) { + var clientBuilder = newClientBuilderForH3() + .proxy(NO_PROXY) + .version(version); + if (sslContext != null) { + clientBuilder.sslContext(sslContext); + } + return clientBuilder.build(); + } + + private static HttpRequest createRequest( + SSLContext sslContext, + HttpTestServer server, + String serverHandlerPath, + Version version, + byte[] requestBodyBytes) { + var requestUri = URI.create(String.format( + "%s://%s%s/x", + sslContext == null ? "http" : "https", + server.serverAuthority(), + serverHandlerPath)); + var requestBuilder = HttpRequest + .newBuilder(requestUri) + .version(version) + .POST(HttpRequest.BodyPublishers.ofByteArray(requestBodyBytes)); + if (HTTP_3.equals(version)) { + requestBuilder.setOption(H3_DISCOVERY, HTTP_3_URI_ONLY); + } + return requestBuilder.build(); + } + + private static void requestAndVerify(HttpClient client, HttpRequest request, byte[] requestBodyBytes) + throws IOException, InterruptedException { + var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray()); + if (response.statusCode() != 200) { + throw new AssertionError("Was expecting status code 200, found: " + response.statusCode()); + } + byte[] responseBodyBytes = response.body(); + int mismatchIndex = Arrays.mismatch(requestBodyBytes, responseBodyBytes); + assertTrue( + mismatchIndex < 0, + String.format( + "Response body (%s bytes) mismatches the request body (%s bytes) at index %s!", + responseBodyBytes.length, requestBodyBytes.length, mismatchIndex)); + } + +} diff --git a/test/jdk/java/net/httpclient/BufferSizePropertyClampTest.java b/test/jdk/java/net/httpclient/BufferSizePropertyClampTest.java new file mode 100644 index 00000000000..caef0a58a6d --- /dev/null +++ b/test/jdk/java/net/httpclient/BufferSizePropertyClampTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.net.http.common.Utils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/* + * @test + * @bug 8367976 + * @summary Verifies that the `jdk.httpclient.bufsize` system property is + * clamped correctly + * + * @library /test/lib + * + * @comment `-Djdk.httpclient.HttpClient.log=errors` is needed to enable + * logging and verify that invalid input gets logged + * @run junit/othervm + * -Djdk.httpclient.HttpClient.log=errors + * -Djdk.httpclient.bufsize=-1 + * BufferSizePropertyClampTest + * @run junit/othervm + * -Djdk.httpclient.HttpClient.log=errors + * -Djdk.httpclient.bufsize=0 + * BufferSizePropertyClampTest + * @run junit/othervm + * -Djdk.httpclient.HttpClient.log=errors + * -Djdk.httpclient.bufsize=16385 + * BufferSizePropertyClampTest + */ + +class BufferSizePropertyClampTest { + + /** Anchor to avoid the {@code Logger} instance get GC'ed */ + private static final Logger CLIENT_LOGGER = + Logger.getLogger("jdk.httpclient.HttpClient"); + + private static final List CLIENT_LOGGER_MESSAGES = + Collections.synchronizedList(new ArrayList<>()); + + @BeforeAll + static void registerLoggerHandler() { + CLIENT_LOGGER.addHandler(new Handler() { + + @Override + public void publish(LogRecord record) { + var message = MessageFormat.format(record.getMessage(), record.getParameters()); + CLIENT_LOGGER_MESSAGES.add(message); + } + + @Override + public void flush() { + // Do nothing + } + + @Override + public void close() { + // Do nothing + } + + }); + } + + @Test + void test() { + assertEquals(16384, Utils.BUFSIZE); + assertEquals( + 1, CLIENT_LOGGER_MESSAGES.size(), + "Unexpected number of logger messages: " + CLIENT_LOGGER_MESSAGES); + var expectedMessage = "ERROR: Property value for jdk.httpclient.bufsize=" + + System.getProperty("jdk.httpclient.bufsize") + + " not in [1..16384]: using default=16384"; + assertEquals(expectedMessage, CLIENT_LOGGER_MESSAGES.getFirst().replaceAll(",", "")); + } + +} diff --git a/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArrayTest.java b/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArrayTest.java index 9973272b435..19f7369125d 100644 --- a/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArrayTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArrayTest.java @@ -43,8 +43,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; * @run junit OfByteArrayTest * * @comment Using `main/othervm` to initiate tests that depend on a custom-configured JVM - * @run main/othervm -Djdk.httpclient.bufsize=-1 OfByteArrayTest testInvalidBufferSize - * @run main/othervm -Djdk.httpclient.bufsize=0 OfByteArrayTest testInvalidBufferSize * @run main/othervm -Djdk.httpclient.bufsize=3 OfByteArrayTest testChunking "" 0 0 "" * @run main/othervm -Djdk.httpclient.bufsize=3 OfByteArrayTest testChunking a 0 0 "" * @run main/othervm -Djdk.httpclient.bufsize=3 OfByteArrayTest testChunking a 1 0 "" @@ -88,7 +86,6 @@ public class OfByteArrayTest { */ public static void main(String[] args) throws InterruptedException { switch (args[0]) { - case "testInvalidBufferSize" -> testInvalidBufferSize(); case "testChunking" -> testChunking( parseStringArg(args[1]), Integer.parseInt(args[2]), @@ -102,10 +99,6 @@ public class OfByteArrayTest { return arg == null || arg.trim().equals("\"\"") ? "" : arg; } - private static void testInvalidBufferSize() { - assertThrows(IllegalArgumentException.class, () -> HttpRequest.BodyPublishers.ofByteArray(new byte[1])); - } - private static void testChunking( String contentText, int offset, int length, String expectedBuffersText) throws InterruptedException { From 65b32394187988abab99a8017eda39b1bd4a1782 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 22 Oct 2025 11:27:11 +0000 Subject: [PATCH 021/736] 8370242: JFR: Clear event reference eagerly when using EventStream Reviewed-by: mgronlun --- .../jdk/jfr/internal/consumer/EventDirectoryStream.java | 5 +++++ .../classes/jdk/jfr/internal/consumer/EventFileStream.java | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java index 46dab564ac0..c8db9aef169 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java @@ -257,6 +257,11 @@ public final class EventDirectoryStream extends AbstractEventStream { } for (int i = 0; i < index; i++) { c.dispatch(sortedCache[i]); + sortedCache[i] = null; + } + // Shrink array + if (index > 100_000 && 4 * index < sortedCache.length) { + sortedCache = new RecordedEvent[2 * index]; } onFlush(); return; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java index 56d9fe01d79..82712fcbedc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java @@ -127,6 +127,10 @@ public final class EventFileStream extends AbstractEventStream { cacheSorted[index++] = event; } dispatchOrdered(c, index); + if (index > 100_000 && 4 * index < cacheSorted.length) { + cacheSorted = new RecordedEvent[2 * index]; + } + onFlush(); index = 0; } } @@ -136,8 +140,8 @@ public final class EventFileStream extends AbstractEventStream { Arrays.sort(cacheSorted, 0, index, EVENT_COMPARATOR); for (int i = 0; i < index; i++) { c.dispatch(cacheSorted[i]); + cacheSorted[i] = null; } - onFlush(); } private void processUnordered(Dispatcher c) throws IOException { From 92e380c59c2498b1bc94e26658b07b383deae59a Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 22 Oct 2025 12:34:17 +0000 Subject: [PATCH 022/736] 8361451: Test vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java fails with OutOfMemoryError: Metaspace Reviewed-by: dholmes, lmesnik, iklam, syan --- .../stressHierarchy/common/PerformChecksHelper.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/PerformChecksHelper.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/PerformChecksHelper.java index 3d57bfb6ea9..e660dac4fd5 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/PerformChecksHelper.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/PerformChecksHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,8 +136,17 @@ public class PerformChecksHelper { } } } + } catch (InvocationTargetException ite) { + Throwable cause = ite.getCause(); + if (cause != null && (cause instanceof OutOfMemoryError) && cause.getMessage().contains("Metaspace")) { + // avoid string concatenation, which may create more classes. + System.out.println("Got OOME in metaspace in PerformChecksHelper.callMethods(Class clazz). "); + System.out.println("This is possible with -triggerUnloadingByFillingMetaspace"); + } else { + throw ite; + } } catch (OutOfMemoryError e) { - if (e.getMessage().trim().toLowerCase().contains("metaspace")) { + if (e.getMessage().contains("Metaspace")) { // avoid string concatenation, which may create more classes. System.out.println("Got OOME in metaspace in PerformChecksHelper.callMethods(Class clazz). "); System.out.println("This is possible with -triggerUnloadingByFillingMetaspace"); From afba636869bc297d0c9c29fbe7f2a1eb5929218b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Wed, 22 Oct 2025 17:39:41 +0000 Subject: [PATCH 023/736] 8369991: Thread blocking during JFR emergency dump must be in safepoint safe state Reviewed-by: fandreuzzi, egahlin --- .../jfr/recorder/repository/jfrEmergencyDump.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp index 5163bc7f6a5..309ae961808 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp @@ -458,6 +458,7 @@ const char* JfrEmergencyDump::chunk_path(const char* repository_path) { */ static void release_locks(Thread* thread) { assert(thread != nullptr, "invariant"); + assert(!thread->is_Java_thread() || JavaThread::cast(thread)->thread_state() == _thread_in_vm, "invariant"); #ifdef ASSERT Mutex* owned_lock = thread->owned_locks(); @@ -519,13 +520,14 @@ static void release_locks(Thread* thread) { class JavaThreadInVMAndNative : public StackObj { private: - JavaThread* const _jt; + JavaThread* _jt; JavaThreadState _original_state; public: - JavaThreadInVMAndNative(Thread* t) : _jt(t->is_Java_thread() ? JavaThread::cast(t) : nullptr), + JavaThreadInVMAndNative(Thread* t) : _jt(nullptr), _original_state(_thread_max_state) { - if (_jt != nullptr) { + if (t != nullptr && t->is_Java_thread()) { + _jt = JavaThread::cast(t); _original_state = _jt->thread_state(); if (_original_state != _thread_in_vm) { _jt->set_thread_state(_thread_in_vm); @@ -535,6 +537,7 @@ class JavaThreadInVMAndNative : public StackObj { ~JavaThreadInVMAndNative() { if (_original_state != _thread_max_state) { + assert(_jt != nullptr, "invariant"); _jt->set_thread_state(_original_state); } } @@ -574,11 +577,13 @@ static bool guard_reentrancy() { Thread* const thread = Thread::current_or_null_safe(); const traceid tid = thread != nullptr ? JFR_JVM_THREAD_ID(thread) : max_julong; if (AtomicAccess::cmpxchg(&_jfr_shutdown_tid, shutdown_tid, tid) != shutdown_tid) { + JavaThreadInVMAndNative jtivm(thread); if (thread != nullptr) { - JavaThreadInVMAndNative jtivm(thread); release_locks(thread); } log_info(jfr, system)("A jfr emergency dump is already in progress, waiting for thread id " UINT64_FORMAT_X, AtomicAccess::load(&_jfr_shutdown_tid)); + // Transition to a safe safepoint state for the infinite sleep. A nop for non-java threads. + jtivm.transition_to_native(); os::infinite_sleep(); // stay here until we exit normally or crash. ShouldNotReachHere(); } From a925461395dc1bc81b70aa49e8869a143d170f31 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Oct 2025 18:08:19 +0000 Subject: [PATCH 024/736] 8370442: Compilation error in jpackage EntitlementsTest test Reviewed-by: almatvee --- .../jdk/jpackage/test/AnnotationsTest.java | 14 +++ .../jdk/jpackage/test/JPackageCommand.java | 11 ++ .../helpers/jdk/jpackage/test/MacHelper.java | 11 ++ .../jpackage/macosx/EntitlementsTest.java | 116 +++++++++++------- 4 files changed, 109 insertions(+), 43 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java index e16b175ab8a..f88d1f81a34 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -95,6 +95,18 @@ public class AnnotationsTest extends JUnitAdapter { recordTestCase(a, b, other); } + enum Tack { + STARBOARD, + PORTSIDE; + } + + @Test + @Parameter({"STARBOARD"}) + @Parameter({"PORTSIDE", "STARBOARD"}) + public void testEnumVarArg(Tack ... cource) { + recordTestCase((Object[]) cource); + } + @Test @ParameterSupplier("dateSupplier") @ParameterSupplier("jdk.jpackage.test.AnnotationsTest.dateSupplier") @@ -118,6 +130,8 @@ public class AnnotationsTest extends JUnitAdapter { "().testVarArg2(-89, bar, [more, moore](length=2))", "().testVarArg2(-89, bar, [more](length=1))", "().testVarArg2(12, foo, [](length=0))", + "().testEnumVarArg(STARBOARD)", + "().testEnumVarArg(PORTSIDE, STARBOARD)", "().testDates(2018-05-05)", "().testDates(2018-07-11)", "().testDates(2034-05-05)", diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 22e75a57911..b3729093ad2 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -203,6 +203,17 @@ public class JPackageCommand extends CommandArguments { return addArguments(name, value.toString()); } + public JPackageCommand mutate(Consumer mutator) { + return mutate(List.of(mutator)); + } + + public JPackageCommand mutate(Iterable> mutators) { + for (var mutator : mutators) { + mutator.accept(this); + } + return this; + } + public boolean isImagePackageType() { return PackageType.IMAGE == getArgumentValue("--type", () -> null, PACKAGE_TYPES::get); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index a7a69ef0329..3900851f810 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -54,6 +54,7 @@ import java.util.Properties; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -370,6 +371,16 @@ public final class MacHelper { }).run(); } + public static Consumer useKeychain(MacSign.ResolvedKeychain keychain) { + return useKeychain(keychain.spec().keychain()); + } + + public static Consumer useKeychain(MacSign.Keychain keychain) { + return cmd -> { + useKeychain(cmd, keychain); + }; + } + public static JPackageCommand useKeychain(JPackageCommand cmd, MacSign.ResolvedKeychain keychain) { return useKeychain(cmd, keychain.spec().keychain()); } diff --git a/test/jdk/tools/jpackage/macosx/EntitlementsTest.java b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java index 1d6d86118a6..aa5879e0c61 100644 --- a/test/jdk/tools/jpackage/macosx/EntitlementsTest.java +++ b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java @@ -21,20 +21,26 @@ * questions. */ +import static jdk.jpackage.internal.util.PListWriter.writeBoolean; import static jdk.jpackage.internal.util.PListWriter.writeDict; import static jdk.jpackage.internal.util.PListWriter.writePList; -import static jdk.jpackage.internal.util.PListWriter.writeBoolean; import static jdk.jpackage.internal.util.XmlUtils.createXml; import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import java.io.IOException; import java.nio.file.Path; -import java.util.Date; - -import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.Annotations.Test; +import java.util.function.Consumer; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.test.AdditionalLauncher; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacHelper.SignKeyOption; +import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.TKit; /* * Test generates signed app-image with custom entitlements file from the @@ -61,7 +67,7 @@ import jdk.jpackage.test.Annotations.Parameter; */ public class EntitlementsTest { - void createEntitlementsFile(Path file, boolean microphone) throws IOException { + private static void createEntitlementsFile(Path file, boolean microphone) throws IOException { createXml(file, xml -> { writePList(xml, toXmlConsumer(() -> { writeDict(xml, toXmlConsumer(() -> { @@ -77,47 +83,71 @@ public class EntitlementsTest { }); } - @Test - // ({"--mac-app-store", doMacEntitlements", "doResources"}) - @Parameter({"false", "true", "false"}) - @Parameter({"false", "false", "true"}) - @Parameter({"false", "true", "true"}) - @Parameter({"true", "true", "false"}) - @Parameter({"true", "false", "true"}) - @Parameter({"true", "true", "true"}) - public void test(boolean appStore, boolean doMacEntitlements, boolean doResources) throws Exception { - final Path macEntitlementsFile; - final Path resourcesDir; - - if (doMacEntitlements) { - macEntitlementsFile = TKit.createTempFile("EntitlementsTest.plist"); + public enum EntitlementsSource implements Consumer { + CMDLINE(cmd -> { + var macEntitlementsFile = TKit.createTempFile("foo.plist"); createEntitlementsFile(macEntitlementsFile, true); - } else { - macEntitlementsFile = null; + cmd.addArguments("--mac-entitlements", macEntitlementsFile); + }), + RESOURCE_DIR(cmd -> { + if (!cmd.hasArgument("--resource-dir")) { + cmd.setArgumentValue("--resource-dir", TKit.createTempDirectory("resources")); + } + + var resourcesDir = Path.of(cmd.getArgumentValue("--resource-dir")); + createEntitlementsFile(resourcesDir.resolve(cmd.name() + ".entitlements"), false); + }), + ; + + EntitlementsSource(ThrowingConsumer initializer) { + this.initializer = toConsumer(initializer); } - if (doResources) { - resourcesDir = TKit.createTempDirectory("resources"); - createEntitlementsFile(resourcesDir.resolve("EntitlementsTest.entitlements"), false); - } else { - resourcesDir = null; + @Override + public void accept(JPackageCommand cmd) { + initializer.accept(cmd); } - JPackageCommand cmd = JPackageCommand.helloAppImage() - .addArguments("--mac-sign", "--mac-signing-keychain", - SigningBase.getKeyChain(), "--mac-app-image-sign-identity", - SigningBase.getAppCert(SigningBase.CertIndex.ASCII_INDEX.value())); - if (appStore) { - cmd.addArguments("--mac-app-store"); - } - if (doMacEntitlements) { - cmd.addArguments("--mac-entitlements", - macEntitlementsFile.toAbsolutePath().toString()); - } - if (doResources) { - cmd.addArguments("--resource-dir", - resourcesDir.toAbsolutePath().toString()); - } + private final Consumer initializer; + } + + @Test + @Parameter({"CMDLINE"}) + @Parameter({"RESOURCE_DIR"}) + @Parameter({"CMDLINE", "RESOURCE_DIR"}) + public static void test(EntitlementsSource... entitlementsSources) { + MacSign.withKeychain(toConsumer(keychain -> { + test(keychain, Stream.of(entitlementsSources)); + }), SigningBase.StandardKeychain.MAIN.keychain()); + } + + @Test + @Parameter({"CMDLINE"}) + @Parameter({"RESOURCE_DIR"}) + @Parameter({"CMDLINE", "RESOURCE_DIR"}) + public static void testAppStore(EntitlementsSource... entitlementsSources) { + MacSign.withKeychain(toConsumer(keychain -> { + test(keychain, Stream.concat(Stream.of(cmd -> { + cmd.addArguments("--mac-app-store"); + // Ignore externally supplied runtime as it may have the "bin" + // directory that will cause jpackage to bail out. + cmd.ignoreDefaultRuntime(true); + }), Stream.of(entitlementsSources))); + }), SigningBase.StandardKeychain.MAIN.keychain()); + } + + private static void test(MacSign.ResolvedKeychain keychain, Stream> mutators) { + + var cmd = JPackageCommand.helloAppImage(); + + cmd.mutate(MacHelper.useKeychain(keychain)).mutate(new SignKeyOption( + SignKeyOption.Type.SIGN_KEY_IDENTITY, + SigningBase.StandardCertificateRequest.CODESIGN.spec() + )::addTo); + + cmd.mutate(new AdditionalLauncher("x")::applyTo); + + mutators.forEach(cmd::mutate); cmd.executeAndAssertHelloAppImageCreated(); } From d8ebe387595af43e2cdbbce396547d6daaf8c7dc Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Wed, 22 Oct 2025 19:11:37 +0000 Subject: [PATCH 025/736] 8370377: Avoid resolving constant pool entries during preimage generation in the training run Reviewed-by: adinn, iklam --- .../share/cds/aotConstantPoolResolver.cpp | 31 ++++++ src/hotspot/share/cds/finalImageRecipes.cpp | 8 ++ src/hotspot/share/oops/constantPool.cpp | 21 ++-- src/hotspot/share/oops/cpCache.cpp | 103 +++++++++--------- 4 files changed, 102 insertions(+), 61 deletions(-) diff --git a/src/hotspot/share/cds/aotConstantPoolResolver.cpp b/src/hotspot/share/cds/aotConstantPoolResolver.cpp index 6cc3a81c2ae..8b4e60dece2 100644 --- a/src/hotspot/share/cds/aotConstantPoolResolver.cpp +++ b/src/hotspot/share/cds/aotConstantPoolResolver.cpp @@ -225,7 +225,38 @@ void AOTConstantPoolResolver::preresolve_field_and_method_cp_entries(JavaThread* Bytecodes::Code raw_bc = bcs.raw_code(); switch (raw_bc) { case Bytecodes::_getfield: + // no-fast bytecode + case Bytecodes::_nofast_getfield: + // fast bytecodes + case Bytecodes::_fast_agetfield: + case Bytecodes::_fast_bgetfield: + case Bytecodes::_fast_cgetfield: + case Bytecodes::_fast_dgetfield: + case Bytecodes::_fast_fgetfield: + case Bytecodes::_fast_igetfield: + case Bytecodes::_fast_lgetfield: + case Bytecodes::_fast_sgetfield: + raw_bc = Bytecodes::_getfield; + maybe_resolve_fmi_ref(ik, m, raw_bc, bcs.get_index_u2(), preresolve_list, THREAD); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; // just ignore + } + break; + case Bytecodes::_putfield: + // no-fast bytecode + case Bytecodes::_nofast_putfield: + // fast bytecodes + case Bytecodes::_fast_aputfield: + case Bytecodes::_fast_bputfield: + case Bytecodes::_fast_zputfield: + case Bytecodes::_fast_cputfield: + case Bytecodes::_fast_dputfield: + case Bytecodes::_fast_fputfield: + case Bytecodes::_fast_iputfield: + case Bytecodes::_fast_lputfield: + case Bytecodes::_fast_sputfield: + raw_bc = Bytecodes::_putfield; maybe_resolve_fmi_ref(ik, m, raw_bc, bcs.get_index_u2(), preresolve_list, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; // just ignore diff --git a/src/hotspot/share/cds/finalImageRecipes.cpp b/src/hotspot/share/cds/finalImageRecipes.cpp index dfe74acd6c1..a9bbc398736 100644 --- a/src/hotspot/share/cds/finalImageRecipes.cpp +++ b/src/hotspot/share/cds/finalImageRecipes.cpp @@ -127,6 +127,14 @@ void FinalImageRecipes::record_recipes_for_constantpool() { } if (cp_indices.length() > 0) { + LogStreamHandle(Trace, aot, resolve) log; + if (log.is_enabled()) { + log.print("ConstantPool entries for %s to be pre-resolved:", k->external_name()); + for (int i = 0; i < cp_indices.length(); i++) { + log.print(" %d", cp_indices.at(i)); + } + log.print("\n"); + } tmp_cp_recipes.append(ArchiveUtils::archive_array(&cp_indices)); } else { tmp_cp_recipes.append(nullptr); diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 5d5c0548215..b072c7f26ec 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -538,18 +538,23 @@ void ConstantPool::remove_resolved_klass_if_non_deterministic(int cp_index) { assert(ArchiveBuilder::current()->is_in_buffer_space(this), "must be"); assert(tag_at(cp_index).is_klass(), "must be resolved"); - Klass* k = resolved_klass_at(cp_index); bool can_archive; + Klass* k = nullptr; - if (k == nullptr) { - // We'd come here if the referenced class has been excluded via - // SystemDictionaryShared::is_excluded_class(). As a result, ArchiveBuilder - // has cleared the resolved_klasses()->at(...) pointer to null. Thus, we - // need to revert the tag to JVM_CONSTANT_UnresolvedClass. + if (CDSConfig::is_dumping_preimage_static_archive()) { can_archive = false; } else { - ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this); - can_archive = AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index); + k = resolved_klass_at(cp_index); + if (k == nullptr) { + // We'd come here if the referenced class has been excluded via + // SystemDictionaryShared::is_excluded_class(). As a result, ArchiveBuilder + // has cleared the resolved_klasses()->at(...) pointer to null. Thus, we + // need to revert the tag to JVM_CONSTANT_UnresolvedClass. + can_archive = false; + } else { + ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this); + can_archive = AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index); + } } if (!can_archive) { diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index 941ceac8de1..f60229dbfff 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -430,26 +430,25 @@ void ConstantPoolCache::remove_resolved_field_entries_if_non_deterministic() { bool archived = false; bool resolved = rfi->is_resolved(Bytecodes::_getfield) || rfi->is_resolved(Bytecodes::_putfield); - if (resolved && AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index)) { + if (resolved && !CDSConfig::is_dumping_preimage_static_archive() + && AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index)) { rfi->mark_and_relocate(); archived = true; } else { rfi->remove_unshareable_info(); } - if (resolved) { - LogStreamHandle(Trace, aot, resolve) log; - if (log.is_enabled()) { - ResourceMark rm; - int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index); - Symbol* klass_name = cp->klass_name_at(klass_cp_index); - Symbol* name = cp->uncached_name_ref_at(cp_index); - Symbol* signature = cp->uncached_signature_ref_at(cp_index); - log.print("%s field CP entry [%3d]: %s => %s.%s:%s", - (archived ? "archived" : "reverted"), - cp_index, - cp->pool_holder()->name()->as_C_string(), - klass_name->as_C_string(), name->as_C_string(), signature->as_C_string()); - } + LogStreamHandle(Trace, aot, resolve) log; + if (log.is_enabled()) { + ResourceMark rm; + int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index); + Symbol* klass_name = cp->klass_name_at(klass_cp_index); + Symbol* name = cp->uncached_name_ref_at(cp_index); + Symbol* signature = cp->uncached_signature_ref_at(cp_index); + log.print("%s field CP entry [%3d]: %s => %s.%s:%s", + (archived ? "archived" : "reverted"), + cp_index, + cp->pool_holder()->name()->as_C_string(), + klass_name->as_C_string(), name->as_C_string(), signature->as_C_string()); } ArchiveBuilder::alloc_stats()->record_field_cp_entry(archived, resolved && !archived); } @@ -470,32 +469,31 @@ void ConstantPoolCache::remove_resolved_method_entries_if_non_deterministic() { // Just for safety -- this should not happen, but do not archive if we ever see this. resolved &= !(rme->is_resolved(Bytecodes::_invokestatic)); - if (resolved && can_archive_resolved_method(src_cp, rme)) { + if (resolved && !CDSConfig::is_dumping_preimage_static_archive() + && can_archive_resolved_method(src_cp, rme)) { rme->mark_and_relocate(src_cp); archived = true; } else { rme->remove_unshareable_info(); } - if (resolved) { - LogStreamHandle(Trace, aot, resolve) log; - if (log.is_enabled()) { - ResourceMark rm; - int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index); - Symbol* klass_name = cp->klass_name_at(klass_cp_index); - Symbol* name = cp->uncached_name_ref_at(cp_index); - Symbol* signature = cp->uncached_signature_ref_at(cp_index); - log.print("%s%s method CP entry [%3d]: %s %s.%s:%s", - (archived ? "archived" : "reverted"), - (rme->is_resolved(Bytecodes::_invokeinterface) ? " interface" : ""), - cp_index, - cp->pool_holder()->name()->as_C_string(), - klass_name->as_C_string(), name->as_C_string(), signature->as_C_string()); - if (archived) { - Klass* resolved_klass = cp->resolved_klass_at(klass_cp_index); - log.print(" => %s%s", - resolved_klass->name()->as_C_string(), - (rme->is_resolved(Bytecodes::_invokestatic) ? " *** static" : "")); - } + LogStreamHandle(Trace, aot, resolve) log; + if (log.is_enabled()) { + ResourceMark rm; + int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index); + Symbol* klass_name = cp->klass_name_at(klass_cp_index); + Symbol* name = cp->uncached_name_ref_at(cp_index); + Symbol* signature = cp->uncached_signature_ref_at(cp_index); + log.print("%s%s method CP entry [%3d]: %s %s.%s:%s", + (archived ? "archived" : "reverted"), + (rme->is_resolved(Bytecodes::_invokeinterface) ? " interface" : ""), + cp_index, + cp->pool_holder()->name()->as_C_string(), + klass_name->as_C_string(), name->as_C_string(), signature->as_C_string()); + if (archived) { + Klass* resolved_klass = cp->resolved_klass_at(klass_cp_index); + log.print(" => %s%s", + resolved_klass->name()->as_C_string(), + (rme->is_resolved(Bytecodes::_invokestatic) ? " *** static" : "")); } ArchiveBuilder::alloc_stats()->record_method_cp_entry(archived, resolved && !archived); } @@ -510,29 +508,28 @@ void ConstantPoolCache::remove_resolved_indy_entries_if_non_deterministic() { int cp_index = rei->constant_pool_index(); bool archived = false; bool resolved = rei->is_resolved(); - if (resolved && AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index)) { + if (resolved && !CDSConfig::is_dumping_preimage_static_archive() + && AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index)) { rei->mark_and_relocate(); archived = true; } else { rei->remove_unshareable_info(); } - if (resolved) { - LogStreamHandle(Trace, aot, resolve) log; - if (log.is_enabled()) { - ResourceMark rm; - int bsm = cp->bootstrap_method_ref_index_at(cp_index); - int bsm_ref = cp->method_handle_index_at(bsm); - Symbol* bsm_name = cp->uncached_name_ref_at(bsm_ref); - Symbol* bsm_signature = cp->uncached_signature_ref_at(bsm_ref); - Symbol* bsm_klass = cp->klass_name_at(cp->uncached_klass_ref_index_at(bsm_ref)); - log.print("%s indy CP entry [%3d]: %s (%d)", - (archived ? "archived" : "reverted"), - cp_index, cp->pool_holder()->name()->as_C_string(), i); - log.print(" %s %s.%s:%s", (archived ? "=>" : " "), bsm_klass->as_C_string(), - bsm_name->as_C_string(), bsm_signature->as_C_string()); - } - ArchiveBuilder::alloc_stats()->record_indy_cp_entry(archived, resolved && !archived); + LogStreamHandle(Trace, aot, resolve) log; + if (log.is_enabled()) { + ResourceMark rm; + int bsm = cp->bootstrap_method_ref_index_at(cp_index); + int bsm_ref = cp->method_handle_index_at(bsm); + Symbol* bsm_name = cp->uncached_name_ref_at(bsm_ref); + Symbol* bsm_signature = cp->uncached_signature_ref_at(bsm_ref); + Symbol* bsm_klass = cp->klass_name_at(cp->uncached_klass_ref_index_at(bsm_ref)); + log.print("%s indy CP entry [%3d]: %s (%d)", + (archived ? "archived" : "reverted"), + cp_index, cp->pool_holder()->name()->as_C_string(), i); + log.print(" %s %s.%s:%s", (archived ? "=>" : " "), bsm_klass->as_C_string(), + bsm_name->as_C_string(), bsm_signature->as_C_string()); } + ArchiveBuilder::alloc_stats()->record_indy_cp_entry(archived, resolved && !archived); } } From 4377e7c9e8399037c66799e99825c56bebbee68e Mon Sep 17 00:00:00 2001 From: Koushik Thirupattur Date: Wed, 22 Oct 2025 21:00:18 +0000 Subject: [PATCH 026/736] 8367008: Algorithm identifiers for HmacSHA* should always have NULL as params Reviewed-by: weijun --- .../sun/security/x509/AlgorithmId.java | 143 ++++++++++-------- .../AlgorithmIdEqualsHashCode.java | 24 ++- .../security/x509/AlgorithmId/NullParams.java | 10 +- 3 files changed, 111 insertions(+), 66 deletions(-) diff --git a/src/java.base/share/classes/sun/security/x509/AlgorithmId.java b/src/java.base/share/classes/sun/security/x509/AlgorithmId.java index 7d525a9add7..8d2c761a011 100644 --- a/src/java.base/share/classes/sun/security/x509/AlgorithmId.java +++ b/src/java.base/share/classes/sun/security/x509/AlgorithmId.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,10 +127,35 @@ public class AlgorithmId implements Serializable, DerEncoder { public AlgorithmId(ObjectIdentifier oid, DerValue params) throws IOException { this.algid = oid; - if (params != null) { - encodedParams = params.toByteArray(); - decodeParams(); + + if (params == null) { + this.encodedParams = null; + this.algParams = null; + return; } + + /* + * If the parameters field explicitly contains an ASN.1 NULL, treat it as + * "no parameters" rather than storing a literal NULL encoding. + * + * This canonicalization ensures consistent encoding/decoding behavior: + * - Algorithms that omit parameters and those that encode explicit NULL + * are treated equivalently (encodedParams == null). + */ + if (params.tag == DerValue.tag_Null) { + if (params.length() != 0) { + throw new IOException("Invalid ASN.1 NULL in AlgorithmId parameters: " + + "non-zero length"); + } + // Canonicalize to "no parameters" representation for consistency + this.encodedParams = null; + this.algParams = null; + return; + } + + // Normal case: non-NULL params -> store and decode + this.encodedParams = params.toByteArray(); + decodeParams(); } protected void decodeParams() throws IOException { @@ -163,38 +188,10 @@ public class AlgorithmId implements Serializable, DerEncoder { bytes.putOID(algid); if (encodedParams == null) { - // MessageDigest algorithms usually have a NULL parameters even - // if most RFCs suggested absent. - // RSA key and signature algorithms requires the NULL parameters - // to be present, see A.1 and A.2.4 of RFC 8017. - if (algid.equals(RSAEncryption_oid) - || algid.equals(MD2_oid) - || algid.equals(MD5_oid) - || algid.equals(SHA_oid) - || algid.equals(SHA224_oid) - || algid.equals(SHA256_oid) - || algid.equals(SHA384_oid) - || algid.equals(SHA512_oid) - || algid.equals(SHA512_224_oid) - || algid.equals(SHA512_256_oid) - || algid.equals(SHA3_224_oid) - || algid.equals(SHA3_256_oid) - || algid.equals(SHA3_384_oid) - || algid.equals(SHA3_512_oid) - || algid.equals(SHA1withRSA_oid) - || algid.equals(SHA224withRSA_oid) - || algid.equals(SHA256withRSA_oid) - || algid.equals(SHA384withRSA_oid) - || algid.equals(SHA512withRSA_oid) - || algid.equals(SHA512$224withRSA_oid) - || algid.equals(SHA512$256withRSA_oid) - || algid.equals(MD2withRSA_oid) - || algid.equals(MD5withRSA_oid) - || algid.equals(SHA3_224withRSA_oid) - || algid.equals(SHA3_256withRSA_oid) - || algid.equals(SHA3_384withRSA_oid) - || algid.equals(SHA3_512withRSA_oid)) { + if (OIDS_REQUIRING_NULL.contains(algid.toString())) { bytes.putNull(); + } else { + // Parameters omitted } } else { bytes.writeBytes(encodedParams); @@ -646,30 +643,54 @@ public class AlgorithmId implements Serializable, DerEncoder { public static final ObjectIdentifier MGF1_oid = ObjectIdentifier.of(KnownOIDs.MGF1); - public static final ObjectIdentifier SHA1withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA1withRSA); - public static final ObjectIdentifier SHA224withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA224withRSA); - public static final ObjectIdentifier SHA256withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA256withRSA); - public static final ObjectIdentifier SHA384withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA384withRSA); - public static final ObjectIdentifier SHA512withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA512withRSA); - public static final ObjectIdentifier SHA512$224withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA512$224withRSA); - public static final ObjectIdentifier SHA512$256withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA512$256withRSA); - public static final ObjectIdentifier MD2withRSA_oid = - ObjectIdentifier.of(KnownOIDs.MD2withRSA); - public static final ObjectIdentifier MD5withRSA_oid = - ObjectIdentifier.of(KnownOIDs.MD5withRSA); - public static final ObjectIdentifier SHA3_224withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA3_224withRSA); - public static final ObjectIdentifier SHA3_256withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA3_256withRSA); - public static final ObjectIdentifier SHA3_384withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA3_384withRSA); - public static final ObjectIdentifier SHA3_512withRSA_oid = - ObjectIdentifier.of(KnownOIDs.SHA3_512withRSA); + /* Set of OIDs that must explicitly encode a NULL parameter in AlgorithmIdentifier. + * References: + - RFC 8017 (PKCS #1) §A.1, §A.2.4: RSA key and signature algorithms + - RFC 9879 (HMAC) §4: HMAC algorithm identifiers + - RFC 9688 (HMAC with SHA-3) §4.3: HMAC-SHA3 algorithms MUST omit parameters + */ + private static final Set OIDS_REQUIRING_NULL = Set.of( + // MessageDigest algorithms usually have a NULL parameters even + // if most RFCs suggested absent. + KnownOIDs.MD2.value(), + KnownOIDs.MD5.value(), + KnownOIDs.SHA_1.value(), + KnownOIDs.SHA_224.value(), + KnownOIDs.SHA_256.value(), + KnownOIDs.SHA_384.value(), + KnownOIDs.SHA_512.value(), + KnownOIDs.SHA_512$224.value(), + KnownOIDs.SHA_512$256.value(), + KnownOIDs.SHA3_224.value(), + KnownOIDs.SHA3_256.value(), + KnownOIDs.SHA3_384.value(), + KnownOIDs.SHA3_512.value(), + + //--- RSA key and signature algorithms (RFC 8017 §A.1, §A.2.4) + KnownOIDs.RSA.value(), + KnownOIDs.SHA1withRSA.value(), + KnownOIDs.SHA224withRSA.value(), + KnownOIDs.SHA256withRSA.value(), + KnownOIDs.SHA384withRSA.value(), + KnownOIDs.SHA512withRSA.value(), + KnownOIDs.SHA512$224withRSA.value(), + KnownOIDs.SHA512$256withRSA.value(), + KnownOIDs.MD2withRSA.value(), + KnownOIDs.MD5withRSA.value(), + KnownOIDs.SHA3_224withRSA.value(), + KnownOIDs.SHA3_256withRSA.value(), + KnownOIDs.SHA3_384withRSA.value(), + KnownOIDs.SHA3_512withRSA.value(), + + // HMACs per RFC 9879 (Section 4): these require explicit NULL parameters + // Note: HMAC-SHA3 algorithms (RFC 9688 §4.3) MUST omit parameters, + // so they are intentionally excluded from this list. + KnownOIDs.HmacSHA1.value(), + KnownOIDs.HmacSHA224.value(), + KnownOIDs.HmacSHA256.value(), + KnownOIDs.HmacSHA384.value(), + KnownOIDs.HmacSHA512.value(), + KnownOIDs.HmacSHA512$224.value(), + KnownOIDs.HmacSHA512$256.value() + ); } diff --git a/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java b/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java index ff91e3dff81..be3da70f851 100644 --- a/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java +++ b/test/jdk/sun/security/x509/AlgorithmId/AlgorithmIdEqualsHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,16 +24,19 @@ /* * @test * @author Gary Ellison - * @bug 4170635 8258247 + * @bug 4170635 8258247 8367008 + * @library /test/lib * @summary Verify equals()/hashCode() contract honored * @modules java.base/sun.security.x509 java.base/sun.security.util */ -import java.io.*; +import java.io.IOException; import java.security.AlgorithmParameters; import java.security.spec.MGF1ParameterSpec; import java.security.spec.PSSParameterSpec; +import jdk.test.lib.Asserts; + import sun.security.util.DerValue; import sun.security.x509.*; @@ -97,5 +100,20 @@ public class AlgorithmIdEqualsHashCode { } else { System.out.println("PASSED equals() test"); } + + // Construct an AlgorithmId with explicit DER NULL parameters + DerValue explicitNullParams = new DerValue(DerValue.tag_Null, new byte[0]); + AlgorithmId aiNullParams = new AlgorithmId(AlgorithmId.SHA256_oid, + explicitNullParams); + // The constructor should canonicalize this to "no parameters" + Asserts.assertTrue(aiNullParams.getEncodedParams() == null); + AlgorithmId aiNormal = AlgorithmId.get("SHA-256"); + Asserts.assertEquals(aiNullParams, aiNormal); + Asserts.assertEquals(aiNullParams.hashCode(), aiNormal.hashCode()); + + // Test invalid ASN.1 NULL (non-zero length) + DerValue invalidNull = new DerValue(DerValue.tag_Null, new byte[]{0x00}); + Asserts.assertThrows(IOException.class, + () -> new AlgorithmId(AlgorithmId.SHA256_oid, invalidNull)); } } diff --git a/test/jdk/sun/security/x509/AlgorithmId/NullParams.java b/test/jdk/sun/security/x509/AlgorithmId/NullParams.java index 733ab9fa522..0b542997a19 100644 --- a/test/jdk/sun/security/x509/AlgorithmId/NullParams.java +++ b/test/jdk/sun/security/x509/AlgorithmId/NullParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,6 +67,13 @@ public class NullParams { test("SHA3-256withRSA", true); test("SHA3-384withRSA", true); test("SHA3-512withRSA", true); + test("HmacSHA1", true); + test("HmacSHA224", true); + test("HmacSHA256", true); + test("HmacSHA384", true); + test("HmacSHA512", true); + test("HmacSHA512/224", true); + test("HmacSHA512/256", true); // Full old list: must be absent test("SHA1withECDSA", false); @@ -83,7 +90,6 @@ public class NullParams { // Others test("DSA", false); test("SHA1withDSA", false); - test("HmacSHA1", false); if (failed) { throw new RuntimeException("At least one failed"); From 45e145fac2abc90faa56679336ddea4a8cd05446 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Wed, 22 Oct 2025 21:06:25 +0000 Subject: [PATCH 027/736] 8359057: AbstractInterpreter::is_not_reached returns incorrectly with invokedynamic Reviewed-by: vlivanov --- src/hotspot/share/interpreter/abstractInterpreter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/interpreter/abstractInterpreter.cpp b/src/hotspot/share/interpreter/abstractInterpreter.cpp index 640e3ab3fff..b6a2255b468 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.cpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.cpp @@ -258,7 +258,8 @@ bool AbstractInterpreter::is_not_reached(const methodHandle& method, int bci) { case Bytecodes::_invokedynamic: { assert(invoke_bc.has_index_u4(code), "sanity"); int method_index = invoke_bc.get_index_u4(code); - return cpool->resolved_indy_entry_at(method_index)->is_resolved(); + bool is_resolved = cpool->resolved_indy_entry_at(method_index)->is_resolved(); + return !is_resolved; } case Bytecodes::_invokevirtual: // fall-through case Bytecodes::_invokeinterface: // fall-through From 2a8cbd944ba4d8896e48181e396c65f70e5aa215 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 22 Oct 2025 21:47:06 +0000 Subject: [PATCH 028/736] 8359472: JVM crashes when attaching a dynamic agent before JVMTI_PHASE_LIVE Reviewed-by: lmesnik, sspitsyn, amenkov --- src/hotspot/share/prims/jvmtiAgentList.cpp | 5 + .../EarlyDynamicLoad/EarlyDynamicLoad.java | 103 ++++++++++++++++++ .../EarlyDynamicLoad/libEarlyDynamicLoad.cpp | 59 ++++++++++ 3 files changed, 167 insertions(+) create mode 100644 test/hotspot/jtreg/serviceability/attach/EarlyDynamicLoad/EarlyDynamicLoad.java create mode 100644 test/hotspot/jtreg/serviceability/attach/EarlyDynamicLoad/libEarlyDynamicLoad.cpp diff --git a/src/hotspot/share/prims/jvmtiAgentList.cpp b/src/hotspot/share/prims/jvmtiAgentList.cpp index 8da5b75be46..41fc9c0f359 100644 --- a/src/hotspot/share/prims/jvmtiAgentList.cpp +++ b/src/hotspot/share/prims/jvmtiAgentList.cpp @@ -196,6 +196,11 @@ void JvmtiAgentList::load_xrun_agents() { // Invokes Agent_OnAttach for agents loaded dynamically during runtime. void JvmtiAgentList::load_agent(const char* agent_name, bool is_absolute_path, const char* options, outputStream* st) { + if (JvmtiEnvBase::get_phase() != JVMTI_PHASE_LIVE) { + st->print_cr("Dynamic agent loading is only permitted in the live phase"); + return; + } + JvmtiAgent* const agent = new JvmtiAgent(agent_name, options, is_absolute_path, /* dynamic agent */ true); if (agent->load(st)) { add(agent); diff --git a/test/hotspot/jtreg/serviceability/attach/EarlyDynamicLoad/EarlyDynamicLoad.java b/test/hotspot/jtreg/serviceability/attach/EarlyDynamicLoad/EarlyDynamicLoad.java new file mode 100644 index 00000000000..cb1596da08c --- /dev/null +++ b/test/hotspot/jtreg/serviceability/attach/EarlyDynamicLoad/EarlyDynamicLoad.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.AgentLoadException; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.TimeUnit; +import jdk.test.lib.dcmd.PidJcmdExecutor; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Utils; + +/* + * @test EarlyDynamicLoad + * @summary Test that dynamic attach fails gracefully when the JVM is not in live phase. + * @requires vm.jvmti + * @library /test/lib + * @run junit EarlyDynamicLoad + */ +public class EarlyDynamicLoad { + private static final String EXPECTED_MESSAGE = "Dynamic agent loading is only permitted in the live phase"; + + private static Process child; + + @BeforeAll + static void startAndWaitChild() throws Exception { + child = ProcessTools.createTestJavaProcessBuilder( + "-XX:+StartAttachListener", + "-agentpath:" + Utils.TEST_NATIVE_PATH + File.separator + System.mapLibraryName("EarlyDynamicLoad"), + "--version").start(); + + // Wait until the process enters VMStartCallback + try (InputStream is = child.getInputStream()) { + is.read(); + } + } + + @AfterAll + static void stopChild() throws Exception { + try (OutputStream os = child.getOutputStream()) { + os.write(0); + } + + if (!child.waitFor(5, TimeUnit.SECONDS)) { + child.destroyForcibly(); + throw new AssertionError("Timed out while waiting child process to complete"); + } + + OutputAnalyzer analyzer = new OutputAnalyzer(child); + analyzer.shouldHaveExitValue(0); + analyzer.stderrShouldBeEmpty(); + } + + @Test + public void virtualMachine() throws Exception { + try { + VirtualMachine vm = VirtualMachine.attach(String.valueOf(child.pid())); + vm.loadAgent("some.jar"); + vm.detach(); + throw new AssertionError("Should have failed with AgentLoadException"); + } catch(AgentLoadException exception) { + if (!exception.getMessage().contains(EXPECTED_MESSAGE)) { + throw new AssertionError("Unexpected error message", exception); + } + } + } + + @Test + public void jcmd() throws Exception { + PidJcmdExecutor executor = new PidJcmdExecutor(String.valueOf(child.pid())); + OutputAnalyzer out = executor.execute("JVMTI.agent_load some.jar"); + + out.shouldHaveExitValue(0); + out.stdoutShouldContain(EXPECTED_MESSAGE); + } +} diff --git a/test/hotspot/jtreg/serviceability/attach/EarlyDynamicLoad/libEarlyDynamicLoad.cpp b/test/hotspot/jtreg/serviceability/attach/EarlyDynamicLoad/libEarlyDynamicLoad.cpp new file mode 100644 index 00000000000..3991926306e --- /dev/null +++ b/test/hotspot/jtreg/serviceability/attach/EarlyDynamicLoad/libEarlyDynamicLoad.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include + +extern "C" { + +static void JNICALL VMStartCallback(jvmtiEnv* jvmti, JNIEnv* env) { + putchar('1'); + fflush(stdout); + getchar(); +} + +JNIEXPORT int Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { + jvmtiEnv* jvmti; + if (vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0) != JVMTI_ERROR_NONE) { + fprintf(stderr, "JVMTI error occurred during GetEnv\n"); + return JNI_ERR; + } + + jvmtiEventCallbacks callbacks; + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.VMStart = VMStartCallback; + + if (jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)) != JVMTI_ERROR_NONE) { + fprintf(stderr, "JVMTI error occurred during SetEventCallbacks\n"); + return JNI_ERR; + } + if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_START, nullptr) != JVMTI_ERROR_NONE) { + fprintf(stderr, "JVMTI error occurred during SetEventNotificationMode\n"); + return JNI_ERR; + } + + return JNI_OK; +} + +} From 0744db8366183a0fd07f42ee1ce6ef677bf4136e Mon Sep 17 00:00:00 2001 From: Dean Long Date: Wed, 22 Oct 2025 22:01:31 +0000 Subject: [PATCH 029/736] 8367002: Missing compiled exception handler for "recursive" exception Reviewed-by: thartmann, kvn --- src/hotspot/share/runtime/deoptimization.cpp | 21 ++++-- src/hotspot/share/runtime/deoptimization.hpp | 6 +- src/hotspot/share/runtime/sharedRuntime.cpp | 12 +++- src/hotspot/share/runtime/vmStructs.cpp | 2 +- .../exceptions/IllegalAccessInCatch.jasm | 62 +++++++++++++++++ .../exceptions/TestAccessErrorInCatch.java | 67 +++++++++++++++++++ 6 files changed, 159 insertions(+), 11 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm create mode 100644 test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 853c6554022..daafcaea61b 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1804,10 +1804,11 @@ void Deoptimization::deoptimize(JavaThread* thread, frame fr, DeoptReason reason deoptimize_single_frame(thread, fr, reason); } -#if INCLUDE_JVMCI -address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm) { +address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm, bool make_not_entrant) { // there is no exception handler for this pc => deoptimize - nm->make_not_entrant(nmethod::InvalidationReason::MISSING_EXCEPTION_HANDLER); + if (make_not_entrant) { + nm->make_not_entrant(nmethod::InvalidationReason::MISSING_EXCEPTION_HANDLER); + } // Use Deoptimization::deoptimize for all of its side-effects: // gathering traps statistics, logging... @@ -1821,6 +1822,15 @@ address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm) { frame runtime_frame = thread->last_frame(); frame caller_frame = runtime_frame.sender(®_map); assert(caller_frame.cb()->as_nmethod_or_null() == nm, "expect top frame compiled method"); + + Deoptimization::deoptimize(thread, caller_frame, Deoptimization::Reason_not_compiled_exception_handler); + + if (!nm->is_compiled_by_jvmci()) { + return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + +#if INCLUDE_JVMCI + // JVMCI support vframe* vf = vframe::new_vframe(&caller_frame, ®_map, thread); compiledVFrame* cvf = compiledVFrame::cast(vf); ScopeDesc* imm_scope = cvf->scope(); @@ -1836,16 +1846,15 @@ address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm) { } } - Deoptimization::deoptimize(thread, caller_frame, Deoptimization::Reason_not_compiled_exception_handler); MethodData* trap_mdo = get_method_data(thread, methodHandle(thread, nm->method()), true); if (trap_mdo != nullptr) { trap_mdo->inc_trap_count(Deoptimization::Reason_not_compiled_exception_handler); } +#endif return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); } -#endif void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason) { assert(thread == Thread::current() || @@ -2748,10 +2757,10 @@ const char* Deoptimization::_trap_reason_name[] = { "unstable_if", "unstable_fused_if", "receiver_constraint", + "not_compiled_exception_handler", "short_running_loop" JVMCI_ONLY("_or_aliasing"), #if INCLUDE_JVMCI "transfer_to_interpreter", - "not_compiled_exception_handler", "unresolved", "jsr_mismatch", #endif diff --git a/src/hotspot/share/runtime/deoptimization.hpp b/src/hotspot/share/runtime/deoptimization.hpp index 5d97e2056ad..d168d9c8af6 100644 --- a/src/hotspot/share/runtime/deoptimization.hpp +++ b/src/hotspot/share/runtime/deoptimization.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,11 +117,11 @@ class Deoptimization : AllStatic { Reason_unstable_if, // a branch predicted always false was taken Reason_unstable_fused_if, // fused two ifs that had each one untaken branch. One is now taken. Reason_receiver_constraint, // receiver subtype check failed + Reason_not_compiled_exception_handler, // missing compiled exception handler Reason_short_running_long_loop, // profile reports loop runs for small number of iterations #if INCLUDE_JVMCI Reason_aliasing = Reason_short_running_long_loop, // optimistic assumption about aliasing failed Reason_transfer_to_interpreter, // explicit transferToInterpreter() - Reason_not_compiled_exception_handler, Reason_unresolved, Reason_jsr_mismatch, #endif @@ -184,8 +184,8 @@ class Deoptimization : AllStatic { // Deoptimizes a frame lazily. Deopt happens on return to the frame. static void deoptimize(JavaThread* thread, frame fr, DeoptReason reason = Reason_constraint); + static address deoptimize_for_missing_exception_handler(nmethod* nm, bool make_not_entrant); #if INCLUDE_JVMCI - static address deoptimize_for_missing_exception_handler(nmethod* nm); static oop get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, bool& cache_init_error, TRAPS); #endif diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index efc47dd11c6..35bc3f5f1be 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -791,7 +791,8 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, if (t != nullptr) { return nm->code_begin() + t->pco(); } else { - return Deoptimization::deoptimize_for_missing_exception_handler(nm); + bool make_not_entrant = true; + return Deoptimization::deoptimize_for_missing_exception_handler(nm, make_not_entrant); } } #endif // INCLUDE_JVMCI @@ -847,6 +848,15 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, ExceptionHandlerTable table(nm); HandlerTableEntry *t = table.entry_for(catch_pco, handler_bci, scope_depth); + + // If the compiler did not anticipate a recursive exception, resulting in an exception + // thrown from the catch bci, then the compiled exception handler might be missing. + // This is rare. Just deoptimize and let the interpreter handle it. + if (t == nullptr && recursive_exception_occurred) { + bool make_not_entrant = false; + return Deoptimization::deoptimize_for_missing_exception_handler(nm, make_not_entrant); + } + if (t == nullptr && (nm->is_compiled_by_c1() || handler_bci != -1)) { // Allow abbreviated catch tables. The idea is to allow a method // to materialize its exceptions without committing to the exact diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 8dc4b660f91..85f921ef3e3 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1581,8 +1581,8 @@ declare_constant(Deoptimization::Reason_unstable_if) \ declare_constant(Deoptimization::Reason_unstable_fused_if) \ declare_constant(Deoptimization::Reason_receiver_constraint) \ + declare_constant(Deoptimization::Reason_not_compiled_exception_handler) \ NOT_ZERO(JVMCI_ONLY(declare_constant(Deoptimization::Reason_transfer_to_interpreter))) \ - NOT_ZERO(JVMCI_ONLY(declare_constant(Deoptimization::Reason_not_compiled_exception_handler))) \ NOT_ZERO(JVMCI_ONLY(declare_constant(Deoptimization::Reason_unresolved))) \ NOT_ZERO(JVMCI_ONLY(declare_constant(Deoptimization::Reason_jsr_mismatch))) \ declare_constant(Deoptimization::Reason_tenured) \ diff --git a/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm b/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm new file mode 100644 index 00000000000..beeffa69a97 --- /dev/null +++ b/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +super class IllegalAccessInCatch + version 52:0 +{ + /* + static int test() { + try { + return 1 / 0; + } catch (jdk.internal.agent.AgentConfigurationError e1) { + try { + return 0; + } catch (IllegalAccessError e2) { + return 1; + } + } + } + */ + static Method test:"()I" + stack 2 locals 1 + { + iconst_1; + iconst_0; + try t0; + idiv; + endtry t0; + ireturn; + catch t0 jdk/internal/agent/AgentConfigurationError; // loadable but not accessible from unnamed module + stack_frame_type full; + stack_map class java/lang/Throwable; + try t1; + iconst_0; + ireturn; + endtry t1; + catch t1 java/lang/IllegalAccessError; + stack_frame_type full; + stack_map class java/lang/Throwable; + iconst_1; + ireturn; + } +} diff --git a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java new file mode 100644 index 00000000000..46541d76016 --- /dev/null +++ b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8367002 + * @summary Compilers might not generate handlers for recursive exceptions + * + * @compile IllegalAccessInCatch.jasm + * @run main/othervm -Xbatch + * -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test + * -XX:-TieredCompilation + * TestAccessErrorInCatch + * @run main/othervm -Xbatch + * -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test + * -XX:TieredStopAtLevel=3 + * TestAccessErrorInCatch + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import java.nio.file.Files; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class TestAccessErrorInCatch { + + public static void main(String[] args) throws Throwable { + Path TEST_CLASSES_DIR = FileSystems.getDefault().getPath(System.getProperty("test.classes")); + byte[] bytes = Files.readAllBytes(TEST_CLASSES_DIR.resolve("IllegalAccessInCatch.class")); + + var l = MethodHandles.lookup().defineHiddenClass(bytes, true); + Class anonClass = l.lookupClass(); + MethodHandle mh = l.findStatic(anonClass, "test", MethodType.methodType(int.class)); + for (int i = 0; i < 16_000; i++) { + invoke(mh); + } + System.out.println(invoke(mh)); + } + + private static int invoke(MethodHandle mh) throws Throwable { + return (int) mh.invokeExact(); + } +} From be18e7ecfd2e89a0abb168e0d9a5b69598e2199f Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Wed, 22 Oct 2025 22:42:46 +0000 Subject: [PATCH 030/736] 8064922: [macos] Test javax/swing/JTabbedPane/4624207/bug4624207.java fails Reviewed-by: tr, honkar, psadhukhan --- test/jdk/ProblemList.txt | 1 - .../swing/JTabbedPane/4624207/bug4624207.java | 67 ++++++++----------- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 0e69446ae35..1f6bea97407 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -676,7 +676,6 @@ javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-al javax/swing/JFileChooser/6396844/TwentyThousandTest.java 8198003 generic-all javax/swing/JFileChooser/8194044/FileSystemRootTest.java 8327236 windows-all javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all -javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all javax/swing/JFileChooser/bug6798062.java 8146446 windows-all javax/swing/JPopupMenu/4870644/bug4870644.java 8194130 macosx-all,linux-all diff --git a/test/jdk/javax/swing/JTabbedPane/4624207/bug4624207.java b/test/jdk/javax/swing/JTabbedPane/4624207/bug4624207.java index 10de2ab221a..4d2fdcf030c 100644 --- a/test/jdk/javax/swing/JTabbedPane/4624207/bug4624207.java +++ b/test/jdk/javax/swing/JTabbedPane/4624207/bug4624207.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,25 +25,26 @@ * @test * @key headful * @bug 4624207 + * @requires (os.family != "mac") * @summary JTabbedPane mnemonics don't work from outside the tabbed pane - * @author Oleg Mokhovikov - * @library /test/lib - * @library ../../regtesthelpers - * @build Util jdk.test.lib.Platform * @run main bug4624207 */ -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; + +import java.awt.BorderLayout; +import java.awt.Robot; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; -import jdk.test.lib.Platform; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; public class bug4624207 implements ChangeListener, FocusListener { - private static volatile boolean stateChanged = false; private static volatile boolean focusGained = false; private static JTextField txtField; @@ -71,51 +72,39 @@ public class bug4624207 implements ChangeListener, FocusListener { Robot robot = new Robot(); robot.setAutoDelay(50); - SwingUtilities.invokeAndWait(new Runnable() { - - public void run() { - createAndShowGUI(); - } - }); - + SwingUtilities.invokeAndWait(() -> createAndShowGUI()); robot.waitForIdle(); - - SwingUtilities.invokeAndWait(new Runnable() { - - public void run() { - txtField.requestFocus(); - } - }); - + SwingUtilities.invokeAndWait(() -> txtField.requestFocus()); robot.waitForIdle(); if (!focusGained) { throw new RuntimeException("Couldn't gain focus for text field"); } - SwingUtilities.invokeAndWait(new Runnable() { - - public void run() { - tab.addChangeListener((ChangeListener) listener); - txtField.removeFocusListener((FocusListener) listener); - } + SwingUtilities.invokeAndWait(() -> { + tab.addChangeListener((ChangeListener) listener); + txtField.removeFocusListener((FocusListener) listener); }); robot.waitForIdle(); - if (Platform.isOSX()) { - Util.hitKeys(robot, KeyEvent.VK_CONTROL, KeyEvent.VK_ALT, KeyEvent.VK_B); - } else { - Util.hitKeys(robot, KeyEvent.VK_ALT, KeyEvent.VK_B); - } + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_B); + robot.keyRelease(KeyEvent.VK_B); + robot.keyRelease(KeyEvent.VK_ALT); robot.waitForIdle(); if (!stateChanged || tab.getSelectedIndex() != 1) { - throw new RuntimeException("JTabbedPane mnemonics don't work from outside the tabbed pane"); + throw new RuntimeException("JTabbedPane mnemonics don't " + + "work from outside the tabbed pane"); } } finally { - if (frame != null) SwingUtilities.invokeAndWait(() -> frame.dispose()); + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } } From 3e20a9392fecef796098507acef429ef2d45a3d2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Oct 2025 23:50:39 +0000 Subject: [PATCH 031/736] 8370156: Fix jpackage IconTest Reviewed-by: almatvee --- test/jdk/tools/jpackage/share/IconTest.java | 320 +++++++++++--------- 1 file changed, 174 insertions(+), 146 deletions(-) diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index 051cad84a13..03726e524dc 100644 --- a/test/jdk/tools/jpackage/share/IconTest.java +++ b/test/jdk/tools/jpackage/share/IconTest.java @@ -21,7 +21,10 @@ * questions. */ +import static jdk.jpackage.test.AdditionalLauncher.getAdditionalLauncherProperties; + import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -29,10 +32,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TreeMap; -import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.util.function.ThrowingBiConsumer; @@ -40,8 +43,11 @@ import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.AdditionalLauncher; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.CannedFormattedString; +import jdk.jpackage.test.ConfigurationTarget; import jdk.jpackage.test.Executor; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.LauncherIconVerifier; import jdk.jpackage.test.LinuxHelper; import jdk.jpackage.test.PackageTest; @@ -159,27 +165,37 @@ public class IconTest { @Test public void test() throws IOException { - if (appImage) { - JPackageCommand cmd = initAppImageTest(); - var result = cmd.executeAndAssertImageCreated(); - ThrowingConsumer.toConsumer(createInstallVerifier()).accept(cmd); - ThrowingBiConsumer.toBiConsumer(createBundleVerifier()).accept(cmd, result); - } else { - PackageTest test = initPackageTest(); - test.addInstallVerifier(createInstallVerifier()); - test.addBundleVerifier(createBundleVerifier()); + final ConfigurationTarget target; + if (appImage) { + target = new ConfigurationTarget(JPackageCommand.helloAppImage()); + } else { + target = new ConfigurationTarget(new PackageTest().configureHelloApp()); + } + + initTest(target); + + var installVerifier = createInstallVerifier(); + var bundleVerifier = createBundleVerifier(); + + var cmdResult = target.cmd().map(JPackageCommand::executeAndAssertImageCreated); + + target.apply(ThrowingConsumer.toConsumer(installVerifier), test -> { + test.addInstallVerifier(installVerifier); + }).apply(cmd -> { + ThrowingBiConsumer.toBiConsumer(bundleVerifier).accept(cmd, cmdResult.orElseThrow()); + }, test -> { + test.addBundleVerifier(bundleVerifier); test.addBundleDesktopIntegrationVerifier(config.values().stream() .anyMatch(this::isWithDesktopIntegration)); + }); - test.run(PackageTest.Action.CREATE_AND_UNPACK); - } + target.test().ifPresent(v -> { + v.run(PackageTest.Action.CREATE_AND_UNPACK); + }); } boolean isWithDesktopIntegration(IconType iconType) { - if (appImage) { - return false; - } boolean withDesktopFile = !Set.of( IconType.NoIcon, IconType.DefaultIcon).contains(iconType); @@ -189,89 +205,110 @@ public class IconTest { private ThrowingBiConsumer createBundleVerifier() { return (cmd, result) -> { - var verifier = createConsoleOutputVerifier(cmd.name(), config.get( - Launcher.Main), null); - if (verifier != null) { - verifier.apply(result.getOutput()); - } - - if (config.containsKey(Launcher.Additional)) { - verifier = createConsoleOutputVerifier( - Launcher.Additional.launcherName, config.get( - Launcher.Additional), config.get(Launcher.Main)); - if (verifier != null) { + Stream.of(Launcher.Main, Launcher.Additional).filter(config::containsKey).forEach(launcher -> { + createConsoleOutputVerifier(cmd, launcher).ifPresent(verifier -> { verifier.apply(result.getOutput()); - } - } + }); + }); }; } - private TKit.TextStreamVerifier createConsoleOutputVerifier( - String launcherName, IconType iconType, IconType mainIconType) { - if (iconType == IconType.DefaultIcon && mainIconType != null) { - iconType = mainIconType; + private Optional createConsoleOutputVerifier( + JPackageCommand cmd, Launcher launcher) { + + var launcherName = Optional.ofNullable(launcher.launcherName).orElseGet(cmd::name); + var resourceName = launcherName; + Optional customIcon; + + if (launcherName.equals(cmd.name())) { + customIcon = Optional.ofNullable(cmd.getArgumentValue("--icon")).map(Path::of); + } else if (config.get(launcher) == IconType.DefaultIcon) { + resourceName = cmd.name(); + customIcon = Optional.ofNullable(cmd.getArgumentValue("--icon")).map(Path::of); + } else { + customIcon = getAdditionalLauncherProperties(cmd, launcherName).findProperty("icon").map(Path::of); } - return createConsoleOutputVerifier(launcherName, iconType); + + return createConsoleOutputVerifier( + getBundleIconType(cmd, launcher), + launcherName, + resourceName, + customIcon); } - private static TKit.TextStreamVerifier createConsoleOutputVerifier( - String launcherName, IconType iconType) { - String lookupString = null; + private static Optional createConsoleOutputVerifier( + IconType iconType, String launcherName, String resourceName, Optional customIcon) { + + Objects.requireNonNull(launcherName); + Objects.requireNonNull(resourceName); + Objects.requireNonNull(customIcon); + + CannedFormattedString lookupString; + switch (iconType) { case DefaultIcon: - lookupString = String.format( - "Using default package resource %s [icon] (add %s%s to the resource-dir to customize)", + lookupString = JPackageStringBundle.MAIN.cannedFormattedString( + "message.using-default-resource", "JavaApp" + TKit.ICON_SUFFIX, - launcherName, TKit.ICON_SUFFIX); + "[icon]", + launcherName + TKit.ICON_SUFFIX); break; case ResourceDirIcon: - lookupString = String.format( - "Using custom package resource [icon] (loaded from %s%s)", - launcherName, TKit.ICON_SUFFIX); + lookupString = JPackageStringBundle.MAIN.cannedFormattedString( + "message.using-custom-resource", + "[icon]", + resourceName + TKit.ICON_SUFFIX); break; case CustomIcon: case CustomWithResourceDirIcon: - lookupString = "Using custom package resource [icon] (loaded from file"; + lookupString = JPackageStringBundle.MAIN.cannedFormattedString( + "message.using-custom-resource-from-file", + "[icon]", + customIcon.orElseThrow()); break; default: - return null; + return Optional.empty(); } - return TKit.assertTextStream(lookupString); + return Optional.of(TKit.assertTextStream(lookupString.getValue())); } private ThrowingConsumer createInstallVerifier() { - LauncherIconVerifier verifier = new LauncherIconVerifier(); - switch (config.get(Launcher.Main)) { - case NoIcon: - verifier.setExpectedIcon(null); - break; - - case DefaultIcon: - verifier.setExpectedDefaultIcon(); - break; - - case CustomIcon: - verifier.setExpectedIcon(Launcher.Main.cmdlineIcon); - break; - - case ResourceDirIcon: - verifier.setExpectedIcon(Launcher.Main.resourceDirIcon); - break; - - case CustomWithResourceDirIcon: - verifier.setExpectedIcon(Launcher.Main2.cmdlineIcon); - break; - } - return cmd -> { + var verifier = new LauncherIconVerifier(); + + var bundleIconType = getBundleIconType(cmd, Launcher.Main); + + switch (bundleIconType) { + case NoIcon: + verifier.setExpectedNoIcon(); + break; + + case DefaultIcon: + verifier.setExpectedDefaultIcon(); + break; + + case CustomIcon: + verifier.setExpectedIcon(Launcher.Main.cmdlineIcon); + break; + + case ResourceDirIcon: + verifier.setExpectedIcon(Launcher.Main.resourceDirIcon); + break; + + case CustomWithResourceDirIcon: + verifier.setExpectedIcon(Launcher.Main2.cmdlineIcon); + break; + } + verifier.applyTo(cmd); + if (TKit.isLinux() && !cmd.isImagePackageType()) { Path desktopFile = LinuxHelper.getDesktopFile(cmd); - if (isWithDesktopIntegration(config.get(Launcher.Main))) { + if (isWithDesktopIntegration(bundleIconType)) { TKit.assertFileExists(desktopFile); } else { TKit.assertPathExists(desktopFile, false); @@ -280,80 +317,61 @@ public class IconTest { }; } - private void initTest(JPackageCommand cmd, PackageTest test) { + private void initTest(ConfigurationTarget target) { config.entrySet().forEach(ThrowingConsumer.toConsumer(entry -> { - initTest(entry.getKey(), entry.getValue(), cmd, test); + initTest(entry.getKey(), entry.getValue(), target); })); - ThrowingConsumer initializer = testCmd -> { - testCmd.saveConsoleOutput(true); - testCmd.setFakeRuntime(); - testCmd.addArguments(extraJPackageArgs); - }; - - if (test != null) { - test.addInitializer(initializer); - } else { - ThrowingConsumer.toConsumer(initializer).accept(cmd); - } + target.addInitializer(cmd -> { + cmd.saveConsoleOutput(true); + cmd.setFakeRuntime(); + cmd.addArguments(extraJPackageArgs); + }); } private static void initTest(Launcher cfg, IconType iconType, - JPackageCommand cmd, PackageTest test) throws IOException { - Consumer addLauncher = v -> { - if (test != null) { - v.applyTo(test); - } else { - v.applyTo(cmd); - } - }; + ConfigurationTarget target) throws IOException { switch (iconType) { case DefaultIcon: - if (cfg.launcherName != null) { - addLauncher.accept(new AdditionalLauncher(cfg.launcherName)); - } + Optional.ofNullable(cfg.launcherName).map(AdditionalLauncher::new) + .ifPresent(target::add); break; case NoIcon: - if (cfg.launcherName != null) { - addLauncher.accept( - new AdditionalLauncher(cfg.launcherName).setNoIcon()); - } + Optional.ofNullable(cfg.launcherName).map(AdditionalLauncher::new) + .map(AdditionalLauncher::setNoIcon) + .ifPresent(target::add); break; case CustomIcon: - if (test != null) { - addCustomIcon(null, test, cfg.launcherName, cfg.cmdlineIcon); - } else { - addCustomIcon(cmd, null, cfg.launcherName, cfg.cmdlineIcon); - } + addCustomIcon(target, cfg.launcherName, cfg.cmdlineIcon); break; case ResourceDirIcon: - if (Launcher.PRIMARY.contains(cfg) && cfg.launcherName != null) { - addLauncher.accept(new AdditionalLauncher(cfg.launcherName)); - } - if (test != null) { - test.addInitializer(testCmd -> { - addResourceDirIcon(testCmd, cfg.launcherName, - cfg.resourceDirIcon); - }); - } else { - addResourceDirIcon(cmd, cfg.launcherName, cfg.resourceDirIcon); + if (Launcher.PRIMARY.contains(cfg)) { + Optional.ofNullable(cfg.launcherName).map(AdditionalLauncher::new) + .ifPresent(target::add); } + target.addInitializer(cmd -> { + try { + addResourceDirIcon(cmd, cfg.launcherName, cfg.resourceDirIcon); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); break; case CustomWithResourceDirIcon: switch (cfg) { case Main: - initTest(Launcher.Main2, IconType.CustomIcon, cmd, test); - initTest(Launcher.Main2, IconType.ResourceDirIcon, cmd, test); + initTest(Launcher.Main2, IconType.CustomIcon, target); + initTest(Launcher.Main2, IconType.ResourceDirIcon, target); break; case Additional: - initTest(Launcher.Additional2, IconType.CustomIcon, cmd, test); - initTest(Launcher.Additional2, IconType.ResourceDirIcon, cmd, test); + initTest(Launcher.Additional2, IconType.CustomIcon, target); + initTest(Launcher.Additional2, IconType.ResourceDirIcon, target); break; default: @@ -363,29 +381,46 @@ public class IconTest { } } - private JPackageCommand initAppImageTest() { - JPackageCommand cmd = JPackageCommand.helloAppImage(); - initTest(cmd, null); - return cmd; + private IconType getBundleIconType(JPackageCommand cmd, Launcher launcher) { + return getBundleIconType(cmd, config.get(Launcher.Main), launcher, config.get(launcher)); } - private PackageTest initPackageTest() { - PackageTest test = new PackageTest().configureHelloApp(); - initTest(null, test); - return test; + /** + * Returns the expected icon type of the given launcher in the output bundle + * that the given jpackage command line will output based on the icon type + * configured for the launcher. + * + * @param cmd jpackage command line + * @param mainLauncherIconType the icon type configured for the main launcher + * @param launcher the launcher + * @param iconType the icon type configured for the specified + * launcher + * @return the type of of an icon of the given launcher in the output bundle + */ + private static IconType getBundleIconType(JPackageCommand cmd, + IconType mainLauncherIconType, Launcher launcher, IconType iconType) { + + Objects.requireNonNull(cmd); + Objects.requireNonNull(mainLauncherIconType); + Objects.requireNonNull(launcher); + Objects.requireNonNull(iconType); + + if (iconType == IconType.DefaultIcon) { + iconType = mainLauncherIconType; + } + + return iconType; } private static void addResourceDirIcon(JPackageCommand cmd, String launcherName, Path iconPath) throws IOException { - Path resourceDir = cmd.getArgumentValue("--resource-dir", () -> null, - Path::of); - if (resourceDir == null) { - resourceDir = TKit.createTempDirectory("resources"); - cmd.addArguments("--resource-dir", resourceDir); - } + var resourceDir = Optional.ofNullable(cmd.getArgumentValue("--resource-dir")).map(Path::of).orElseGet(() -> { + return TKit.createTempDirectory("resources"); + }); - String dstIconFileName = Optional.ofNullable(launcherName).orElseGet( - () -> cmd.name()) + TKit.ICON_SUFFIX; + cmd.addArguments("--resource-dir", resourceDir); + + String dstIconFileName = Optional.ofNullable(launcherName).orElseGet(cmd::name) + TKit.ICON_SUFFIX; TKit.trace(String.format("Resource file: [%s] <- [%s]", resourceDir.resolve(dstIconFileName), iconPath)); @@ -393,23 +428,16 @@ public class IconTest { StandardCopyOption.REPLACE_EXISTING); } - private static void addCustomIcon(JPackageCommand cmd, PackageTest test, - String launcherName, Path iconPath) throws IOException { + private static void addCustomIcon(ConfigurationTarget target, + String launcherName, Path iconPath) { if (launcherName != null) { - AdditionalLauncher al = new AdditionalLauncher(launcherName).setIcon( - iconPath); - if (test != null) { - al.applyTo(test); - } else { - al.applyTo(cmd); - } - } else if (test != null) { - test.addInitializer(testCmd -> { - testCmd.addArguments("--icon", iconPath); - }); + var al = new AdditionalLauncher(launcherName).setIcon(iconPath); + target.apply(al::applyTo, al::applyTo); } else { - cmd.addArguments("--icon", iconPath); + target.addInitializer(cmd -> { + cmd.addArguments("--icon", iconPath); + }); } } From ffcb1585ed6c2a2bff28be6854d44a672aa31a0b Mon Sep 17 00:00:00 2001 From: Anass Baya Date: Thu, 23 Oct 2025 06:28:50 +0000 Subject: [PATCH 032/736] 8320677: Printer tests use invalid '@run main/manual=yesno Reviewed-by: aivanov, dnguyen --- .../java/awt/print/PrinterJob/PageRanges.java | 67 ++++--- .../PrinterJob/PolylinePrintingTest.java | 179 ++++-------------- 2 files changed, 69 insertions(+), 177 deletions(-) diff --git a/test/jdk/java/awt/print/PrinterJob/PageRanges.java b/test/jdk/java/awt/print/PrinterJob/PageRanges.java index accde99ae95..e80330bae6c 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageRanges.java +++ b/test/jdk/java/awt/print/PrinterJob/PageRanges.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,58 +21,63 @@ * questions. */ -/** +/* * @test * @bug 6575331 * @key printer * @summary The specified pages should be printed. - * @run main/manual=yesno PageRanges + * @library /java/awt/regtesthelpers + * @library /test/lib + * @build PassFailJFrame + * @build jtreg.SkippedException + * @run main/manual PageRanges */ -import java.awt.*; -import java.awt.print.*; +import java.awt.Graphics; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import jtreg.SkippedException; public class PageRanges implements Printable { - - static String[] instr = { - "This test prints two jobs, and tests that the specified range", - "of pages is printed. You must have a printer installed for this test.", - "In the first dialog, select a page range of 2 to 3, and press OK", - "In the second dialog, select ALL, to print all pages (in total 5 pages).", - "Collect the two print outs and confirm the jobs printed correctly", - }; + private static final String INSTRUCTIONS = """ + This test prints two jobs and tests that the specified range + of pages is printed. + In the first dialog, select a page range of 2 to 3, and press OK. + In the second dialog, select ALL, to print all pages (in total 5 pages). + Collect the two print outs and confirm the jobs are printed correctly. + """; public static void main(String args[]) throws Exception { - for (int i=0;i= 5) { return NO_SUCH_PAGE; } g.drawString("Page : " + (pi+1), 200, 200); - return PAGE_EXISTS; } } diff --git a/test/jdk/java/awt/print/PrinterJob/PolylinePrintingTest.java b/test/jdk/java/awt/print/PrinterJob/PolylinePrintingTest.java index 7d8568c01f9..c9dcdfdd450 100644 --- a/test/jdk/java/awt/print/PrinterJob/PolylinePrintingTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PolylinePrintingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,31 +21,56 @@ * questions. */ -/** +/* + * @test * @bug 8041902 * @key printer * @summary Test printing of wide poly lines. - * @run main/manual=yesno PolylinePrintingTest + * @library /java/awt/regtesthelpers + * @library /test/lib + * @build PassFailJFrame + * @build jtreg.SkippedException + * @run main/manual PolylinePrintingTest */ -import java.awt.Dialog; -import java.awt.Frame; -import java.awt.TextArea; import java.awt.BasicStroke; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.Path2D; import java.awt.print.PageFormat; -import java.awt.print.Paper; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; +import jtreg.SkippedException; public class PolylinePrintingTest implements Printable { + private static final String INSTRUCTIONS = """ + Press OK in the print dialog and collect the printed page. + Passing test : Output should show two identical chevrons. + Failing test : The line joins will appear different. + """; + + public static void main(String[] args) throws Exception { + PrinterJob job = PrinterJob.getPrinterJob(); + if (job.getPrintService() == null) { + throw new SkippedException("Printer not configured or available."); + } + + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .build(); + + job.setPrintable(new PolylinePrintingTest()); + if (job.printDialog()) { + job.print(); + } + + passFailJFrame.awaitAndCheck(); + } public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { - if (pageIndex > 0) { return NO_SUCH_PAGE; } @@ -66,7 +91,6 @@ public class PolylinePrintingTest implements Printable { private void drawPolylineGOOD(Graphics2D g2d, int[] x2Points, int[] y2Points) { - Path2D polyline = new Path2D.Float(Path2D.WIND_EVEN_ODD, x2Points.length); @@ -83,141 +107,4 @@ public class PolylinePrintingTest implements Printable { g.translate(0, offset); g.drawPolyline(xp, yp, xp.length); } - - public PolylinePrintingTest() throws PrinterException { - PrinterJob job = PrinterJob.getPrinterJob(); - PageFormat pf = job.defaultPage(); - Paper p = pf.getPaper(); - p.setImageableArea(0,0,p.getWidth(), p.getHeight()); - pf.setPaper(p); - job.setPrintable(this, pf); - if (job.printDialog()) { - job.print(); - } - } - - public static void main(String[] args) throws PrinterException { - String[] instructions = { - "You must have a printer available to perform this test.", - "OK the print dialog, and collect the printed page.", - "Passing test : Output should show two identical chevrons.", - "Failing test : The line joins will appear different." - }; - Sysout.createDialog(); - Sysout.printInstructions(instructions); - new PolylinePrintingTest(); - } } - -class Sysout { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog { - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - } - -}// TestDialog class - From 027aea9d2e0dff29fcd00fa7074ca955066929ec Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 23 Oct 2025 07:05:08 +0000 Subject: [PATCH 033/736] 8370325: G1: Disallow GC for TLAB allocation Reviewed-by: iwalulya, ayang --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 21 ++++++++++++++------- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 21 +++++++++------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 485caa9f6c0..d3e02df3e09 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -403,21 +403,25 @@ HeapWord* G1CollectedHeap::allocate_new_tlab(size_t min_size, assert_heap_not_locked_and_not_at_safepoint(); assert(!is_humongous(requested_size), "we do not allow humongous TLABs"); - return attempt_allocation(min_size, requested_size, actual_size); + // Do not allow a GC because we are allocating a new TLAB to avoid an issue + // with UseGCOverheadLimit: although this GC would return null if the overhead + // limit would be exceeded, but it would likely free at least some space. + // So the subsequent outside-TLAB allocation could be successful anyway and + // the indication that the overhead limit had been exceeded swallowed. + return attempt_allocation(min_size, requested_size, actual_size, false /* allow_gc */); } -HeapWord* -G1CollectedHeap::mem_allocate(size_t word_size) { +HeapWord* G1CollectedHeap::mem_allocate(size_t word_size) { assert_heap_not_locked_and_not_at_safepoint(); if (is_humongous(word_size)) { return attempt_allocation_humongous(word_size); } size_t dummy = 0; - return attempt_allocation(word_size, word_size, &dummy); + return attempt_allocation(word_size, word_size, &dummy, true /* allow_gc */); } -HeapWord* G1CollectedHeap::attempt_allocation_slow(uint node_index, size_t word_size) { +HeapWord* G1CollectedHeap::attempt_allocation_slow(uint node_index, size_t word_size, bool allow_gc) { ResourceMark rm; // For retrieving the thread names in log messages. // Make sure you read the note in attempt_allocation_humongous(). @@ -444,6 +448,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(uint node_index, size_t word_ result = _allocator->attempt_allocation_locked(node_index, word_size); if (result != nullptr) { return result; + } else if (!allow_gc) { + return nullptr; } // Read the GC count while still holding the Heap_lock. @@ -612,7 +618,8 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion range) { inline HeapWord* G1CollectedHeap::attempt_allocation(size_t min_word_size, size_t desired_word_size, - size_t* actual_word_size) { + size_t* actual_word_size, + bool allow_gc) { assert_heap_not_locked_and_not_at_safepoint(); assert(!is_humongous(desired_word_size), "attempt_allocation() should not " "be called for humongous allocation requests"); @@ -624,7 +631,7 @@ inline HeapWord* G1CollectedHeap::attempt_allocation(size_t min_word_size, if (result == nullptr) { *actual_word_size = desired_word_size; - result = attempt_allocation_slow(node_index, desired_word_size); + result = attempt_allocation_slow(node_index, desired_word_size, allow_gc); } assert_heap_not_locked(); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 7e3f8a30285..0d354525d89 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -439,18 +439,14 @@ private: // // * If either call cannot satisfy the allocation request using the // current allocating region, they will try to get a new one. If - // this fails, they will attempt to do an evacuation pause and - // retry the allocation. - // - // * If all allocation attempts fail, even after trying to schedule - // an evacuation pause, allocate_new_tlab() will return null, - // whereas mem_allocate() will attempt a heap expansion and/or - // schedule a Full GC. + // this fails, (only) mem_allocate() will attempt to do an evacuation + // pause and retry the allocation. Allocate_new_tlab() will return null, + // deferring to the following mem_allocate(). // // * We do not allow humongous-sized TLABs. So, allocate_new_tlab // should never be called with word_size being humongous. All // humongous allocation requests should go to mem_allocate() which - // will satisfy them with a special path. + // will satisfy them in a special path. HeapWord* allocate_new_tlab(size_t min_size, size_t requested_size, @@ -463,12 +459,13 @@ private: // should only be used for non-humongous allocations. inline HeapWord* attempt_allocation(size_t min_word_size, size_t desired_word_size, - size_t* actual_word_size); - + size_t* actual_word_size, + bool allow_gc); // Second-level mutator allocation attempt: take the Heap_lock and // retry the allocation attempt, potentially scheduling a GC - // pause. This should only be used for non-humongous allocations. - HeapWord* attempt_allocation_slow(uint node_index, size_t word_size); + // pause if allow_gc is set. This should only be used for non-humongous + // allocations. + HeapWord* attempt_allocation_slow(uint node_index, size_t word_size, bool allow_gc); // Takes the Heap_lock and attempts a humongous allocation. It can // potentially schedule a GC pause. From dcf46a0a195d7386ed0bc872f60eb9c586425cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 23 Oct 2025 08:22:32 +0000 Subject: [PATCH 034/736] 8369658: Client emulation mode sets MaxRAM too late Reviewed-by: aboldtch, stefank --- .../share/compiler/compilerDefinitions.cpp | 28 +++++++++++++------ .../share/compiler/compilerDefinitions.hpp | 2 ++ src/hotspot/share/runtime/arguments.cpp | 6 ++++ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index 35201973dfe..aed1edc0db5 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -215,11 +215,6 @@ void CompilerConfig::set_client_emulation_mode_flags() { if (FLAG_IS_DEFAULT(CodeCacheExpansionSize)) { FLAG_SET_ERGO(CodeCacheExpansionSize, 32*K); } - if (FLAG_IS_DEFAULT(MaxRAM)) { - // Do not use FLAG_SET_ERGO to update MaxRAM, as this will impact - // heap setting done based on available phys_mem (see Arguments::set_heap_size). - FLAG_SET_DEFAULT(MaxRAM, 1ULL*G); - } if (FLAG_IS_DEFAULT(CICompilerCount)) { FLAG_SET_ERGO(CICompilerCount, 1); } @@ -553,21 +548,36 @@ bool CompilerConfig::check_args_consistency(bool status) { return status; } -void CompilerConfig::ergo_initialize() { +bool CompilerConfig::should_set_client_emulation_mode_flags() { #if !COMPILER1_OR_COMPILER2 - return; + return false; #endif if (has_c1()) { if (!is_compilation_mode_selected()) { if (NeverActAsServerClassMachine) { - set_client_emulation_mode_flags(); + return true; } } else if (!has_c2() && !is_jvmci_compiler()) { - set_client_emulation_mode_flags(); + return true; } } + return false; +} + +void CompilerConfig::ergo_initialize() { +#if !COMPILER1_OR_COMPILER2 + return; +#endif + + // This property is also checked when selecting the heap size. Since client + // emulation mode influences Java heap memory usage, part of the logic must + // occur before choosing the heap size. + if (should_set_client_emulation_mode_flags()) { + set_client_emulation_mode_flags(); + } + set_legacy_emulation_flags(); set_compilation_policy_flags(); diff --git a/src/hotspot/share/compiler/compilerDefinitions.hpp b/src/hotspot/share/compiler/compilerDefinitions.hpp index 1c8c65b2a53..a9b052ff782 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.hpp +++ b/src/hotspot/share/compiler/compilerDefinitions.hpp @@ -151,6 +151,8 @@ public: inline static CompilerType compiler_type(); + static bool should_set_client_emulation_mode_flags(); + private: static bool is_compilation_mode_selected(); static void set_compilation_policy_flags(); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 0d9973a1b09..0d92f22af79 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1521,6 +1521,12 @@ void Arguments::set_heap_size() { !FLAG_IS_DEFAULT(InitialRAMPercentage) || !FLAG_IS_DEFAULT(MaxRAM); + if (CompilerConfig::should_set_client_emulation_mode_flags() && + FLAG_IS_DEFAULT(MaxRAM)) { + // Reduce the maximum available memory if client emulation mode is enabled. + FLAG_SET_DEFAULT(MaxRAM, 1ULL*G); + } + if (has_ram_limit) { if (!FLAG_IS_DEFAULT(MaxRAM)) { // The user has configured MaxRAM, use that instead of physical memory From aec138886ec2dff765ed810059a1c7b9905c43ca Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Thu, 23 Oct 2025 09:06:00 +0000 Subject: [PATCH 035/736] 8313770: jdk/internal/platform/docker/TestSystemMetrics.java fails on Ubuntu Reviewed-by: sgehwolf, mbaesken, syan --- .../test/lib/containers/cgroup/MetricsTesterCgroupV2.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/lib/jdk/test/lib/containers/cgroup/MetricsTesterCgroupV2.java b/test/lib/jdk/test/lib/containers/cgroup/MetricsTesterCgroupV2.java index a3723e2eda2..2a756102ded 100644 --- a/test/lib/jdk/test/lib/containers/cgroup/MetricsTesterCgroupV2.java +++ b/test/lib/jdk/test/lib/containers/cgroup/MetricsTesterCgroupV2.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Red Hat Inc. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -447,13 +448,13 @@ public class MetricsTesterCgroupV2 implements CgroupMetricsTester { Metrics metrics = Metrics.systemMetrics(); long oldVal = metrics.getBlkIOServiceCount(); long newVal = getIoStatAccumulate(new String[] { "rios", "wios" }); - if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) { + if (newVal < oldVal) { fail("io.stat->rios/wios: ", oldVal, newVal); } oldVal = metrics.getBlkIOServiced(); newVal = getIoStatAccumulate(new String[] { "rbytes", "wbytes" }); - if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) { + if (newVal < oldVal) { fail("io.stat->rbytes/wbytes: ", oldVal, newVal); } } From da968dc645db498b4315e4c8926e7aeb21cc533a Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 23 Oct 2025 10:02:03 +0000 Subject: [PATCH 036/736] 8370227: Migrate micros-javac benchmarks from jmh-jdk-microbenchmarks Reviewed-by: asotona, erikj, ecaspole --- .gitignore | 1 + test/benchmarks/micros-javac/README.md | 61 +++++ test/benchmarks/micros-javac/pom.xml | 139 +++++++++++ .../langtools/javac/GroupJavacBenchmark.java | 231 ++++++++++++++++++ .../bench/langtools/javac/JavacBenchmark.java | 198 +++++++++++++++ .../langtools/javac/SingleJavacBenchmark.java | 69 ++++++ 6 files changed, 699 insertions(+) create mode 100644 test/benchmarks/micros-javac/README.md create mode 100644 test/benchmarks/micros-javac/pom.xml create mode 100644 test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/GroupJavacBenchmark.java create mode 100644 test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/JavacBenchmark.java create mode 100644 test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/SingleJavacBenchmark.java diff --git a/.gitignore b/.gitignore index 9145a9fa67b..852b692f99b 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ NashornProfile.txt **/core.[0-9]* *.rej *.orig +test/benchmarks/**/target diff --git a/test/benchmarks/micros-javac/README.md b/test/benchmarks/micros-javac/README.md new file mode 100644 index 00000000000..66ca073a763 --- /dev/null +++ b/test/benchmarks/micros-javac/README.md @@ -0,0 +1,61 @@ +# Javac microbenchmarks + +The Javac Microbenchmarks is a collection of microbenchmarks for measuring +the performance of Javac API using the +[JMH](http://openjdk.java.net/projects/code-tools/jmh/) framework. + + +## Building and running the project + +Currently, the project can be built and run with JDK 9 and later. This is +a Maven project and is built by: + + $ mvn clean install + +After building, the executable jar is target/micros-javac-[version].jar. +Run the benchmarks with: + + $ java -jar target/micros-javac-*.jar [optional jmh parameters] + +See the entire list of benchmarks using: + + $ java -jar target/micros-javacs-*.jar -l [optional regex to select benchmarks] + +For example: + + $ java -jar target/micros-javac-1.0-SNAPSHOT.jar -l + Benchmarks: + org.openjdk.bench.langtools.javac.GroupJavacBenchmark.coldGroup + org.openjdk.bench.langtools.javac.GroupJavacBenchmark.hotGroup + org.openjdk.bench.langtools.javac.SingleJavacBenchmark.compileCold + org.openjdk.bench.langtools.javac.SingleJavacBenchmark.compileHot + +And the same regex syntax works to run some test: + + $ java -jar target/micros-javac-1.0-SNAPSHOT.jar SingleJavacBenchmark.compileHot + +## Troubleshooting + +### Build of micros-javac module got stuck + +If you build got stuck on `[get] Getting: https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip` then you are probably experiencing some networking or web proxy obstacles. + +One solution is to download required reference JDK from [https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip](https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip) manually and then build the project with property pointing to the local copy: + + $ mvn clean install -Djavac.benchmark.openjdk.zip.download.url=file:////openjdk-11+28_windows-x64_bin.zip + +Note: Please use `openjdk-11+28_windows-x64_bin.zip` to build the project no matter what target platform is. + +Another solution might be to add proxy settings: + + $ mvn -Dhttps.proxyHost=... -Dhttps.proxyPort=... clean install + +### Execution of micros-javac benchmarks takes several hours + +micros-javac benchmarks consist of two sets of benchmarks: + * `SingleJavacBenchmark` (which is parametrized) measures each single javac compilation stage in an isolated run. This benchmark is designed for exact automated performance regression testing and it takes several hours to execute completely. + * `GroupJavacBenchmark` is grouping the measurements of all javac compilation stages into one run and its execution should take less than 30 minutes on a regular developers computer. + +Solution to speed up javac benchmarking is to select only `GroupJavacBenchmark` for execution using following command line: + + $ java -jar target/micros-javac-1.0-SNAPSHOT.jar .*GroupJavacBenchmark.* diff --git a/test/benchmarks/micros-javac/pom.xml b/test/benchmarks/micros-javac/pom.xml new file mode 100644 index 00000000000..5a8a40d7a9a --- /dev/null +++ b/test/benchmarks/micros-javac/pom.xml @@ -0,0 +1,139 @@ + + + 4.0.0 + org.openjdk + micros-javac + jar + 1.0-SNAPSHOT + OpenJDK Microbenchmark of Java Compile + + https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip + UTF-8 + 1.36 + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.1 + + + package + + shade + + + + + org.openjdk.jmh.Main + + + META-INF/BenchmarkList + + + META-INF/CompilerHints + + + false + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.1 + + 1.8 + 1.8 + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + + + + org.apache.maven.plugins + maven-release-plugin + 3.1.1 + + + maven-deploy-plugin + 3.1.4 + + + maven-antrun-plugin + 3.1.0 + + + process-resources + + + + + + + + + + + + + +------------------------------------------------- +Bundling JDK sources with following release info: +------------------------------------------------- +${release.info} +------------------------------------------------- + + + + + run + + + + + + + + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + provided + + + diff --git a/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/GroupJavacBenchmark.java b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/GroupJavacBenchmark.java new file mode 100644 index 00000000000..5ca3f0bf648 --- /dev/null +++ b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/GroupJavacBenchmark.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.langtools.javac; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Group; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +public class GroupJavacBenchmark extends JavacBenchmark { + + public static final String COLD_GROUP_NAME = "coldGroup"; + public static final int COLD_ITERATION_WARMUPS = 0; + public static final int COLD_ITERATIONS = 1; + public static final int COLD_FORK_WARMUPS = 1; + public static final int COLD_FORKS = 15; + + public static final String HOT_GROUP_NAME = "hotGroup"; + public static final int HOT_ITERATION_WARMUPS = 8; + public static final int HOT_ITERATIONS = 10; + public static final int HOT_FORK_WARMUPS = 0; + public static final int HOT_FORKS = 1; + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold1_Init() throws InterruptedException { + Stage.Init.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold2_Parse() throws InterruptedException { + Stage.Parse.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold3_InitModules() throws InterruptedException { + Stage.InitModules.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold4_Enter() throws InterruptedException { + Stage.Enter.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold5_Attribute() throws InterruptedException { + Stage.Attribute.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold6_Flow() throws InterruptedException { + Stage.Flow.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold7_Desugar() throws InterruptedException { + Stage.Desugar.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold8_Generate(Blackhole bh) throws IOException { + compile(bh, Stage.Generate); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot1_Init() throws InterruptedException { + Stage.Init.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot2_Parse() throws InterruptedException { + Stage.Parse.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot3_InitModules() throws InterruptedException { + Stage.InitModules.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot4_Enter() throws InterruptedException { + Stage.Enter.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot5_Attribute() throws InterruptedException { + Stage.Attribute.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot6_Flow() throws InterruptedException { + Stage.Flow.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot7_Desugar() throws InterruptedException { + Stage.Desugar.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot8_Generate(Blackhole bh) throws IOException { + compile(bh, Stage.Generate); + } +} diff --git a/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/JavacBenchmark.java b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/JavacBenchmark.java new file mode 100644 index 00000000000..1afffc6d044 --- /dev/null +++ b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/JavacBenchmark.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.langtools.javac; + +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Context.Factory; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Pair; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Queue; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.CONFIG; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileObject; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +public class JavacBenchmark { + + static final Logger LOG = Logger.getLogger(JavacBenchmark.class.getName()); + + public enum Stage { + Init, Parse, InitModules, Enter, Attribute, Flow, Desugar, Generate; + + public synchronized void waitFor() throws InterruptedException { + wait(); + } + public synchronized void notifyDone() { + notifyAll(); + LOG.log(FINE, "{0} finished.", this.name()); + } + public boolean isAfter(Stage other) { + return ordinal() > other.ordinal(); + } + } + + private Path root; + private Path srcList; + + @Setup(Level.Trial) + public void setup(Blackhole bh) throws IOException, InterruptedException { + LOG.log(CONFIG, "Release info of the sources to be compiled by the benchmark:\n{0}", new String(JavacBenchmark.class.getResourceAsStream("/release").readAllBytes(), StandardCharsets.UTF_8)); + root = Files.createTempDirectory("JavacBenchmarkRoot"); + srcList = root.resolve("sources.list"); + int i = 0; + try (PrintStream srcListOut = new PrintStream(srcList.toFile())) { + try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(JavacBenchmark.class.getResourceAsStream("/src.zip")))) { + for (ZipEntry entry; (entry = zis.getNextEntry()) != null;) { + final String ename = entry.getName(); + if (!ename.startsWith("java.desktop") && !ename.startsWith("jdk.internal.vm.compiler") && !ename.startsWith("jdk.aot") && !ename.startsWith("jdk.accessibility")) { + if (!entry.isDirectory() && ename.endsWith(".java")) { + Path dst = root.resolve(ename); + Files.createDirectories(dst.getParent()); + Files.copy(zis, dst); + Files.readAllBytes(dst); //reads all the file back to exclude antivirus scanning time from following measurements + srcListOut.println(dst.toString()); + i++; + } + } + } + } + } + Files.walk(root).map(Path::toFile).forEach(File::deleteOnExit); //mark all files and folders for deletion on JVM exit for cases when tearDown is not executed + Thread.sleep(10000); //give some more time for the system to catch a breath for more precise measurement + LOG.log(FINE, "Extracted {0} sources.", i); + } + + @TearDown(Level.Trial) + public void tearDown() throws IOException { + Files.walk(root).sorted(Comparator.reverseOrder()).map(Path::toFile).forEachOrdered(File::delete); + LOG.fine("Sources deleted."); + } + + protected void compile(Blackhole bh, final Stage stopAt) throws IOException { + final OutputStream bhos = new OutputStream() { + @Override + public void write(int b) throws IOException { + bh.consume(b); + } + @Override + public void write(byte[] b, int off, int len) throws IOException { + bh.consume(b); + } + }; + final Context ctx = new Context(); + //inject JavaCompiler wrapping all measured methods so they directly report to the benchmark + ctx.put(JavaCompiler.compilerKey, (Factory)(c) -> { + return new JavaCompiler(c) { + @Override + public List parseFiles(Iterable fileObjects) { + Stage.Init.notifyDone(); + return stopAt.isAfter(Stage.Init) ? super.parseFiles(fileObjects) : List.nil(); + } + + @Override + public List initModules(List roots) { + Stage.Parse.notifyDone(); + return stopAt.isAfter(Stage.Parse) ? super.initModules(roots) : List.nil(); + } + + @Override + public List enterTrees(List roots) { + Stage.InitModules.notifyDone(); + return stopAt.isAfter(Stage.InitModules) ? super.enterTrees(roots) : List.nil(); + } + + @Override + public Queue> attribute(Queue> envs) { + Stage.Enter.notifyDone(); + return stopAt.isAfter(Stage.Enter) ? super.attribute(envs) : new ListBuffer<>(); + } + + @Override + public Queue> flow(Queue> envs) { + Stage.Attribute.notifyDone(); + return stopAt.isAfter(Stage.Attribute) ? super.flow(envs) : new ListBuffer<>(); + } + + @Override + public Queue, JCTree.JCClassDecl>> desugar(Queue> envs) { + Stage.Flow.notifyDone(); + return stopAt.isAfter(Stage.Flow) ? super.desugar(envs) : new ListBuffer<>(); + } + + @Override + public void generate(Queue, JCTree.JCClassDecl>> queue) { + Stage.Desugar.notifyDone(); + if (stopAt.isAfter(Stage.Desugar)) super.generate(queue); + } + }; + }); + //JavaFileManager directing all writes to a Blackhole to avoid measurement fluctuations due to delayed filesystem writes + try (JavacFileManager mngr = new JavacFileManager(ctx, true, null) { + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location arg0, String arg1, JavaFileObject.Kind arg2, FileObject arg3) throws IOException { + return new ForwardingJavaFileObject(super.getJavaFileForOutput(arg0, arg1, arg2, arg3)) { + @Override + public OutputStream openOutputStream() throws IOException { + return bhos; + } + }; + } + }) { + String[] cmdLine = new String[] {"-XDcompilePolicy=simple", "-implicit:none", "-nowarn", "--module-source-path", root.toString(), "-d", root.toString(), "-XDignore.symbol.file=true", "@" + srcList.toString()}; + if (new Main("javac").compile(cmdLine, ctx).exitCode != 0) { + throw new IOException("compilation failed"); + } + } + LOG.fine("Compilation finished."); + } +} diff --git a/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/SingleJavacBenchmark.java b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/SingleJavacBenchmark.java new file mode 100644 index 00000000000..2cc5c1a7c83 --- /dev/null +++ b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/SingleJavacBenchmark.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.langtools.javac; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +public class SingleJavacBenchmark extends JavacBenchmark { + + @Param + public Stage stopStage; + + @Benchmark + @Threads(1) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = 0) + @Measurement(iterations = 1) + @Fork(warmups = 1, value = 15, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void compileCold(Blackhole bh) throws IOException { + compile(bh, stopStage); + } + + @Benchmark + @Threads(1) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = 8) + @Measurement(iterations = 10) + @Fork(warmups = 0, value = 1, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void compileHot(Blackhole bh) throws IOException { + compile(bh, stopStage); + } +} From 5a83d6a8355b36cffcf5945b9c6bcfc7aebdd136 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 23 Oct 2025 11:09:33 +0000 Subject: [PATCH 037/736] 8370406: Parallel: Refactor ParCompactionManager::mark_and_push Reviewed-by: fandreuzzi, iwalulya --- .../share/gc/parallel/psCompactionManager.hpp | 1 - .../parallel/psCompactionManager.inline.hpp | 40 +++++++++---------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.hpp index 613361c7039..0a404579da8 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp @@ -188,7 +188,6 @@ public: ParMarkBitMap* mark_bitmap() { return _mark_bitmap; } // Save for later processing. Must not fail. - inline void push(oop obj); inline void push_region(size_t index); // Check mark and maybe push on marking stack. diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp index 75f54caf89e..663cd83be9c 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp @@ -56,10 +56,6 @@ inline bool ParCompactionManager::steal(int queue_num, size_t& region) { return region_task_queues()->steal(queue_num, region); } -inline void ParCompactionManager::push(oop obj) { - marking_stack()->push(ScannerTask(obj)); -} - void ParCompactionManager::push_region(size_t index) { #ifdef ASSERT @@ -74,24 +70,26 @@ void ParCompactionManager::push_region(size_t index) template inline void ParCompactionManager::mark_and_push(T* p) { T heap_oop = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(heap_oop)) { - oop obj = CompressedOops::decode_not_null(heap_oop); - assert(ParallelScavengeHeap::heap()->is_in(obj), "should be in heap"); - - if (mark_bitmap()->mark_obj(obj)) { - if (StringDedup::is_enabled() && - java_lang_String::is_instance(obj) && - psStringDedup::is_candidate_from_mark(obj)) { - _string_dedup_requests.add(obj); - } - - ContinuationGCSupport::transform_stack_chunk(obj); - - assert(_marking_stats_cache != nullptr, "inv"); - _marking_stats_cache->push(obj, obj->size()); - push(obj); - } + if (CompressedOops::is_null(heap_oop)) { + return; } + + oop obj = CompressedOops::decode_not_null(heap_oop); + if (!mark_bitmap()->mark_obj(obj)) { + // Marked by another worker. + return; + } + + if (StringDedup::is_enabled() && + java_lang_String::is_instance(obj) && + psStringDedup::is_candidate_from_mark(obj)) { + _string_dedup_requests.add(obj); + } + + ContinuationGCSupport::transform_stack_chunk(obj); + + _marking_stats_cache->push(obj, obj->size()); + marking_stack()->push(ScannerTask(obj)); } inline void ParCompactionManager::FollowStackClosure::do_void() { From 3fdb15fc5203a559a5e6951a5a9505160057f258 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 23 Oct 2025 11:46:01 +0000 Subject: [PATCH 038/736] 8369622: GlobalChunkPoolMutex is recursively locked during error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Johan Sjölen Co-authored-by: Afshin Zafari Reviewed-by: dholmes, azafari, phubner --- src/hotspot/share/memory/arena.cpp | 19 +++++++++++++------ src/hotspot/share/memory/arena.hpp | 5 ++++- src/hotspot/share/nmt/mallocTracker.cpp | 6 +++++- src/hotspot/share/nmt/nmtUsage.cpp | 7 ++++++- .../test_nmt_buffer_overflow_detection.cpp | 16 ++++++++++++++++ 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/memory/arena.cpp b/src/hotspot/share/memory/arena.cpp index db0bb8add21..b9968083e0e 100644 --- a/src/hotspot/share/memory/arena.cpp +++ b/src/hotspot/share/memory/arena.cpp @@ -39,19 +39,26 @@ // It is used very early in the vm initialization, in allocation // code and other areas. For many calls, the current thread has not // been created so we cannot use Mutex. -static PlatformMutex* GlobalChunkPoolMutex = nullptr; +static DeferredStatic GlobalChunkPoolMutex; void Arena::initialize_chunk_pool() { - GlobalChunkPoolMutex = new PlatformMutex(); + GlobalChunkPoolMutex.initialize(); } -ChunkPoolLocker::ChunkPoolLocker() { - assert(GlobalChunkPoolMutex != nullptr, "must be initialized"); - GlobalChunkPoolMutex->lock(); +ChunkPoolLocker::ChunkPoolLocker(LockStrategy ls) { + if (ls == LockStrategy::Lock) { + GlobalChunkPoolMutex->lock(); + _locked = true; + } else { + assert(ls == LockStrategy::Try, "must be"); + _locked = GlobalChunkPoolMutex->try_lock(); + } }; ChunkPoolLocker::~ChunkPoolLocker() { - GlobalChunkPoolMutex->unlock(); + if (_locked) { + GlobalChunkPoolMutex->unlock(); + } }; // Pre-defined default chunk sizes must be arena-aligned, see Chunk::operator new() diff --git a/src/hotspot/share/memory/arena.hpp b/src/hotspot/share/memory/arena.hpp index e2169ee406e..b4a0546babf 100644 --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -38,8 +38,11 @@ #define ARENA_ALIGN(x) (align_up((x), ARENA_AMALLOC_ALIGNMENT)) class ChunkPoolLocker : public StackObj { + bool _locked; public: - ChunkPoolLocker(); + enum class LockStrategy { Lock, Try }; + + ChunkPoolLocker(LockStrategy ls = LockStrategy::Lock); ~ChunkPoolLocker(); }; diff --git a/src/hotspot/share/nmt/mallocTracker.cpp b/src/hotspot/share/nmt/mallocTracker.cpp index 75089dffc30..a61a27db25d 100644 --- a/src/hotspot/share/nmt/mallocTracker.cpp +++ b/src/hotspot/share/nmt/mallocTracker.cpp @@ -65,7 +65,11 @@ void MallocMemorySnapshot::copy_to(MallocMemorySnapshot* s) { // Use lock to make sure that mtChunks don't get deallocated while the // copy is going on, because their size is adjusted using this // buffer in make_adjustment(). - ChunkPoolLocker lock; + ChunkPoolLocker::LockStrategy ls = ChunkPoolLocker::LockStrategy::Lock; + if (VMError::is_error_reported() && VMError::is_error_reported_in_current_thread()) { + ls = ChunkPoolLocker::LockStrategy::Try; + } + ChunkPoolLocker cpl(ls); s->_all_mallocs = _all_mallocs; size_t total_size = 0; size_t total_count = 0; diff --git a/src/hotspot/share/nmt/nmtUsage.cpp b/src/hotspot/share/nmt/nmtUsage.cpp index 3a9a232a36e..9e6fc3e183b 100644 --- a/src/hotspot/share/nmt/nmtUsage.cpp +++ b/src/hotspot/share/nmt/nmtUsage.cpp @@ -30,6 +30,7 @@ #include "nmt/nmtUsage.hpp" #include "nmt/threadStackTracker.hpp" #include "runtime/mutexLocker.hpp" +#include "utilities/vmError.hpp" // Enabled all options for snapshot. const NMTUsageOptions NMTUsage::OptionsAll = { true, true, true }; @@ -58,7 +59,11 @@ void NMTUsage::update_malloc_usage() { // Lock needed to keep values in sync, total area size // is deducted from mtChunk in the end to give correct values. { - ChunkPoolLocker lock; + ChunkPoolLocker::LockStrategy ls = ChunkPoolLocker::LockStrategy::Lock; + if (VMError::is_error_reported() && VMError::is_error_reported_in_current_thread()) { + ls = ChunkPoolLocker::LockStrategy::Try; + } + ChunkPoolLocker cpl(ls); ms = MallocMemorySummary::as_snapshot(); } diff --git a/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp b/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp index 82ddd28d56c..5752d6df75d 100644 --- a/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp @@ -23,6 +23,7 @@ */ #include "memory/allocation.hpp" +#include "memory/arena.hpp" #include "nmt/memTracker.hpp" #include "runtime/os.hpp" #include "sanitizers/address.hpp" @@ -142,6 +143,21 @@ DEFINE_TEST(test_corruption_on_realloc_growing, COMMON_NMT_HEAP_CORRUPTION_MESSA static void test_corruption_on_realloc_shrinking() { test_corruption_on_realloc(0x11, 0x10); } DEFINE_TEST(test_corruption_on_realloc_shrinking, COMMON_NMT_HEAP_CORRUPTION_MESSAGE_PREFIX); +static void test_chunkpool_lock() { + if (!MemTracker::enabled()) { + tty->print_cr("Skipped"); + return; + } + PrintNMTStatistics = true; + { + ChunkPoolLocker cpl; + char* mem = (char*)os::malloc(100, mtTest); + memset(mem - 16, 0, 100 + 16 + 2); + os::free(mem); + } +} +DEFINE_TEST(test_chunkpool_lock, COMMON_NMT_HEAP_CORRUPTION_MESSAGE_PREFIX); + /////// // realloc is the trickiest of the bunch. Test that realloc works and correctly takes over From b597b6556dbd18360423c29c784a5fbb792a8899 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 23 Oct 2025 13:03:13 +0000 Subject: [PATCH 039/736] 8370065: Windows perfmemory coding - use SetSecurityDescriptorControl directly Reviewed-by: dholmes, stuefe --- src/hotspot/os/windows/perfMemory_windows.cpp | 38 ++++++------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index f815f3bd104..f54a2b52cca 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -42,11 +42,7 @@ #include #include #include - -typedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)( - IN PSECURITY_DESCRIPTOR pSecurityDescriptor, - IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, - IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet); +#include // Standard Memory Implementation Details @@ -952,28 +948,18 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, return false; } - // if running on windows 2000 or later, set the automatic inheritance - // control flags. - SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl; - _SetSecurityDescriptorControl = (SetSecurityDescriptorControlFnPtr) - GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")), - "SetSecurityDescriptorControl"); - - if (_SetSecurityDescriptorControl != nullptr) { - // We do not want to further propagate inherited DACLs, so making them - // protected prevents that. - if (!_SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED, - SE_DACL_PROTECTED)) { - log_debug(perf)("SetSecurityDescriptorControl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); - return false; - } + // We do not want to further propagate inherited DACLs, so making them + // protected prevents that. + if (!SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { + log_debug(perf)("SetSecurityDescriptorControl failure: lasterror = %d", GetLastError()); + FREE_C_HEAP_ARRAY(char, newACL); + return false; } - // Note, the security descriptor maintains a reference to the newACL, not - // a copy of it. Therefore, the newACL is not freed here. It is freed when - // the security descriptor containing its reference is freed. - // - return true; + + // Note, the security descriptor maintains a reference to the newACL, not + // a copy of it. Therefore, the newACL is not freed here. It is freed when + // the security descriptor containing its reference is freed. + return true; } // method to create a security attributes structure, which contains a From aaa9fbf6b5a0dda0773a657a986246b407402fa1 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 23 Oct 2025 13:03:31 +0000 Subject: [PATCH 040/736] 8368365: ASAN errors should produce hs-err files and core dumps Reviewed-by: mbaesken, asmehra --- src/hotspot/share/logging/logTag.hpp | 1 + src/hotspot/share/runtime/globals.hpp | 2 +- src/hotspot/share/runtime/threads.cpp | 5 + src/hotspot/share/sanitizers/address.cpp | 120 ++++++++++++++++++ src/hotspot/share/sanitizers/address.hpp | 12 ++ src/hotspot/share/utilities/vmError.cpp | 20 ++- .../runtime/ErrorHandling/AsanReportTest.java | 87 +++++++++++++ 7 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 src/hotspot/share/sanitizers/address.cpp create mode 100644 test/hotspot/jtreg/runtime/ErrorHandling/AsanReportTest.java diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index 6d0bd117ad9..3ad6a197d07 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -41,6 +41,7 @@ class outputStream; LOG_TAG(aot) \ LOG_TAG(arguments) \ LOG_TAG(array) \ + LOG_TAG(asan) \ LOG_TAG(attach) \ LOG_TAG(barrier) \ LOG_TAG(blocks) \ diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 513edaf6588..238517197b2 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -502,7 +502,7 @@ const int ObjectAlignmentInBytes = 8; "If > 0, provokes an error after VM initialization; the value " \ "determines which error to provoke. See controlled_crash() " \ "in vmError.cpp.") \ - range(0, 17) \ + range(0, 18) \ \ develop(uint, TestCrashInErrorHandler, 0, \ "If > 0, provokes an error inside VM error handler (a secondary " \ diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 52275049eae..299905ff0a2 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -97,6 +97,7 @@ #include "runtime/trimNativeHeap.hpp" #include "runtime/vm_version.hpp" #include "runtime/vmOperations.hpp" +#include "sanitizers/address.hpp" #include "services/attachListener.hpp" #include "services/management.hpp" #include "services/threadIdTable.hpp" @@ -702,6 +703,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // No more stub generation allowed after that point. StubCodeDesc::freeze(); +#ifdef ADDRESS_SANITIZER + Asan::initialize(); +#endif + // Set flag that basic initialization has completed. Used by exceptions and various // debug stuff, that does not work until all basic classes have been initialized. set_init_completed(); diff --git a/src/hotspot/share/sanitizers/address.cpp b/src/hotspot/share/sanitizers/address.cpp new file mode 100644 index 00000000000..b050039b1b8 --- /dev/null +++ b/src/hotspot/share/sanitizers/address.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifdef ADDRESS_SANITIZER + +#include "logging/log.hpp" +#include "sanitizers/address.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/vmError.hpp" + +#include +#include + +typedef void (*callback_setter_t) (void (*callback)(const char *)); +static callback_setter_t g_callback_setter = nullptr; +static const char* g_report = nullptr; + +extern "C" void asan_error_callback(const char* report_text) { + // Please keep things very short and simple here and use as little + // as possible of any hotspot infrastructure. However shaky the JVM, + // we should always at least get the ASAN report on stderr. + + // Note: this is threadsafe since ASAN synchronizes error reports + g_report = report_text; + + // First, print off the bare error to stderr + fprintf(stderr, "JVM caught ASAN Error\n"); + fprintf(stderr, "%s\n", report_text); + + // Then, let normal JVM error handling run its due course. + fatal("ASAN Error"); +} + +void Asan::initialize() { + + // For documentation of __asan_set_error_report_callback() see asan_interface.h . + g_callback_setter = (callback_setter_t) dlsym(RTLD_DEFAULT, "__asan_set_error_report_callback"); + if (g_callback_setter == nullptr) { + log_info(asan)("*** Failed to install JVM callback for ASAN. ASAN errors will not generate hs-err files. ***"); + return; + } + + g_callback_setter(asan_error_callback); + log_info(asan)("JVM callback for ASAN errors successfully installed"); + + // Controlling core dump behavior: + // + // In hotspot, CreateCoredumpOnCrash decides whether to create a core dump (on Posix, whether to + // end the process with abort(3) or exit(3)). + // + // Core generation in the default ASAN reporter is controlled by two options: + // - "abort_on_error=0" (default) - end with exit(3), "abort_on_error=1" end with abort(3) + // - "disable_coredump=1" (default) disables cores by imposing a near-zero core soft limit. + // By default both options are set to prevent cores. That default makes sense since ASAN cores + // can get very large (due to the shadow map) and very numerous (ASAN is typically ran for + // large-scale integration tests, not targeted micro-tests). + // + // In hotspot ASAN builds, we replace the default ASAN reporter. The soft limit imposed by + // "disable_coredump=1" is still in effect. But "abort_on_error" is not honored. Since we'd + // like to exhibit exactly the same behavior as the standard ASAN error reporter, we disable + // core files if ASAN would inhibit them (we just switch off CreateCoredumpOnCrash). + // + // Thus: + // abort_on_error disable_coredump core file? + // 0 0 No (enforced by ergo-setting CreateCoredumpOnCrash=0) + // (*) 0 1 No (enforced by ASAN-imposed soft limit) + // 1 0 Yes, unless -XX:-CreateCoredumpOnCrash set on command line + // 1 1 No (enforced by ASAN-imposed soft limit) + // (*) is the default if no ASAN options are specified. + + const char* const asan_options = getenv("ASAN_OPTIONS"); + const bool asan_inhibits_cores = (asan_options == nullptr) || + (::strstr(asan_options, "abort_on_error=1") == nullptr) || + (::strstr(asan_options, "disable_coredump=0") == nullptr); + if (asan_inhibits_cores) { + if (CreateCoredumpOnCrash) { + log_info(asan)("CreateCoredumpOnCrash overruled by%s asan options. Core generation disabled.", + asan_options != nullptr ? "" : " default setting for"); + log_info(asan)("Use 'ASAN_OPTIONS=abort_on_error=1:disable_coredump=0:unmap_shadow_on_exit=1' " + "to enable core generation."); + } + FLAG_SET_ERGO(CreateCoredumpOnCrash, false); + } +} + +bool Asan::had_error() { + return g_report != nullptr; +} + +void Asan::report(outputStream* st) { + if (had_error()) { + // Use raw print here to avoid truncation. + st->print_raw(g_report); + st->cr(); + st->cr(); + } +} + +#endif // ADDRESS_SANITIZER diff --git a/src/hotspot/share/sanitizers/address.hpp b/src/hotspot/share/sanitizers/address.hpp index 5186053f1c9..109aa59dac0 100644 --- a/src/hotspot/share/sanitizers/address.hpp +++ b/src/hotspot/share/sanitizers/address.hpp @@ -26,6 +26,8 @@ #define SHARE_SANITIZERS_ADDRESS_HPP #ifdef ADDRESS_SANITIZER +#include "memory/allStatic.hpp" + #include #endif @@ -74,4 +76,14 @@ } while (false) #endif +class outputStream; + +#ifdef ADDRESS_SANITIZER +struct Asan : public AllStatic { + static void initialize(); + static bool had_error(); + static void report(outputStream* st); +}; +#endif + #endif // SHARE_SANITIZERS_ADDRESS_HPP diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 0fbd8ed4259..e0cbb60c744 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -60,6 +60,7 @@ #include "runtime/vm_version.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" +#include "sanitizers/address.hpp" #include "sanitizers/ub.hpp" #include "utilities/debug.hpp" #include "utilities/decoder.hpp" @@ -910,7 +911,16 @@ void VMError::report(outputStream* st, bool _verbose) { STEP_IF("printing date and time", _verbose) os::print_date_and_time(st, buf, sizeof(buf)); - STEP_IF("printing thread", _verbose) +#ifdef ADDRESS_SANITIZER + STEP_IF("printing ASAN error information", _verbose && Asan::had_error()) + st->cr(); + st->print_cr("------------------ A S A N ----------------"); + st->cr(); + Asan::report(st); + st->cr(); +#endif // ADDRESS_SANITIZER + + STEP_IF("printing thread", _verbose) st->cr(); st->print_cr("--------------- T H R E A D ---------------"); st->cr(); @@ -2186,6 +2196,14 @@ void VMError::controlled_crash(int how) { fatal("Force crash with a nested ThreadsListHandle."); } } + case 18: { + // Trigger an error that should cause ASAN to report a double free or use-after-free. + // Please note that this is not 100% bullet-proof since it assumes that this block + // is not immediately repurposed by some other thread after free. + void* const p = os::malloc(4096, mtTest); + os::free(p); + os::free(p); + } default: // If another number is given, give a generic crash. fatal("Crashing with number %d", how); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/AsanReportTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/AsanReportTest.java new file mode 100644 index 00000000000..211df563e6c --- /dev/null +++ b/test/hotspot/jtreg/runtime/ErrorHandling/AsanReportTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025, IBM Corporation. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that we get ASAN-reports and hs-err files on ASAN error + * @library /test/lib + * @requires vm.asan + * @requires vm.flagless + * @requires vm.debug == true & os.family == "linux" + * @modules java.base/jdk.internal.misc + * java.management + * @run driver AsanReportTest + */ + +// Note: this test can only run on debug since it relies on VMError::controlled_crash() which +// only exists in debug builds. +import java.io.File; +import java.util.regex.Pattern; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class AsanReportTest { + + private static void do_test() throws Exception { + + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xmx64M", "-XX:CompressedClassSpaceSize=64M", + // Default ASAN options should prevent core file generation, which should overrule +CreateCoredumpOnCrash. + // We test below. + "-XX:+CreateCoredumpOnCrash", + "-Xlog:asan", + // Switch off NMT since it can alter the error ASAN sees; we want the pure double free error + "-XX:NativeMemoryTracking=off", + // Causes double-free in controlled_crash + "-XX:ErrorHandlerTest=18", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldNotHaveExitValue(0); + + // ASAN error should appear on stderr + output.shouldContain("CreateCoredumpOnCrash overruled"); + output.shouldContain("JVM caught ASAN Error"); + output.shouldMatch("AddressSanitizer.*double-free"); + output.shouldMatch("# +A fatal error has been detected by the Java Runtime Environment"); + output.shouldMatch("# +fatal error: ASAN"); + output.shouldNotContain("Aborted (core dumped)"); + + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output); + Pattern[] pat = new Pattern[] { + Pattern.compile(".*A S A N.*"), + Pattern.compile(".*AddressSanitizer.*double-free.*"), + Pattern.compile(".*(crash_with_segfault|controlled_crash).*") + }; + HsErrFileUtils.checkHsErrFileContent(hs_err_file, pat, false); + } + + public static void main(String[] args) throws Exception { + do_test(); + } + +} + From 6e898e21130259839e8060245c70182f70d8ee12 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Thu, 23 Oct 2025 15:46:34 +0000 Subject: [PATCH 041/736] 8369944: Notification can be lost due to interrupt in Object.wait Reviewed-by: dholmes, fbredberg --- src/hotspot/share/runtime/objectMonitor.cpp | 17 ++++++----------- src/hotspot/share/runtime/objectMonitor.hpp | 4 +--- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 142324fec7a..f6d569b1b7a 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -1863,10 +1863,10 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // could be profitable. // // TODO-FIXME: change the following logic to a loop of the form - // while (!timeout && !interrupted && _notified == 0) park() + // while (!timeout && !interrupted && node.TState == TS_WAIT) park() int ret = OS_OK; - int WasNotified = 0; + bool was_notified = false; // Need to check interrupt state whilst still _thread_in_vm bool interrupted = interruptible && current->is_interrupted(false); @@ -1882,7 +1882,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { ThreadBlockInVMPreprocess tbivs(current, csos, true /* allow_suspend */); if (interrupted || HAS_PENDING_EXCEPTION) { // Intentionally empty - } else if (!node._notified) { + } else if (node.TState == ObjectWaiter::TS_WAIT) { if (millis <= 0) { current->_ParkEvent->park(); } else { @@ -1910,7 +1910,6 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { Thread::SpinAcquire(&_wait_set_lock); if (node.TState == ObjectWaiter::TS_WAIT) { dequeue_specific_waiter(&node); // unlink from wait_set - assert(!node._notified, "invariant"); node.TState = ObjectWaiter::TS_RUN; } Thread::SpinRelease(&_wait_set_lock); @@ -1923,7 +1922,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { guarantee(node.TState != ObjectWaiter::TS_WAIT, "invariant"); OrderAccess::loadload(); if (has_successor(current)) clear_successor(); - WasNotified = node._notified; + was_notified = node.TState == ObjectWaiter::TS_ENTER; // Reentry phase -- reacquire the monitor. // re-enter contended monitor after object.wait(). @@ -1936,7 +1935,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { if (JvmtiExport::should_post_monitor_waited()) { JvmtiExport::post_monitor_waited(current, this, ret == OS_TIMEOUT); - if (node._notified && has_successor(current)) { + if (was_notified && has_successor(current)) { // In this part of the monitor wait-notify-reenter protocol it // is possible (and normal) for another thread to do a fastpath // monitor enter-exit while this thread is still trying to get @@ -2003,7 +2002,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { } // check if the notification happened - if (!WasNotified) { + if (!was_notified) { // no, it could be timeout or Thread.interrupt() or both // check for interrupt event, otherwise it is timeout if (interruptible && current->is_interrupted(true) && !HAS_PENDING_EXCEPTION) { @@ -2026,7 +2025,6 @@ bool ObjectMonitor::notify_internal(JavaThread* current) { ObjectWaiter* iterator = dequeue_waiter(); if (iterator != nullptr) { guarantee(iterator->TState == ObjectWaiter::TS_WAIT, "invariant"); - guarantee(!iterator->_notified, "invariant"); if (iterator->is_vthread()) { oop vthread = iterator->vthread(); @@ -2048,7 +2046,6 @@ bool ObjectMonitor::notify_internal(JavaThread* current) { inc_unmounted_vthreads(); } - iterator->_notified = true; iterator->_notifier_tid = JFR_THREAD_ID(current); did_notify = true; add_to_entry_list(current, iterator); @@ -2210,7 +2207,6 @@ bool ObjectMonitor::vthread_wait_reenter(JavaThread* current, ObjectWaiter* node Thread::SpinAcquire(&_wait_set_lock); if (node->TState == ObjectWaiter::TS_WAIT) { dequeue_specific_waiter(node); // unlink from wait_set - assert(!node->_notified, "invariant"); node->TState = ObjectWaiter::TS_RUN; } Thread::SpinRelease(&_wait_set_lock); @@ -2516,7 +2512,6 @@ ObjectWaiter::ObjectWaiter(JavaThread* current) { _notifier_tid = 0; _recursions = 0; TState = TS_RUN; - _notified = false; _is_wait = false; _at_reenter = false; _interrupted = false; diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 058e0317ec1..77919d99955 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -52,7 +52,6 @@ class ObjectWaiter : public CHeapObj { uint64_t _notifier_tid; int _recursions; volatile TStates TState; - volatile bool _notified; bool _is_wait; bool _at_reenter; bool _interrupted; @@ -67,9 +66,8 @@ class ObjectWaiter : public CHeapObj { uint8_t state() const { return TState; } ObjectMonitor* monitor() const { return _monitor; } bool is_wait() const { return _is_wait; } - bool notified() const { return _notified; } bool at_reenter() const { return _at_reenter; } - bool at_monitorenter() const { return !_is_wait || _at_reenter || _notified; } + bool at_monitorenter() const { return !_is_wait || TState != TS_WAIT; } oop vthread() const; void wait_reenter_begin(ObjectMonitor *mon); void wait_reenter_end(ObjectMonitor *mon); From 869112ef65ec79c8a746a7dc51fa7dbd2384f035 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 23 Oct 2025 16:24:48 +0000 Subject: [PATCH 042/736] 8026776: Broken API names in API doc Reviewed-by: aivanov, tr, ayang, prr --- .../share/classes/java/awt/GridBagConstraints.java | 4 ++-- .../image/renderable/ContextualRenderedImageFactory.java | 4 ++-- .../java/awt/image/renderable/RenderableImageOp.java | 4 ++-- .../share/classes/javax/swing/ScrollPaneLayout.java | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/GridBagConstraints.java b/src/java.desktop/share/classes/java/awt/GridBagConstraints.java index 30f8bc4bf50..0008f5ac780 100644 --- a/src/java.desktop/share/classes/java/awt/GridBagConstraints.java +++ b/src/java.desktop/share/classes/java/awt/GridBagConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -575,7 +575,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable { private static final long serialVersionUID = -1000070633030801713L; /** - * Creates a {@code GridBagConstraint} object with + * Creates a {@code GridBagConstraints} object with * all of its fields set to their default value. */ public GridBagConstraints () { diff --git a/src/java.desktop/share/classes/java/awt/image/renderable/ContextualRenderedImageFactory.java b/src/java.desktop/share/classes/java/awt/image/renderable/ContextualRenderedImageFactory.java index 94a2aa14bf5..8df3895a021 100644 --- a/src/java.desktop/share/classes/java/awt/image/renderable/ContextualRenderedImageFactory.java +++ b/src/java.desktop/share/classes/java/awt/image/renderable/ContextualRenderedImageFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ import java.awt.image.RenderedImage; * ContextualRenderedImageFactory provides an interface for the * functionality that may differ between instances of * RenderableImageOp. Thus different operations on RenderableImages - * may be performed by a single class such as RenderedImageOp through + * may be performed by a single class such as RenderableImageOp through * the use of multiple instances of ContextualRenderedImageFactory. * The name ContextualRenderedImageFactory is commonly shortened to * "CRIF." diff --git a/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageOp.java b/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageOp.java index 19bf3b39323..f2f0d458ba1 100644 --- a/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageOp.java +++ b/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ public class RenderableImageOp implements RenderableImage { /** - * Constructs a RenderedImageOp given a + * Constructs a {@code RenderableImageOp} given a * ContextualRenderedImageFactory object, and * a ParameterBlock containing RenderableImage sources and other * parameters. Any RenderedImage sources referenced by the diff --git a/src/java.desktop/share/classes/javax/swing/ScrollPaneLayout.java b/src/java.desktop/share/classes/javax/swing/ScrollPaneLayout.java index 0b8d8576f14..50cb25fe4f8 100644 --- a/src/java.desktop/share/classes/javax/swing/ScrollPaneLayout.java +++ b/src/java.desktop/share/classes/javax/swing/ScrollPaneLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,8 +38,8 @@ import java.io.Serializable; /** - * The layout manager used by JScrollPane. - * JScrollPaneLayout is + * The layout manager used by {@code JScrollPane}. + * {@code ScrollPaneLayout} is * responsible for nine components: a viewport, two scrollbars, * a row header, a column header, and four "corner" components. *

    From a0e0b2d3658e6b9f9d228b410e1621f5281074f6 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 23 Oct 2025 17:02:44 +0000 Subject: [PATCH 043/736] 8370057: Correct scale handling of BigDecimal.sqrt Reviewed-by: rgiulietti --- src/java.base/share/classes/java/math/BigDecimal.java | 6 +++--- test/jdk/java/math/BigDecimal/SquareRootTests.java | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index 199b6648cdd..14d81d30c3d 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -154,7 +154,7 @@ import jdk.internal.vm.annotation.Stable; * Subtractmax(minuend.scale(), subtrahend.scale()) * Multiplymultiplier.scale() + multiplicand.scale() * Dividedividend.scale() - divisor.scale() - * Square rootradicand.scale()/2 + * Square rootceil(radicand.scale()/2.0) * * * @@ -2113,7 +2113,7 @@ public class BigDecimal extends Number implements Comparable { * with rounding according to the context settings. * *

    The preferred scale of the returned result is equal to - * {@code this.scale()/2}. The value of the returned result is + * {@code Math.ceilDiv(this.scale(), 2)}. The value of the returned result is * always within one ulp of the exact decimal value for the * precision in question. If the rounding mode is {@link * RoundingMode#HALF_UP HALF_UP}, {@link RoundingMode#HALF_DOWN @@ -2174,7 +2174,7 @@ public class BigDecimal extends Number implements Comparable { // The code below favors relative simplicity over checking // for special cases that could run faster. - final int preferredScale = this.scale/2; + final int preferredScale = Math.ceilDiv(this.scale, 2); BigDecimal result; if (mc.roundingMode == RoundingMode.UNNECESSARY || mc.precision == 0) { // Exact result requested diff --git a/test/jdk/java/math/BigDecimal/SquareRootTests.java b/test/jdk/java/math/BigDecimal/SquareRootTests.java index 7d9fce4caa0..1a685c8483a 100644 --- a/test/jdk/java/math/BigDecimal/SquareRootTests.java +++ b/test/jdk/java/math/BigDecimal/SquareRootTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -348,7 +348,7 @@ public class SquareRootTests { for (int scale = 0; scale <= 4; scale++) { BigDecimal scaledSquare = square.setScale(scale, RoundingMode.UNNECESSARY); - int expectedScale = scale/2; + int expectedScale = Math.ceilDiv(scale, 2); for (int precision = 0; precision <= 5; precision++) { for (RoundingMode rm : RoundingMode.values()) { MathContext mc = new MathContext(precision, rm); @@ -582,7 +582,8 @@ public class SquareRootTests { // The code below favors relative simplicity over checking // for special cases that could run faster. - int preferredScale = bd.scale()/2; + int preferredScale = Math.ceilDiv(bd.scale(), 2); + BigDecimal zeroWithFinalPreferredScale = BigDecimal.valueOf(0L, preferredScale); From b0721e28591f2ee19fd5cb6581747df0b1efed48 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 23 Oct 2025 17:08:53 +0000 Subject: [PATCH 044/736] 8368982: Test sun/security/tools/jarsigner/EC.java completed and timed out Reviewed-by: rhalade --- test/jdk/sun/security/tools/jarsigner/EC.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/sun/security/tools/jarsigner/EC.java b/test/jdk/sun/security/tools/jarsigner/EC.java index 848dc8bf843..1b41c48e234 100644 --- a/test/jdk/sun/security/tools/jarsigner/EC.java +++ b/test/jdk/sun/security/tools/jarsigner/EC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 6870812 * @summary enhance security tools to use ECC algorithm * @library /test/lib + * @run main/timeout=300 EC */ import jdk.test.lib.SecurityTools; From b2e431a1cb22b78eca396ac1d97e6c272de72aa9 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Thu, 23 Oct 2025 19:06:47 +0000 Subject: [PATCH 045/736] 8369068: GenShen: Generations still aren't reconciled assertion failure Reviewed-by: ysr, kdnilsen --- .../shenandoahGenerationalHeuristics.cpp | 2 +- .../heuristics/shenandoahHeuristics.cpp | 7 +- .../share/gc/shenandoah/shenandoahAsserts.cpp | 27 ++-- .../share/gc/shenandoah/shenandoahAsserts.hpp | 14 +- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 45 ++++--- .../gc/shenandoah/shenandoahConcurrentGC.hpp | 1 - .../shenandoah/shenandoahConcurrentMark.cpp | 14 +- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 23 ++-- .../gc/shenandoah/shenandoahDegeneratedGC.hpp | 3 +- .../share/gc/shenandoah/shenandoahFullGC.cpp | 79 +++++------ .../share/gc/shenandoah/shenandoahFullGC.hpp | 2 +- .../share/gc/shenandoah/shenandoahGC.hpp | 7 + .../gc/shenandoah/shenandoahGeneration.hpp | 2 +- .../shenandoahGenerationalEvacuationTask.cpp | 8 +- .../shenandoahGenerationalEvacuationTask.hpp | 2 + .../shenandoahGenerationalFullGC.cpp | 3 +- .../shenandoah/shenandoahGenerationalHeap.cpp | 38 +++--- .../shenandoah/shenandoahGenerationalHeap.hpp | 11 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 39 ++---- .../share/gc/shenandoah/shenandoahHeap.hpp | 35 ++--- .../gc/shenandoah/shenandoahHeapRegion.cpp | 12 +- .../share/gc/shenandoah/shenandoahMark.cpp | 42 +++--- .../share/gc/shenandoah/shenandoahMark.hpp | 13 +- .../share/gc/shenandoah/shenandoahOldGC.cpp | 2 +- .../shenandoahReferenceProcessor.cpp | 26 ++-- .../gc/shenandoah/shenandoahRootVerifier.cpp | 12 +- .../gc/shenandoah/shenandoahRootVerifier.hpp | 6 +- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 11 +- .../gc/shenandoah/shenandoahVMOperations.cpp | 36 ++++- .../gc/shenandoah/shenandoahVMOperations.hpp | 86 +++++------- .../gc/shenandoah/shenandoahVerifier.cpp | 127 ++++++++---------- .../gc/shenandoah/shenandoahVerifier.hpp | 27 ++-- 32 files changed, 361 insertions(+), 401 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index c7067b2e5ab..a2cccec8423 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -127,7 +127,7 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio // Reclaim humongous regions here, and count them as the immediate garbage #ifdef ASSERT bool reg_live = region->has_live(); - bool bm_live = heap->active_generation()->complete_marking_context()->is_marked(cast_to_oop(region->bottom())); + bool bm_live = _generation->complete_marking_context()->is_marked(cast_to_oop(region->bottom())); assert(reg_live == bm_live, "Humongous liveness and marks should agree. Region live: %s; Bitmap live: %s; Region Live Words: %zu", BOOL_TO_STR(reg_live), BOOL_TO_STR(bm_live), region->get_live_data_words()); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index c8a0c3dc518..478c5696188 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -73,10 +73,11 @@ ShenandoahHeuristics::~ShenandoahHeuristics() { } void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) { - assert(collection_set->is_empty(), "Must be empty"); - ShenandoahHeap* heap = ShenandoahHeap::heap(); + assert(collection_set->is_empty(), "Must be empty"); + assert(!heap->mode()->is_generational(), "Wrong heuristic for heap mode"); + // Check all pinned regions have updated status before choosing the collection set. heap->assert_pinned_region_status(); @@ -120,7 +121,7 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec // Reclaim humongous regions here, and count them as the immediate garbage #ifdef ASSERT bool reg_live = region->has_live(); - bool bm_live = heap->gc_generation()->complete_marking_context()->is_marked(cast_to_oop(region->bottom())); + bool bm_live = heap->global_generation()->complete_marking_context()->is_marked(cast_to_oop(region->bottom())); assert(reg_live == bm_live, "Humongous liveness and marks should agree. Region live: %s; Bitmap live: %s; Region Live Words: %zu", BOOL_TO_STR(reg_live), BOOL_TO_STR(bm_live), region->get_live_data_words()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index 3d9fa10b0fc..baeaffb9c7b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -425,6 +425,16 @@ void ShenandoahAsserts::assert_marked_strong(void *interior_loc, oop obj, const } } +void ShenandoahAsserts::assert_mark_complete(HeapWord* obj, const char* file, int line) { + const ShenandoahHeap* heap = ShenandoahHeap::heap(); + const ShenandoahHeapRegion* region = heap->heap_region_containing(obj); + const ShenandoahGeneration* generation = heap->generation_for(region->affiliation()); + if (!generation->is_mark_complete()) { + ShenandoahMessageBuffer msg("Marking should be complete for object " PTR_FORMAT " in the %s generation", p2i(obj), generation->name()); + report_vm_error(file, line, msg.buffer()); + } +} + void ShenandoahAsserts::assert_in_cset(void* interior_loc, oop obj, const char* file, int line) { assert_correct(interior_loc, obj, file, line); @@ -542,23 +552,6 @@ void ShenandoahAsserts::assert_control_or_vm_thread_at_safepoint(bool at_safepoi report_vm_error(file, line, msg.buffer()); } -void ShenandoahAsserts::assert_generations_reconciled(const char* file, int line) { - if (!ShenandoahSafepoint::is_at_shenandoah_safepoint()) { - // Only shenandoah safepoint operations participate in the active/gc generation scheme - return; - } - - ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahGeneration* ggen = heap->gc_generation(); - ShenandoahGeneration* agen = heap->active_generation(); - if (agen == ggen) { - return; - } - - ShenandoahMessageBuffer msg("Active(%s) & GC(%s) Generations aren't reconciled", agen->name(), ggen->name()); - report_vm_error(file, line, msg.buffer()); -} - bool ShenandoahAsserts::extract_klass_safely(oop obj, narrowKlass& nk, const Klass*& k) { nk = 0; k = nullptr; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp index e31ef7c99aa..d0fc3e213c8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp @@ -65,6 +65,9 @@ public: static void assert_marked(void* interior_loc, oop obj, const char* file, int line); static void assert_marked_weak(void* interior_loc, oop obj, const char* file, int line); static void assert_marked_strong(void* interior_loc, oop obj, const char* file, int line); + + // Assert that marking is complete for the generation where this obj resides + static void assert_mark_complete(HeapWord* obj, const char* file, int line); static void assert_in_cset(void* interior_loc, oop obj, const char* file, int line); static void assert_not_in_cset(void* interior_loc, oop obj, const char* file, int line); static void assert_not_in_cset_loc(void* interior_loc, const char* file, int line); @@ -76,7 +79,6 @@ public: static void assert_heaplocked_or_safepoint(const char* file, int line); static void assert_control_or_vm_thread_at_safepoint(bool at_safepoint, const char* file, int line); static void assert_generational(const char* file, int line); - static void assert_generations_reconciled(const char* file, int line); // Given a possibly invalid oop, extract narrowKlass (if UCCP) and Klass* // from it safely. @@ -133,6 +135,9 @@ public: #define shenandoah_assert_marked_strong(interior_loc, obj) \ ShenandoahAsserts::assert_marked_strong(interior_loc, obj, __FILE__, __LINE__) +#define shenandoah_assert_mark_complete(obj) \ + ShenandoahAsserts::assert_mark_complete(obj, __FILE__, __LINE__) + #define shenandoah_assert_in_cset_if(interior_loc, obj, condition) \ if (condition) ShenandoahAsserts::assert_in_cset(interior_loc, obj, __FILE__, __LINE__) #define shenandoah_assert_in_cset_except(interior_loc, obj, exception) \ @@ -184,10 +189,6 @@ public: #define shenandoah_assert_generational() \ ShenandoahAsserts::assert_generational(__FILE__, __LINE__) -// Some limited sanity checking of the _gc_generation and _active_generation fields of ShenandoahHeap -#define shenandoah_assert_generations_reconciled() \ - ShenandoahAsserts::assert_generations_reconciled(__FILE__, __LINE__) - #else #define shenandoah_assert_in_heap_bounds(interior_loc, obj) #define shenandoah_assert_in_heap_bounds_or_null(interior_loc, obj) @@ -217,6 +218,8 @@ public: #define shenandoah_assert_marked_strong_except(interior_loc, obj, exception) #define shenandoah_assert_marked_strong(interior_loc, obj) +#define shenandoah_assert_mark_complete(obj) + #define shenandoah_assert_in_cset_if(interior_loc, obj, condition) #define shenandoah_assert_in_cset_except(interior_loc, obj, exception) #define shenandoah_assert_in_cset(interior_loc, obj) @@ -241,7 +244,6 @@ public: #define shenandoah_assert_control_or_vm_thread() #define shenandoah_assert_control_or_vm_thread_at_safepoint() #define shenandoah_assert_generational() -#define shenandoah_assert_generations_reconciled() #endif diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 456b9fe6d3c..9613422496a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -91,8 +91,8 @@ public: }; ShenandoahConcurrentGC::ShenandoahConcurrentGC(ShenandoahGeneration* generation, bool do_old_gc_bootstrap) : + ShenandoahGC(generation), _mark(generation), - _generation(generation), _degen_point(ShenandoahDegenPoint::_degenerated_unset), _abbreviated(false), _do_old_gc_bootstrap(do_old_gc_bootstrap) { @@ -576,7 +576,7 @@ void ShenandoahConcurrentGC::entry_promote_in_place() const { ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::promote_in_place); EventMark em("%s", "Promote in place"); - ShenandoahGenerationalHeap::heap()->promote_regions_in_place(true); + ShenandoahGenerationalHeap::heap()->promote_regions_in_place(_generation, true); } void ShenandoahConcurrentGC::entry_update_thread_roots() { @@ -706,7 +706,7 @@ void ShenandoahConcurrentGC::op_init_mark() { if (ShenandoahVerify) { ShenandoahTimingsTracker v(ShenandoahPhaseTimings::init_mark_verify); - heap->verifier()->verify_before_concmark(); + heap->verifier()->verify_before_concmark(_generation); } if (VerifyBeforeGC) { @@ -763,7 +763,7 @@ void ShenandoahConcurrentGC::op_final_mark() { assert(!heap->has_forwarded_objects(), "No forwarded objects on this path"); if (ShenandoahVerify) { - heap->verifier()->verify_roots_no_forwarded(); + heap->verifier()->verify_roots_no_forwarded(_generation); } if (!heap->cancelled_gc()) { @@ -791,7 +791,7 @@ void ShenandoahConcurrentGC::op_final_mark() { if (ShenandoahVerify) { ShenandoahTimingsTracker v(ShenandoahPhaseTimings::final_mark_verify); - heap->verifier()->verify_before_evacuation(); + heap->verifier()->verify_before_evacuation(_generation); } heap->set_evacuation_in_progress(true); @@ -806,9 +806,9 @@ void ShenandoahConcurrentGC::op_final_mark() { if (ShenandoahVerify) { ShenandoahTimingsTracker v(ShenandoahPhaseTimings::final_mark_verify); if (has_in_place_promotions(heap)) { - heap->verifier()->verify_after_concmark_with_promotions(); + heap->verifier()->verify_after_concmark_with_promotions(_generation); } else { - heap->verifier()->verify_after_concmark(); + heap->verifier()->verify_after_concmark(_generation); } } } @@ -877,18 +877,20 @@ void ShenandoahConcurrentGC::op_weak_refs() { class ShenandoahEvacUpdateCleanupOopStorageRootsClosure : public BasicOopIterateClosure { private: ShenandoahHeap* const _heap; + ShenandoahGeneration* const _generation; ShenandoahMarkingContext* const _mark_context; bool _evac_in_progress; Thread* const _thread; public: - ShenandoahEvacUpdateCleanupOopStorageRootsClosure(); + explicit ShenandoahEvacUpdateCleanupOopStorageRootsClosure(ShenandoahGeneration* generation); void do_oop(oop* p); void do_oop(narrowOop* p); }; -ShenandoahEvacUpdateCleanupOopStorageRootsClosure::ShenandoahEvacUpdateCleanupOopStorageRootsClosure() : +ShenandoahEvacUpdateCleanupOopStorageRootsClosure::ShenandoahEvacUpdateCleanupOopStorageRootsClosure(ShenandoahGeneration* generation) : _heap(ShenandoahHeap::heap()), + _generation(generation), _mark_context(ShenandoahHeap::heap()->marking_context()), _evac_in_progress(ShenandoahHeap::heap()->is_evacuation_in_progress()), _thread(Thread::current()) { @@ -898,8 +900,7 @@ void ShenandoahEvacUpdateCleanupOopStorageRootsClosure::do_oop(oop* p) { const oop obj = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(obj)) { if (!_mark_context->is_marked(obj)) { - shenandoah_assert_generations_reconciled(); - if (_heap->is_in_active_generation(obj)) { + if (_generation->contains(obj)) { // Note: The obj is dead here. Do not touch it, just clear. ShenandoahHeap::atomic_clear_oop(p, obj); } @@ -942,14 +943,16 @@ private: ShenandoahClassLoaderDataRoots _cld_roots; ShenandoahConcurrentNMethodIterator _nmethod_itr; + ShenandoahGeneration* _generation; ShenandoahPhaseTimings::Phase _phase; public: - ShenandoahConcurrentWeakRootsEvacUpdateTask(ShenandoahPhaseTimings::Phase phase) : + ShenandoahConcurrentWeakRootsEvacUpdateTask(ShenandoahGeneration* generation, ShenandoahPhaseTimings::Phase phase) : WorkerTask("Shenandoah Evacuate/Update Concurrent Weak Roots"), _vm_roots(phase), _cld_roots(phase, ShenandoahHeap::heap()->workers()->active_workers(), false /*heap iteration*/), _nmethod_itr(ShenandoahCodeRoots::table()), + _generation(generation), _phase(phase) {} ~ShenandoahConcurrentWeakRootsEvacUpdateTask() { @@ -957,14 +960,14 @@ public: _vm_roots.report_num_dead(); } - void work(uint worker_id) { + void work(uint worker_id) override { ShenandoahConcurrentWorkerSession worker_session(worker_id); ShenandoahSuspendibleThreadSetJoiner sts_join; { ShenandoahEvacOOMScope oom; // jni_roots and weak_roots are OopStorage backed roots, concurrent iteration // may race against OopStorage::release() calls. - ShenandoahEvacUpdateCleanupOopStorageRootsClosure cl; + ShenandoahEvacUpdateCleanupOopStorageRootsClosure cl(_generation); _vm_roots.oops_do(&cl, worker_id); } @@ -999,7 +1002,7 @@ void ShenandoahConcurrentGC::op_weak_roots() { // Concurrent weak root processing ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_weak_roots_work); ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_weak_roots_work); - ShenandoahConcurrentWeakRootsEvacUpdateTask task(ShenandoahPhaseTimings::conc_weak_roots_work); + ShenandoahConcurrentWeakRootsEvacUpdateTask task(_generation, ShenandoahPhaseTimings::conc_weak_roots_work); heap->workers()->run_task(&task); } @@ -1105,19 +1108,19 @@ void ShenandoahConcurrentGC::op_cleanup_early() { } void ShenandoahConcurrentGC::op_evacuate() { - ShenandoahHeap::heap()->evacuate_collection_set(true /*concurrent*/); + ShenandoahHeap::heap()->evacuate_collection_set(_generation, true /*concurrent*/); } void ShenandoahConcurrentGC::op_init_update_refs() { - ShenandoahHeap* const heap = ShenandoahHeap::heap(); if (ShenandoahVerify) { + ShenandoahHeap* const heap = ShenandoahHeap::heap(); ShenandoahTimingsTracker v(ShenandoahPhaseTimings::init_update_refs_verify); - heap->verifier()->verify_before_update_refs(); + heap->verifier()->verify_before_update_refs(_generation); } } void ShenandoahConcurrentGC::op_update_refs() { - ShenandoahHeap::heap()->update_heap_references(true /*concurrent*/); + ShenandoahHeap::heap()->update_heap_references(_generation, true /*concurrent*/); } class ShenandoahUpdateThreadHandshakeClosure : public HandshakeClosure { @@ -1163,7 +1166,7 @@ void ShenandoahConcurrentGC::op_final_update_refs() { // Has to be done before cset is clear if (ShenandoahVerify) { - heap->verifier()->verify_roots_in_to_space(); + heap->verifier()->verify_roots_in_to_space(_generation); } // If we are running in generational mode and this is an aging cycle, this will also age active @@ -1198,7 +1201,7 @@ void ShenandoahConcurrentGC::op_final_update_refs() { if (ShenandoahVerify) { ShenandoahTimingsTracker v(ShenandoahPhaseTimings::final_update_refs_verify); - heap->verifier()->verify_after_update_refs(); + heap->verifier()->verify_after_update_refs(_generation); } if (VerifyAfterGC) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp index d81c49363a2..54d43416fdb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp @@ -47,7 +47,6 @@ class ShenandoahConcurrentGC : public ShenandoahGC { protected: ShenandoahConcurrentMark _mark; - ShenandoahGeneration* const _generation; private: ShenandoahDegenPoint _degen_point; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 005d6c42f8c..7a195f64cbd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -56,18 +56,11 @@ public: } void work(uint worker_id) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahConcurrentWorkerSession worker_session(worker_id); ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_mark, ShenandoahPhaseTimings::ParallelMark, worker_id, true); ShenandoahSuspendibleThreadSetJoiner stsj; - // Do not use active_generation() : we must use the gc_generation() set by - // ShenandoahGCScope on the ControllerThread's stack; no safepoint may - // intervene to update active_generation, so we can't - // shenandoah_assert_generations_reconciled() here. - ShenandoahReferenceProcessor* rp = heap->gc_generation()->ref_processor(); - assert(rp != nullptr, "need reference processor"); StringDedup::Requests requests; - _cm->mark_loop(worker_id, _terminator, rp, GENERATION, true /*cancellable*/, + _cm->mark_loop(worker_id, _terminator, GENERATION, true /*cancellable*/, ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP, &requests); } @@ -106,9 +99,6 @@ public: ShenandoahParallelWorkerSession worker_session(worker_id); StringDedup::Requests requests; - ShenandoahReferenceProcessor* rp = heap->gc_generation()->ref_processor(); - shenandoah_assert_generations_reconciled(); - // First drain remaining SATB buffers. { ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id); @@ -122,7 +112,7 @@ public: ShenandoahSATBAndRemarkThreadsClosure tc(satb_mq_set); Threads::possibly_parallel_threads_do(true /* is_par */, &tc); } - _cm->mark_loop(worker_id, _terminator, rp, GENERATION, false /*not cancellable*/, + _cm->mark_loop(worker_id, _terminator, GENERATION, false /*not cancellable*/, _dedup_string ? ENQUEUE_DEDUP : NO_DEDUP, &requests); assert(_cm->task_queues()->is_empty(), "Should be empty"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index b918bf67b34..2b791619d2e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -46,9 +46,8 @@ #include "utilities/events.hpp" ShenandoahDegenGC::ShenandoahDegenGC(ShenandoahDegenPoint degen_point, ShenandoahGeneration* generation) : - ShenandoahGC(), + ShenandoahGC(generation), _degen_point(degen_point), - _generation(generation), _abbreviated(false) { } @@ -260,7 +259,7 @@ void ShenandoahDegenGC::op_degenerated() { } else if (has_in_place_promotions(heap)) { // We have nothing to evacuate, but there are still regions to promote in place. ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_promote_regions); - ShenandoahGenerationalHeap::heap()->promote_regions_in_place(false /* concurrent*/); + ShenandoahGenerationalHeap::heap()->promote_regions_in_place(_generation, false /* concurrent*/); } // Update collector state regardless of whether there are forwarded objects @@ -300,7 +299,7 @@ void ShenandoahDegenGC::op_degenerated() { } if (ShenandoahVerify) { - heap->verifier()->verify_after_degenerated(); + heap->verifier()->verify_after_degenerated(_generation); } if (VerifyAfterGC) { @@ -337,11 +336,11 @@ void ShenandoahDegenGC::op_finish_mark() { void ShenandoahDegenGC::op_prepare_evacuation() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); if (ShenandoahVerify) { - heap->verifier()->verify_roots_no_forwarded(); + heap->verifier()->verify_roots_no_forwarded(_generation); } // STW cleanup weak roots and unload classes - heap->parallel_cleaning(false /*full gc*/); + heap->parallel_cleaning(_generation, false /*full gc*/); // Prepare regions and collection set _generation->prepare_regions_and_collection_set(false /*concurrent*/); @@ -358,7 +357,7 @@ void ShenandoahDegenGC::op_prepare_evacuation() { if (!heap->collection_set()->is_empty()) { if (ShenandoahVerify) { - heap->verifier()->verify_before_evacuation(); + heap->verifier()->verify_before_evacuation(_generation); } heap->set_evacuation_in_progress(true); @@ -366,9 +365,9 @@ void ShenandoahDegenGC::op_prepare_evacuation() { } else { if (ShenandoahVerify) { if (has_in_place_promotions(heap)) { - heap->verifier()->verify_after_concmark_with_promotions(); + heap->verifier()->verify_after_concmark_with_promotions(_generation); } else { - heap->verifier()->verify_after_concmark(); + heap->verifier()->verify_after_concmark(_generation); } } @@ -388,7 +387,7 @@ void ShenandoahDegenGC::op_cleanup_early() { void ShenandoahDegenGC::op_evacuate() { ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_stw_evac); - ShenandoahHeap::heap()->evacuate_collection_set(false /* concurrent*/); + ShenandoahHeap::heap()->evacuate_collection_set(_generation, false /* concurrent*/); } void ShenandoahDegenGC::op_init_update_refs() { @@ -402,7 +401,7 @@ void ShenandoahDegenGC::op_update_refs() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_update_refs); // Handed over from concurrent update references phase - heap->update_heap_references(false /*concurrent*/); + heap->update_heap_references(_generation, false /*concurrent*/); heap->set_update_refs_in_progress(false); heap->set_has_forwarded_objects(false); @@ -416,7 +415,7 @@ void ShenandoahDegenGC::op_update_roots() { heap->update_heap_region_states(false /*concurrent*/); if (ShenandoahVerify) { - heap->verifier()->verify_after_update_refs(); + heap->verifier()->verify_after_update_refs(_generation); } if (VerifyAfterGC) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.hpp index 971bd67eb0d..34b9688106c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.hpp @@ -34,12 +34,11 @@ class ShenandoahDegenGC : public ShenandoahGC { friend class VM_ShenandoahDegeneratedGC; private: const ShenandoahDegenPoint _degen_point; - ShenandoahGeneration* _generation; bool _abbreviated; public: ShenandoahDegenGC(ShenandoahDegenPoint degen_point, ShenandoahGeneration* generation); - bool collect(GCCause::Cause cause); + bool collect(GCCause::Cause cause) override; private: void vmop_degenerated(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 2e486a23363..78218f5e403 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -68,6 +68,7 @@ #include "utilities/growableArray.hpp" ShenandoahFullGC::ShenandoahFullGC() : + ShenandoahGC(ShenandoahHeap::heap()->global_generation()), _gc_timer(ShenandoahHeap::heap()->gc_timer()), _preserved_marks(new PreservedMarksSet(true)) {} @@ -124,7 +125,7 @@ void ShenandoahFullGC::op_full(GCCause::Cause cause) { } // Regardless if progress was made, we record that we completed a "successful" full GC. - heap->global_generation()->heuristics()->record_success_full(); + _generation->heuristics()->record_success_full(); heap->shenandoah_policy()->record_success_full(); { @@ -141,7 +142,7 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) { } if (ShenandoahVerify) { - heap->verifier()->verify_before_fullgc(); + heap->verifier()->verify_before_fullgc(_generation); } if (VerifyBeforeGC) { @@ -194,7 +195,7 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) { } // d. Abandon reference discovery and clear all discovered references. - ShenandoahReferenceProcessor* rp = heap->global_generation()->ref_processor(); + ShenandoahReferenceProcessor* rp = _generation->ref_processor(); rp->abandon_partial_discovery(); // e. Sync pinned region status from the CP marks @@ -273,7 +274,7 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) { heap->set_full_gc_in_progress(false); if (ShenandoahVerify) { - heap->verifier()->verify_after_fullgc(); + heap->verifier()->verify_after_fullgc(_generation); } if (VerifyAfterGC) { @@ -292,19 +293,19 @@ void ShenandoahFullGC::phase1_mark_heap() { ShenandoahHeap* heap = ShenandoahHeap::heap(); - heap->global_generation()->reset_mark_bitmap(); + _generation->reset_mark_bitmap(); assert(heap->marking_context()->is_bitmap_clear(), "sanity"); - assert(!heap->global_generation()->is_mark_complete(), "sanity"); + assert(!_generation->is_mark_complete(), "sanity"); - heap->set_unload_classes(heap->global_generation()->heuristics()->can_unload_classes()); + heap->set_unload_classes(_generation->heuristics()->can_unload_classes()); - ShenandoahReferenceProcessor* rp = heap->global_generation()->ref_processor(); + ShenandoahReferenceProcessor* rp = _generation->ref_processor(); // enable ("weak") refs discovery rp->set_soft_reference_policy(true); // forcefully purge all soft references - ShenandoahSTWMark mark(heap->global_generation(), true /*full_gc*/); + ShenandoahSTWMark mark(_generation, true /*full_gc*/); mark.mark(); - heap->parallel_cleaning(true /* full_gc */); + heap->parallel_cleaning(_generation, true /* full_gc */); if (ShenandoahHeap::heap()->mode()->is_generational()) { ShenandoahGenerationalFullGC::log_live_in_old(heap); @@ -350,10 +351,12 @@ public: return _empty_regions_pos; } - void do_object(oop p) { + void do_object(oop p) override { + shenandoah_assert_mark_complete(cast_from_oop(p)); assert(_from_region != nullptr, "must set before work"); - assert(_heap->gc_generation()->complete_marking_context()->is_marked(p), "must be marked"); - assert(!_heap->gc_generation()->complete_marking_context()->allocated_after_mark_start(p), "must be truly marked"); + assert(_heap->global_generation()->is_mark_complete(), "marking must be finished"); + assert(_heap->marking_context()->is_marked(p), "must be marked"); + assert(!_heap->marking_context()->allocated_after_mark_start(p), "must be truly marked"); size_t obj_size = p->size(); if (_compact_point + obj_size > _to_region->end()) { @@ -523,12 +526,8 @@ void ShenandoahFullGC::calculate_target_humongous_objects() { } class ShenandoahEnsureHeapActiveClosure: public ShenandoahHeapRegionClosure { -private: - ShenandoahHeap* const _heap; - public: - ShenandoahEnsureHeapActiveClosure() : _heap(ShenandoahHeap::heap()) {} - void heap_region_do(ShenandoahHeapRegion* r) { + void heap_region_do(ShenandoahHeapRegion* r) override { if (r->is_trash()) { r->try_recycle_under_lock(); } @@ -760,7 +759,6 @@ void ShenandoahFullGC::phase2_calculate_target_addresses(ShenandoahHeapRegionSet class ShenandoahAdjustPointersClosure : public MetadataVisitingOopIterateClosure { private: - ShenandoahHeap* const _heap; ShenandoahMarkingContext* const _ctx; template @@ -778,8 +776,7 @@ private: public: ShenandoahAdjustPointersClosure() : - _heap(ShenandoahHeap::heap()), - _ctx(ShenandoahHeap::heap()->gc_generation()->complete_marking_context()) {} + _ctx(ShenandoahHeap::heap()->global_generation()->complete_marking_context()) {} void do_oop(oop* p) { do_oop_work(p); } void do_oop(narrowOop* p) { do_oop_work(p); } @@ -789,15 +786,12 @@ public: class ShenandoahAdjustPointersObjectClosure : public ObjectClosure { private: - ShenandoahHeap* const _heap; ShenandoahAdjustPointersClosure _cl; public: - ShenandoahAdjustPointersObjectClosure() : - _heap(ShenandoahHeap::heap()) { - } - void do_object(oop p) { - assert(_heap->gc_generation()->complete_marking_context()->is_marked(p), "must be marked"); + void do_object(oop p) override { + assert(ShenandoahHeap::heap()->global_generation()->is_mark_complete(), "marking must be complete"); + assert(ShenandoahHeap::heap()->marking_context()->is_marked(p), "must be marked"); p->oop_iterate(&_cl); } }; @@ -813,7 +807,7 @@ public: _heap(ShenandoahHeap::heap()) { } - void work(uint worker_id) { + void work(uint worker_id) override { ShenandoahParallelWorkerSession worker_session(worker_id); ShenandoahAdjustPointersObjectClosure obj_cl; ShenandoahHeapRegion* r = _regions.next(); @@ -839,7 +833,7 @@ public: _rp(rp), _preserved_marks(preserved_marks) {} - void work(uint worker_id) { + void work(uint worker_id) override { ShenandoahParallelWorkerSession worker_session(worker_id); ShenandoahAdjustPointersClosure cl; _rp->roots_do(worker_id, &cl); @@ -873,15 +867,15 @@ void ShenandoahFullGC::phase3_update_references() { class ShenandoahCompactObjectsClosure : public ObjectClosure { private: - ShenandoahHeap* const _heap; - uint const _worker_id; + uint const _worker_id; public: - ShenandoahCompactObjectsClosure(uint worker_id) : - _heap(ShenandoahHeap::heap()), _worker_id(worker_id) {} + explicit ShenandoahCompactObjectsClosure(uint worker_id) : + _worker_id(worker_id) {} - void do_object(oop p) { - assert(_heap->gc_generation()->complete_marking_context()->is_marked(p), "must be marked"); + void do_object(oop p) override { + assert(ShenandoahHeap::heap()->global_generation()->is_mark_complete(), "marking must be finished"); + assert(ShenandoahHeap::heap()->marking_context()->is_marked(p), "must be marked"); size_t size = p->size(); if (FullGCForwarding::is_forwarded(p)) { HeapWord* compact_from = cast_from_oop(p); @@ -908,7 +902,7 @@ public: _worker_slices(worker_slices) { } - void work(uint worker_id) { + void work(uint worker_id) override { ShenandoahParallelWorkerSession worker_session(worker_id); ShenandoahHeapRegionSetIterator slice(_worker_slices[worker_id]); @@ -945,7 +939,7 @@ public: _heap->free_set()->clear(); } - void heap_region_do(ShenandoahHeapRegion* r) { + void heap_region_do(ShenandoahHeapRegion* r) override { assert (!r->is_cset(), "cset regions should have been demoted already"); // Need to reset the complete-top-at-mark-start pointer here because @@ -954,7 +948,7 @@ public: // NOTE: See blurb at ShenandoahMCResetCompleteBitmapTask on why we need to skip // pinned regions. if (!r->is_pinned()) { - _heap->gc_generation()->complete_marking_context()->reset_top_at_mark_start(r); + _heap->marking_context()->reset_top_at_mark_start(r); } size_t live = r->used(); @@ -1079,7 +1073,7 @@ void ShenandoahFullGC::compact_humongous_objects() { // we need to remain able to walk pinned regions. // Since pinned region do not move and don't get compacted, we will get holes with // unreachable objects in them (which may have pointers to unloaded Klasses and thus -// cannot be iterated over using oop->size(). The only way to safely iterate over those is using +// cannot be iterated over using oop->size()). The only way to safely iterate over those is using // a valid marking bitmap and valid TAMS pointer. This class only resets marking // bitmaps for un-pinned regions, and later we only reset TAMS for unpinned regions. class ShenandoahMCResetCompleteBitmapTask : public WorkerTask { @@ -1091,11 +1085,12 @@ public: WorkerTask("Shenandoah Reset Bitmap") { } - void work(uint worker_id) { + void work(uint worker_id) override { ShenandoahParallelWorkerSession worker_session(worker_id); ShenandoahHeapRegion* region = _regions.next(); ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahMarkingContext* const ctx = heap->gc_generation()->complete_marking_context(); + ShenandoahMarkingContext* const ctx = heap->marking_context(); + assert(heap->global_generation()->is_mark_complete(), "Marking must be complete"); while (region != nullptr) { if (heap->is_bitmap_slice_committed(region) && !region->is_pinned() && region->has_live()) { ctx->clear_bitmap(region); @@ -1163,7 +1158,7 @@ ShenandoahGenerationalHeap::TransferResult ShenandoahFullGC::phase5_epilog() { heap->free_set()->finish_rebuild(young_cset_regions, old_cset_regions, num_old); // Set mark incomplete because the marking bitmaps have been reset except pinned regions. - heap->global_generation()->set_mark_incomplete(); + _generation->set_mark_incomplete(); heap->clear_cancelled_gc(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.hpp index b0b8c7bf0c5..8b8244f2ce3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.hpp @@ -68,7 +68,7 @@ private: public: ShenandoahFullGC(); ~ShenandoahFullGC(); - bool collect(GCCause::Cause cause); + bool collect(GCCause::Cause cause) override; private: // GC entries diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGC.hpp index f08bdce0a20..7182665f2e3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGC.hpp @@ -44,6 +44,8 @@ * Full GC --------> (finish) */ +class ShenandoahGeneration; + class ShenandoahGC : public StackObj { public: // Fail point from concurrent GC @@ -57,12 +59,17 @@ public: _DEGENERATED_LIMIT }; + explicit ShenandoahGC(ShenandoahGeneration* generation) : _generation(generation) {} + // Returns false if the collection was cancelled, true otherwise. virtual bool collect(GCCause::Cause cause) = 0; static const char* degen_point_to_string(ShenandoahDegenPoint point); + ShenandoahGeneration* generation() const { return _generation; } protected: static void update_roots(bool full_gc); + + ShenandoahGeneration* _generation; }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHGC_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 76e4412cfed..d2e25176c1f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -203,7 +203,7 @@ private: bool is_bitmap_clear(); // We need to track the status of marking for different generations. - bool is_mark_complete() { return _is_marking_complete.is_set(); } + bool is_mark_complete() const { return _is_marking_complete.is_set(); } virtual void set_mark_complete(); virtual void set_mark_incomplete(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp index 971129beea8..ccabdb7b9da 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp @@ -50,10 +50,12 @@ public: }; ShenandoahGenerationalEvacuationTask::ShenandoahGenerationalEvacuationTask(ShenandoahGenerationalHeap* heap, + ShenandoahGeneration* generation, ShenandoahRegionIterator* iterator, bool concurrent, bool only_promote_regions) : WorkerTask("Shenandoah Evacuation"), _heap(heap), + _generation(generation), _regions(iterator), _concurrent(concurrent), _only_promote_regions(only_promote_regions) @@ -169,13 +171,12 @@ void ShenandoahGenerationalEvacuationTask::maybe_promote_region(ShenandoahHeapRe // We identify the entirety of the region as DIRTY to force the next remembered set scan to identify the "interesting pointers" // contained herein. void ShenandoahGenerationalEvacuationTask::promote_in_place(ShenandoahHeapRegion* region) { - assert(!_heap->gc_generation()->is_old(), "Sanity check"); + assert(!_generation->is_old(), "Sanity check"); ShenandoahMarkingContext* const marking_context = _heap->young_generation()->complete_marking_context(); HeapWord* const tams = marking_context->top_at_mark_start(region); { const size_t old_garbage_threshold = (ShenandoahHeapRegion::region_size_bytes() * ShenandoahOldGarbageThreshold) / 100; - shenandoah_assert_generations_reconciled(); assert(!_heap->is_concurrent_old_mark_in_progress(), "Cannot promote in place during old marking"); assert(region->garbage_before_padded_for_promote() < old_garbage_threshold, "Region %zu has too much garbage for promotion", region->index()); assert(region->is_young(), "Only young regions can be promoted"); @@ -259,8 +260,7 @@ void ShenandoahGenerationalEvacuationTask::promote_in_place(ShenandoahHeapRegion void ShenandoahGenerationalEvacuationTask::promote_humongous(ShenandoahHeapRegion* region) { ShenandoahMarkingContext* marking_context = _heap->marking_context(); oop obj = cast_to_oop(region->bottom()); - assert(_heap->gc_generation()->is_mark_complete(), "sanity"); - shenandoah_assert_generations_reconciled(); + assert(_generation->is_mark_complete(), "sanity"); assert(region->is_young(), "Only young regions can be promoted"); assert(region->is_humongous_start(), "Should not promote humongous continuation in isolation"); assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp index 0c402d6c90a..de47184ffff 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp @@ -36,12 +36,14 @@ class ShenandoahRegionIterator; class ShenandoahGenerationalEvacuationTask : public WorkerTask { private: ShenandoahGenerationalHeap* const _heap; + ShenandoahGeneration* const _generation; ShenandoahRegionIterator* _regions; bool _concurrent; bool _only_promote_regions; public: ShenandoahGenerationalEvacuationTask(ShenandoahGenerationalHeap* sh, + ShenandoahGeneration* generation, ShenandoahRegionIterator* iterator, bool concurrent, bool only_promote_regions); void work(uint worker_id) override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index c4a7408e032..8d8091472fc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -53,8 +53,7 @@ void assert_usage_not_more_than_regions_used(ShenandoahGeneration* generation) { void ShenandoahGenerationalFullGC::prepare() { auto heap = ShenandoahGenerationalHeap::heap(); // Since we may arrive here from degenerated GC failure of either young or old, establish generation as GLOBAL. - heap->set_gc_generation(heap->global_generation()); - heap->set_active_generation(); + heap->set_active_generation(heap->global_generation()); // No need for old_gen->increase_used() as this was done when plabs were allocated. heap->reset_generation_reserves(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 34f217ada25..bc653b030a8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -178,15 +178,15 @@ bool ShenandoahGenerationalHeap::requires_barriers(stackChunkOop obj) const { return false; } -void ShenandoahGenerationalHeap::evacuate_collection_set(bool concurrent) { +void ShenandoahGenerationalHeap::evacuate_collection_set(ShenandoahGeneration* generation, bool concurrent) { ShenandoahRegionIterator regions; - ShenandoahGenerationalEvacuationTask task(this, ®ions, concurrent, false /* only promote regions */); + ShenandoahGenerationalEvacuationTask task(this, generation, ®ions, concurrent, false /* only promote regions */); workers()->run_task(&task); } -void ShenandoahGenerationalHeap::promote_regions_in_place(bool concurrent) { +void ShenandoahGenerationalHeap::promote_regions_in_place(ShenandoahGeneration* generation, bool concurrent) { ShenandoahRegionIterator regions; - ShenandoahGenerationalEvacuationTask task(this, ®ions, concurrent, true /* only promote regions */); + ShenandoahGenerationalEvacuationTask task(this, generation, ®ions, concurrent, true /* only promote regions */); workers()->run_task(&task); } @@ -757,23 +757,27 @@ void ShenandoahGenerationalHeap::coalesce_and_fill_old_regions(bool concurrent) template class ShenandoahGenerationalUpdateHeapRefsTask : public WorkerTask { private: + // For update refs, _generation will be young or global. Mixed collections use the young generation. + ShenandoahGeneration* _generation; ShenandoahGenerationalHeap* _heap; ShenandoahRegionIterator* _regions; ShenandoahRegionChunkIterator* _work_chunks; public: - explicit ShenandoahGenerationalUpdateHeapRefsTask(ShenandoahRegionIterator* regions, - ShenandoahRegionChunkIterator* work_chunks) : + ShenandoahGenerationalUpdateHeapRefsTask(ShenandoahGeneration* generation, + ShenandoahRegionIterator* regions, + ShenandoahRegionChunkIterator* work_chunks) : WorkerTask("Shenandoah Update References"), + _generation(generation), _heap(ShenandoahGenerationalHeap::heap()), _regions(regions), _work_chunks(work_chunks) { - bool old_bitmap_stable = _heap->old_generation()->is_mark_complete(); + const bool old_bitmap_stable = _heap->old_generation()->is_mark_complete(); log_debug(gc, remset)("Update refs, scan remembered set using bitmap: %s", BOOL_TO_STR(old_bitmap_stable)); } - void work(uint worker_id) { + void work(uint worker_id) override { if (CONCURRENT) { ShenandoahConcurrentWorkerSession worker_session(worker_id); ShenandoahSuspendibleThreadSetJoiner stsj; @@ -803,10 +807,8 @@ private: // If !CONCURRENT, there's no value in expanding Mutator free set ShenandoahHeapRegion* r = _regions->next(); - // We update references for global, old, and young collections. - ShenandoahGeneration* const gc_generation = _heap->gc_generation(); - shenandoah_assert_generations_reconciled(); - assert(gc_generation->is_mark_complete(), "Expected complete marking"); + // We update references for global, mixed, and young collections. + assert(_generation->is_mark_complete(), "Expected complete marking"); ShenandoahMarkingContext* const ctx = _heap->marking_context(); bool is_mixed = _heap->collection_set()->has_old_regions(); while (r != nullptr) { @@ -818,7 +820,7 @@ private: if (r->is_young()) { _heap->marked_object_oop_iterate(r, &cl, update_watermark); } else if (r->is_old()) { - if (gc_generation->is_global()) { + if (_generation->is_global()) { _heap->marked_object_oop_iterate(r, &cl, update_watermark); } @@ -847,7 +849,7 @@ private: r = _regions->next(); } - if (!gc_generation->is_global()) { + if (_generation->is_young()) { // Since this is generational and not GLOBAL, we have to process the remembered set. There's no remembered // set processing if not in generational mode or if GLOBAL mode. @@ -961,15 +963,15 @@ private: } }; -void ShenandoahGenerationalHeap::update_heap_references(bool concurrent) { +void ShenandoahGenerationalHeap::update_heap_references(ShenandoahGeneration* generation, bool concurrent) { assert(!is_full_gc_in_progress(), "Only for concurrent and degenerated GC"); const uint nworkers = workers()->active_workers(); ShenandoahRegionChunkIterator work_list(nworkers); if (concurrent) { - ShenandoahGenerationalUpdateHeapRefsTask task(&_update_refs_iterator, &work_list); + ShenandoahGenerationalUpdateHeapRefsTask task(generation, &_update_refs_iterator, &work_list); workers()->run_task(&task); } else { - ShenandoahGenerationalUpdateHeapRefsTask task(&_update_refs_iterator, &work_list); + ShenandoahGenerationalUpdateHeapRefsTask task(generation, &_update_refs_iterator, &work_list); workers()->run_task(&task); } @@ -1044,7 +1046,7 @@ public: void ShenandoahGenerationalHeap::final_update_refs_update_region_states() { ShenandoahSynchronizePinnedRegionStates pins; - ShenandoahUpdateRegionAges ages(active_generation()->complete_marking_context()); + ShenandoahUpdateRegionAges ages(marking_context()); auto cl = ShenandoahCompositeRegionClosure::of(pins, ages); parallel_heap_region_iterate(&cl); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index 6960562b31d..d3584a6f9a0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -88,8 +88,11 @@ public: oop evacuate_object(oop p, Thread* thread) override; oop try_evacuate_object(oop p, Thread* thread, ShenandoahHeapRegion* from_region, ShenandoahAffiliation target_gen); - void evacuate_collection_set(bool concurrent) override; - void promote_regions_in_place(bool concurrent); + + // In the generational mode, we will use these two functions for young, mixed, and global collections. + // For young and mixed, the generation argument will be the young generation, otherwise it will be the global generation. + void evacuate_collection_set(ShenandoahGeneration* generation, bool concurrent) override; + void promote_regions_in_place(ShenandoahGeneration* generation, bool concurrent); size_t plab_min_size() const { return _min_plab_size; } size_t plab_max_size() const { return _max_plab_size; } @@ -99,7 +102,9 @@ public: // ---------- Update References // - void update_heap_references(bool concurrent) override; + // In the generational mode, we will use this function for young, mixed, and global collections. + // For young and mixed, the generation argument will be the young generation, otherwise it will be the global generation. + void update_heap_references(ShenandoahGeneration* generation, bool concurrent) override; void final_update_refs_update_region_states() override; private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 84f5c3362ac..cb22c794d85 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -529,7 +529,6 @@ void ShenandoahHeap::initialize_heuristics() { ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : CollectedHeap(), - _gc_generation(nullptr), _active_generation(nullptr), _initial_size(0), _committed(0), @@ -1257,7 +1256,8 @@ private: ShenandoahGCStatePropagatorHandshakeClosure _propagator; }; -void ShenandoahHeap::evacuate_collection_set(bool concurrent) { +void ShenandoahHeap::evacuate_collection_set(ShenandoahGeneration* generation, bool concurrent) { + assert(generation->is_global(), "Only global generation expected here"); ShenandoahEvacuationTask task(this, _collection_set, concurrent); workers()->run_task(&task); } @@ -1659,17 +1659,11 @@ void ShenandoahHeap::print_tracing_info() const { } } -void ShenandoahHeap::set_gc_generation(ShenandoahGeneration* generation) { - shenandoah_assert_control_or_vm_thread_at_safepoint(); - _gc_generation = generation; -} - // Active generation may only be set by the VM thread at a safepoint. -void ShenandoahHeap::set_active_generation() { +void ShenandoahHeap::set_active_generation(ShenandoahGeneration* generation) { assert(Thread::current()->is_VM_thread(), "Only the VM Thread"); assert(SafepointSynchronize::is_at_safepoint(), "Only at a safepoint!"); - assert(_gc_generation != nullptr, "Will set _active_generation to nullptr"); - _active_generation = _gc_generation; + _active_generation = generation; } void ShenandoahHeap::on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation) { @@ -1678,17 +1672,14 @@ void ShenandoahHeap::on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* const GCCause::Cause current = gc_cause(); assert(current == GCCause::_no_gc, "Over-writing cause: %s, with: %s", GCCause::to_string(current), GCCause::to_string(cause)); - assert(_gc_generation == nullptr, "Over-writing _gc_generation"); set_gc_cause(cause); - set_gc_generation(generation); generation->heuristics()->record_cycle_start(); } void ShenandoahHeap::on_cycle_end(ShenandoahGeneration* generation) { assert(gc_cause() != GCCause::_no_gc, "cause wasn't set"); - assert(_gc_generation != nullptr, "_gc_generation wasn't set"); generation->heuristics()->record_cycle_end(); if (mode()->is_generational() && generation->is_global()) { @@ -1697,14 +1688,13 @@ void ShenandoahHeap::on_cycle_end(ShenandoahGeneration* generation) { old_generation()->heuristics()->record_cycle_end(); } - set_gc_generation(nullptr); set_gc_cause(GCCause::_no_gc); } void ShenandoahHeap::verify(VerifyOption vo) { if (ShenandoahSafepoint::is_at_shenandoah_safepoint()) { if (ShenandoahVerify) { - verifier()->verify_generic(vo); + verifier()->verify_generic(active_generation(), vo); } else { // TODO: Consider allocating verification bitmaps on demand, // and turn this on unconditionally. @@ -2064,14 +2054,13 @@ void ShenandoahHeap::do_class_unloading() { } } -void ShenandoahHeap::stw_weak_refs(bool full_gc) { +void ShenandoahHeap::stw_weak_refs(ShenandoahGeneration* generation, bool full_gc) { // Weak refs processing ShenandoahPhaseTimings::Phase phase = full_gc ? ShenandoahPhaseTimings::full_gc_weakrefs : ShenandoahPhaseTimings::degen_gc_weakrefs; ShenandoahTimingsTracker t(phase); ShenandoahGCWorkerPhase worker_phase(phase); - shenandoah_assert_generations_reconciled(); - gc_generation()->ref_processor()->process_references(phase, workers(), false /* concurrent */); + generation->ref_processor()->process_references(phase, workers(), false /* concurrent */); } void ShenandoahHeap::prepare_update_heap_references() { @@ -2312,13 +2301,13 @@ void ShenandoahHeap::stw_process_weak_roots(bool full_gc) { } } -void ShenandoahHeap::parallel_cleaning(bool full_gc) { +void ShenandoahHeap::parallel_cleaning(ShenandoahGeneration* generation, bool full_gc) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); assert(is_stw_gc_in_progress(), "Only for Degenerated and Full GC"); ShenandoahGCPhase phase(full_gc ? ShenandoahPhaseTimings::full_gc_purge : ShenandoahPhaseTimings::degen_gc_purge); - stw_weak_refs(full_gc); + stw_weak_refs(generation, full_gc); stw_process_weak_roots(full_gc); stw_unload_classes(full_gc); } @@ -2426,11 +2415,8 @@ void ShenandoahHeap::sync_pinned_region_status() { void ShenandoahHeap::assert_pinned_region_status() { for (size_t i = 0; i < num_regions(); i++) { ShenandoahHeapRegion* r = get_region(i); - shenandoah_assert_generations_reconciled(); - if (gc_generation()->contains(r)) { - assert((r->is_pinned() && r->pin_count() > 0) || (!r->is_pinned() && r->pin_count() == 0), - "Region %zu pinning status is inconsistent", i); - } + assert((r->is_pinned() && r->pin_count() > 0) || (!r->is_pinned() && r->pin_count() == 0), + "Region %zu pinning status is inconsistent", i); } } #endif @@ -2533,7 +2519,8 @@ private: } }; -void ShenandoahHeap::update_heap_references(bool concurrent) { +void ShenandoahHeap::update_heap_references(ShenandoahGeneration* generation, bool concurrent) { + assert(generation->is_global(), "Should only get global generation here"); assert(!is_full_gc_in_progress(), "Only for concurrent and degenerated GC"); if (concurrent) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 8bcb04e5766..d6bc17b844b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -145,17 +145,10 @@ class ShenandoahHeap : public CollectedHeap { private: ShenandoahHeapLock _lock; - // Indicates the generation whose collection is in - // progress. Mutator threads aren't allowed to read - // this field. - ShenandoahGeneration* _gc_generation; - // This is set and cleared by only the VMThread - // at each STW pause (safepoint) to the value seen in - // _gc_generation. This allows the value to be always consistently + // at each STW pause (safepoint) to the value given to the VM operation. + // This allows the value to be always consistently // seen by all mutators as well as all GC worker threads. - // In that sense, it's a stable snapshot of _gc_generation that is - // updated at each STW pause associated with a ShenandoahVMOp. ShenandoahGeneration* _active_generation; protected: @@ -167,25 +160,13 @@ public: return &_lock; } - ShenandoahGeneration* gc_generation() const { - // We don't want this field read by a mutator thread - assert(!Thread::current()->is_Java_thread(), "Not allowed"); - // value of _gc_generation field, see above - return _gc_generation; - } - ShenandoahGeneration* active_generation() const { // value of _active_generation field, see above return _active_generation; } - // Set the _gc_generation field - void set_gc_generation(ShenandoahGeneration* generation); - - // Copy the value in the _gc_generation field into - // the _active_generation field: can only be called at - // a safepoint by the VMThread. - void set_active_generation(); + // Update the _active_generation field: can only be called at a safepoint by the VMThread. + void set_active_generation(ShenandoahGeneration* generation); ShenandoahHeuristics* heuristics(); @@ -482,7 +463,7 @@ private: // GC support // Evacuation - virtual void evacuate_collection_set(bool concurrent); + virtual void evacuate_collection_set(ShenandoahGeneration* generation, bool concurrent); // Concurrent root processing void prepare_concurrent_roots(); void finish_concurrent_roots(); @@ -497,7 +478,7 @@ private: // Turn off weak roots flag, purge old satb buffers in generational mode void concurrent_final_roots(HandshakeClosure* handshake_closure = nullptr); - virtual void update_heap_references(bool concurrent); + virtual void update_heap_references(ShenandoahGeneration* generation, bool concurrent); // Final update region states void update_heap_region_states(bool concurrent); virtual void final_update_refs_update_region_states(); @@ -605,12 +586,12 @@ public: bool unload_classes() const; // Perform STW class unloading and weak root cleaning - void parallel_cleaning(bool full_gc); + void parallel_cleaning(ShenandoahGeneration* generation, bool full_gc); private: void stw_unload_classes(bool full_gc); void stw_process_weak_roots(bool full_gc); - void stw_weak_refs(bool full_gc); + void stw_weak_refs(ShenandoahGeneration* generation, bool full_gc); inline void assert_lock_for_affiliation(ShenandoahAffiliation orig_affiliation, ShenandoahAffiliation new_affiliation); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index df45a59433e..ca0f7460d54 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -315,9 +315,9 @@ void ShenandoahHeapRegion::make_trash_immediate() { // On this path, we know there are no marked objects in the region, // tell marking context about it to bypass bitmap resets. - assert(ShenandoahHeap::heap()->gc_generation()->is_mark_complete(), "Marking should be complete here."); - shenandoah_assert_generations_reconciled(); - ShenandoahHeap::heap()->marking_context()->reset_top_bitmap(this); + const ShenandoahHeap* heap = ShenandoahHeap::heap(); + assert(heap->generation_for(affiliation())->is_mark_complete(), "Marking should be complete here."); + heap->marking_context()->reset_top_bitmap(this); } void ShenandoahHeapRegion::make_empty() { @@ -461,9 +461,9 @@ bool ShenandoahHeapRegion::oop_coalesce_and_fill(bool cancellable) { ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); ShenandoahMarkingContext* marking_context = heap->marking_context(); - // Expect marking to be completed before these threads invoke this service. - assert(heap->gc_generation()->is_mark_complete(), "sanity"); - shenandoah_assert_generations_reconciled(); + // Expect marking to be completed for the old generation before we fill in unmarked objects + assert(heap->old_generation()->is_mark_complete(), "sanity"); + assert(is_old(), "Only need to coalesce and fill old regions"); // All objects above TAMS are considered live even though their mark bits will not be set. Note that young- // gen evacuations that interrupt a long-running old-gen concurrent mark may promote objects into old-gen diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 2a4149ee44d..a3c28e2c6d3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -55,10 +55,10 @@ ShenandoahMark::ShenandoahMark(ShenandoahGeneration* generation) : } template -void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahReferenceProcessor *rp, StringDedup::Requests* const req, bool update_refs) { +void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, StringDedup::Requests* const req, bool update_refs) { ShenandoahObjToScanQueue* q = get_queue(w); ShenandoahObjToScanQueue* old_q = get_old_queue(w); - + ShenandoahReferenceProcessor *rp = _generation->ref_processor(); ShenandoahHeap* const heap = ShenandoahHeap::heap(); ShenandoahLiveData* ld = heap->get_liveness_cache(w); @@ -78,22 +78,22 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe } template -void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp, - ShenandoahGenerationType generation, StringDedup::Requests* const req) { +void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, + ShenandoahGenerationType generation_type, StringDedup::Requests* const req) { bool update_refs = ShenandoahHeap::heap()->has_forwarded_objects(); - switch (generation) { + switch (generation_type) { case YOUNG: - mark_loop_prework(worker_id, terminator, rp, req, update_refs); + mark_loop_prework(worker_id, terminator, req, update_refs); break; case OLD: // Old generation collection only performs marking, it should not update references. - mark_loop_prework(worker_id, terminator, rp, req, false); + mark_loop_prework(worker_id, terminator, req, false); break; case GLOBAL: - mark_loop_prework(worker_id, terminator, rp, req, update_refs); + mark_loop_prework(worker_id, terminator, req, update_refs); break; case NON_GEN: - mark_loop_prework(worker_id, terminator, rp, req, update_refs); + mark_loop_prework(worker_id, terminator, req, update_refs); break; default: ShouldNotReachHere(); @@ -101,30 +101,30 @@ void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, Shena } } -void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp, - ShenandoahGenerationType generation, bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req) { +void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type, + bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req) { if (cancellable) { switch(dedup_mode) { case NO_DEDUP: - mark_loop(worker_id, terminator, rp, generation, req); + mark_loop(worker_id, terminator, generation_type, req); break; case ENQUEUE_DEDUP: - mark_loop(worker_id, terminator, rp, generation, req); + mark_loop(worker_id, terminator, generation_type, req); break; case ALWAYS_DEDUP: - mark_loop(worker_id, terminator, rp, generation, req); + mark_loop(worker_id, terminator, generation_type, req); break; } } else { switch(dedup_mode) { case NO_DEDUP: - mark_loop(worker_id, terminator, rp, generation, req); + mark_loop(worker_id, terminator, generation_type, req); break; case ENQUEUE_DEDUP: - mark_loop(worker_id, terminator, rp, generation, req); + mark_loop(worker_id, terminator, generation_type, req); break; case ALWAYS_DEDUP: - mark_loop(worker_id, terminator, rp, generation, req); + mark_loop(worker_id, terminator, generation_type, req); break; } } @@ -139,12 +139,8 @@ void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint w ShenandoahObjToScanQueue* q; ShenandoahMarkTask t; - // Do not use active_generation() : we must use the gc_generation() set by - // ShenandoahGCScope on the ControllerThread's stack; no safepoint may - // intervene to update active_generation, so we can't - // shenandoah_assert_generations_reconciled() here. - assert(heap->gc_generation()->type() == GENERATION, "Sanity: %d != %d", heap->gc_generation()->type(), GENERATION); - heap->gc_generation()->ref_processor()->set_mark_closure(worker_id, cl); + assert(_generation->type() == GENERATION, "Sanity: %d != %d", _generation->type(), GENERATION); + _generation->ref_processor()->set_mark_closure(worker_id, cl); /* * Process outstanding queues, if any. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index 4aef14f2c9a..2fbb106f4d7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -41,7 +41,6 @@ enum StringDedupMode { }; class ShenandoahMarkingContext; -class ShenandoahReferenceProcessor; // Base class for mark // Mark class does not maintain states. Instead, mark states are @@ -72,7 +71,7 @@ public: inline ShenandoahObjToScanQueue* get_queue(uint index) const; inline ShenandoahObjToScanQueue* get_old_queue(uint index) const; - inline ShenandoahGeneration* generation() { return _generation; }; + ShenandoahGeneration* generation() const { return _generation; }; private: // ---------- Marking loop and tasks @@ -93,7 +92,7 @@ private: void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t, StringDedup::Requests* const req); template - void mark_loop_prework(uint worker_id, TaskTerminator *terminator, ShenandoahReferenceProcessor *rp, StringDedup::Requests* const req, bool update_refs); + void mark_loop_prework(uint worker_id, TaskTerminator *terminator, StringDedup::Requests* const req, bool update_refs); template static bool in_generation(ShenandoahHeap* const heap, oop obj); @@ -109,11 +108,11 @@ private: inline void dedup_string(oop obj, StringDedup::Requests* const req); protected: template - void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp, - ShenandoahGenerationType generation, StringDedup::Requests* const req); + void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type, + StringDedup::Requests* const req); - void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahReferenceProcessor *rp, - ShenandoahGenerationType generation, bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req); + void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type, + bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARK_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp index 1724fc2849f..3e9f3a490df 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp @@ -49,7 +49,7 @@ void ShenandoahOldGC::op_final_mark() { assert(!heap->has_forwarded_objects(), "No forwarded objects on this path"); if (ShenandoahVerify) { - heap->verifier()->verify_roots_no_forwarded(); + heap->verifier()->verify_roots_no_forwarded(_old_generation); } if (!heap->cancelled_gc()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index 4ca6f2fdf49..f37329d1c44 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -329,25 +329,31 @@ bool ShenandoahReferenceProcessor::should_drop(oop reference, ReferenceType type return true; } + shenandoah_assert_mark_complete(raw_referent); ShenandoahHeap* heap = ShenandoahHeap::heap(); - // Check if the referent is still alive, in which case we should - // drop the reference. + // Check if the referent is still alive, in which case we should drop the reference. if (type == REF_PHANTOM) { - return heap->active_generation()->complete_marking_context()->is_marked(raw_referent); + return heap->marking_context()->is_marked(raw_referent); } else { - return heap->active_generation()->complete_marking_context()->is_marked_strong(raw_referent); + return heap->marking_context()->is_marked_strong(raw_referent); } } template void ShenandoahReferenceProcessor::make_inactive(oop reference, ReferenceType type) const { if (type == REF_FINAL) { +#ifdef ASSERT + auto referent = reference_referent_raw(reference); + auto heap = ShenandoahHeap::heap(); + shenandoah_assert_mark_complete(referent); + assert(reference_next(reference) == nullptr, "Already inactive"); + assert(heap->marking_context()->is_marked(referent), "only make inactive final refs with alive referents"); +#endif + // Don't clear referent. It is needed by the Finalizer thread to make the call // to finalize(). A FinalReference is instead made inactive by self-looping the // next field. An application can't call FinalReference.enqueue(), so there is // no race to worry about when setting the next field. - assert(reference_next(reference) == nullptr, "Already inactive"); - assert(ShenandoahHeap::heap()->active_generation()->complete_marking_context()->is_marked(reference_referent_raw(reference)), "only make inactive final refs with alive referents"); reference_set_next(reference, reference); } else { // Clear referent @@ -437,8 +443,12 @@ oop ShenandoahReferenceProcessor::drop(oop reference, ReferenceType type) { HeapWord* raw_referent = reference_referent_raw(reference); #ifdef ASSERT - assert(raw_referent == nullptr || ShenandoahHeap::heap()->active_generation()->complete_marking_context()->is_marked(raw_referent), - "only drop references with alive referents"); + if (raw_referent != nullptr) { + ShenandoahHeap* heap = ShenandoahHeap::heap(); + ShenandoahHeapRegion* region = heap->heap_region_containing(raw_referent); + ShenandoahMarkingContext* ctx = heap->generation_for(region->affiliation())->complete_marking_context(); + assert(ctx->is_marked(raw_referent), "only drop references with alive referents"); + } #endif // Unlink and return next in list diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp index 11ff92cd9cc..23edc780e47 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp @@ -61,7 +61,7 @@ ShenandoahGCStateResetter::~ShenandoahGCStateResetter() { assert(_heap->gc_state() == _saved_gc_state, "Should be restored"); } -void ShenandoahRootVerifier::roots_do(OopIterateClosure* oops) { +void ShenandoahRootVerifier::roots_do(OopIterateClosure* oops, ShenandoahGeneration* generation) { ShenandoahGCStateResetter resetter; shenandoah_assert_safepoint(); @@ -75,9 +75,9 @@ void ShenandoahRootVerifier::roots_do(OopIterateClosure* oops) { OopStorageSet::storage(id)->oops_do(oops); } - ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (heap->mode()->is_generational() && heap->active_generation()->is_young()) { + if (generation->is_young()) { shenandoah_assert_safepoint(); + shenandoah_assert_generational(); ShenandoahGenerationalHeap::heap()->old_generation()->card_scan()->roots_do(oops); } @@ -87,7 +87,7 @@ void ShenandoahRootVerifier::roots_do(OopIterateClosure* oops) { Threads::possibly_parallel_oops_do(true, oops, nullptr); } -void ShenandoahRootVerifier::strong_roots_do(OopIterateClosure* oops) { +void ShenandoahRootVerifier::strong_roots_do(OopIterateClosure* oops, ShenandoahGeneration* generation) { ShenandoahGCStateResetter resetter; shenandoah_assert_safepoint(); @@ -98,8 +98,8 @@ void ShenandoahRootVerifier::strong_roots_do(OopIterateClosure* oops) { OopStorageSet::storage(id)->oops_do(oops); } - ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (heap->mode()->is_generational() && heap->active_generation()->is_young()) { + if (generation->is_young()) { + shenandoah_assert_generational(); ShenandoahGenerationalHeap::heap()->old_generation()->card_scan()->roots_do(oops); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp index 405c69c4160..1f3cb400465 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp @@ -43,8 +43,10 @@ public: class ShenandoahRootVerifier : public AllStatic { public: // Used to seed ShenandoahVerifier, do not honor root type filter - static void roots_do(OopIterateClosure* cl); - static void strong_roots_do(OopIterateClosure* cl); + // The generation parameter here may be young or global. If it is young, + // then the roots will include the remembered set. + static void roots_do(OopIterateClosure* cl, ShenandoahGeneration* generation); + static void strong_roots_do(OopIterateClosure* cl, ShenandoahGeneration* generation); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHROOTVERIFIER_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 53391a3e224..117984a6d41 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -77,15 +77,13 @@ void ShenandoahSTWMark::mark() { ShenandoahCodeRoots::arm_nmethods_for_mark(); // Weak reference processing - assert(ShenandoahHeap::heap()->gc_generation() == _generation, "Marking unexpected generation"); ShenandoahReferenceProcessor* rp = _generation->ref_processor(); - shenandoah_assert_generations_reconciled(); rp->reset_thread_locals(); // Init mark, do not expect forwarded pointers in roots if (ShenandoahVerify) { assert(Thread::current()->is_VM_thread(), "Must be"); - heap->verifier()->verify_roots_no_forwarded(); + heap->verifier()->verify_roots_no_forwarded(_generation); } start_mark(); @@ -119,7 +117,6 @@ void ShenandoahSTWMark::mark() { } void ShenandoahSTWMark::mark_roots(uint worker_id) { - assert(ShenandoahHeap::heap()->gc_generation() == _generation, "Marking unexpected generation"); ShenandoahReferenceProcessor* rp = _generation->ref_processor(); auto queue = task_queues()->queue(worker_id); switch (_generation->type()) { @@ -148,14 +145,10 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { } void ShenandoahSTWMark::finish_mark(uint worker_id) { - assert(ShenandoahHeap::heap()->gc_generation() == _generation, "Marking unexpected generation"); ShenandoahPhaseTimings::Phase phase = _full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark; ShenandoahWorkerTimingsTracker timer(phase, ShenandoahPhaseTimings::ParallelMark, worker_id); - ShenandoahReferenceProcessor* rp = _generation->ref_processor(); - shenandoah_assert_generations_reconciled(); StringDedup::Requests requests; - mark_loop(worker_id, &_terminator, rp, - _generation->type(), false /* not cancellable */, + mark_loop(worker_id, &_terminator, _generation->type(), false /* not cancellable */, ShenandoahStringDedup::is_enabled() ? ALWAYS_DEDUP : NO_DEDUP, &requests); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index 0137492f06f..6b45842f781 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -50,16 +50,14 @@ void VM_ShenandoahOperation::doit_epilogue() { void VM_ShenandoahOperation::log_active_generation(const char* prefix) { ShenandoahGeneration* agen = ShenandoahHeap::heap()->active_generation(); - ShenandoahGeneration* ggen = ShenandoahHeap::heap()->gc_generation(); - log_debug(gc, heap)("%s: active_generation is %s, gc_generation is %s", prefix, - agen == nullptr ? "nullptr" : shenandoah_generation_name(agen->type()), - ggen == nullptr ? "nullptr" : shenandoah_generation_name(ggen->type())); + log_debug(gc, heap)("%s: active_generation is %s", prefix, + agen == nullptr ? "nullptr" : shenandoah_generation_name(agen->type())); } void VM_ShenandoahOperation::set_active_generation() { if (evaluate_at_safepoint()) { assert(SafepointSynchronize::is_at_safepoint(), "Error??"); - ShenandoahHeap::heap()->set_active_generation(); + ShenandoahHeap::heap()->set_active_generation(_generation); } } @@ -77,42 +75,70 @@ void VM_ShenandoahReferenceOperation::doit_epilogue() { Heap_lock->unlock(); } +VM_ShenandoahInitMark::VM_ShenandoahInitMark(ShenandoahConcurrentGC* gc) + : VM_ShenandoahOperation(gc->generation()), _gc(gc) { +} + void VM_ShenandoahInitMark::doit() { ShenandoahGCPauseMark mark(_gc_id, "Init Mark", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_init_mark(); } +VM_ShenandoahFinalMarkStartEvac::VM_ShenandoahFinalMarkStartEvac(ShenandoahConcurrentGC* gc) + : VM_ShenandoahOperation(gc->generation()), _gc(gc) { +} + void VM_ShenandoahFinalMarkStartEvac::doit() { ShenandoahGCPauseMark mark(_gc_id, "Final Mark", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_final_mark(); } +VM_ShenandoahFullGC::VM_ShenandoahFullGC(GCCause::Cause gc_cause, ShenandoahFullGC* full_gc) + : VM_ShenandoahReferenceOperation(full_gc->generation()), _gc_cause(gc_cause), _full_gc(full_gc) { +} + void VM_ShenandoahFullGC::doit() { ShenandoahGCPauseMark mark(_gc_id, "Full GC", SvcGCMarker::FULL); set_active_generation(); _full_gc->entry_full(_gc_cause); } +VM_ShenandoahDegeneratedGC::VM_ShenandoahDegeneratedGC(ShenandoahDegenGC* gc) + : VM_ShenandoahReferenceOperation(gc->generation()), _gc(gc) { +} + void VM_ShenandoahDegeneratedGC::doit() { ShenandoahGCPauseMark mark(_gc_id, "Degenerated GC", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_degenerated(); } +VM_ShenandoahInitUpdateRefs::VM_ShenandoahInitUpdateRefs(ShenandoahConcurrentGC* gc) + : VM_ShenandoahOperation(gc->generation()), _gc(gc) { +} + void VM_ShenandoahInitUpdateRefs::doit() { ShenandoahGCPauseMark mark(_gc_id, "Init Update Refs", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_init_update_refs(); } +VM_ShenandoahFinalUpdateRefs::VM_ShenandoahFinalUpdateRefs(ShenandoahConcurrentGC* gc) + : VM_ShenandoahOperation(gc->generation()), _gc(gc) { +} + void VM_ShenandoahFinalUpdateRefs::doit() { ShenandoahGCPauseMark mark(_gc_id, "Final Update Refs", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_final_update_refs(); } +VM_ShenandoahFinalRoots::VM_ShenandoahFinalRoots(ShenandoahConcurrentGC* gc) + : VM_ShenandoahOperation(gc->generation()), _gc(gc) { +} + void VM_ShenandoahFinalRoots::doit() { ShenandoahGCPauseMark mark(_gc_id, "Final Roots", SvcGCMarker::CONCURRENT); set_active_generation(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp index 291fadd1887..d565a3df22c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp @@ -46,10 +46,15 @@ class ShenandoahFullGC; class VM_ShenandoahOperation : public VM_Operation { protected: uint _gc_id; + ShenandoahGeneration* _generation; void set_active_generation(); public: - VM_ShenandoahOperation() : _gc_id(GCId::current()) {}; + explicit VM_ShenandoahOperation(ShenandoahGeneration* generation) + : _gc_id(GCId::current()) + , _generation(generation) { + } + bool skip_thread_oop_barriers() const override { return true; } void log_active_generation(const char* prefix); @@ -61,93 +66,74 @@ public: class VM_ShenandoahReferenceOperation : public VM_ShenandoahOperation { public: - VM_ShenandoahReferenceOperation() : VM_ShenandoahOperation() {}; + explicit VM_ShenandoahReferenceOperation(ShenandoahGeneration* generation) + : VM_ShenandoahOperation(generation) {}; bool doit_prologue() override; void doit_epilogue() override; }; class VM_ShenandoahInitMark: public VM_ShenandoahOperation { -private: ShenandoahConcurrentGC* const _gc; public: - VM_ShenandoahInitMark(ShenandoahConcurrentGC* gc) : - VM_ShenandoahOperation(), - _gc(gc) {}; - VM_Operation::VMOp_Type type() const { return VMOp_ShenandoahInitMark; } - const char* name() const { return "Shenandoah Init Marking"; } - virtual void doit(); + explicit VM_ShenandoahInitMark(ShenandoahConcurrentGC* gc); + VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahInitMark; } + const char* name() const override { return "Shenandoah Init Marking"; } + void doit() override; }; class VM_ShenandoahFinalMarkStartEvac: public VM_ShenandoahOperation { -private: ShenandoahConcurrentGC* const _gc; public: - VM_ShenandoahFinalMarkStartEvac(ShenandoahConcurrentGC* gc) : - VM_ShenandoahOperation(), - _gc(gc) {}; - VM_Operation::VMOp_Type type() const { return VMOp_ShenandoahFinalMarkStartEvac; } - const char* name() const { return "Shenandoah Final Mark and Start Evacuation"; } - virtual void doit(); + explicit VM_ShenandoahFinalMarkStartEvac(ShenandoahConcurrentGC* gc); + VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahFinalMarkStartEvac; } + const char* name() const override { return "Shenandoah Final Mark and Start Evacuation"; } + void doit() override; }; class VM_ShenandoahDegeneratedGC: public VM_ShenandoahReferenceOperation { -private: ShenandoahDegenGC* const _gc; public: - VM_ShenandoahDegeneratedGC(ShenandoahDegenGC* gc) : - VM_ShenandoahReferenceOperation(), - _gc(gc) {}; - - VM_Operation::VMOp_Type type() const { return VMOp_ShenandoahDegeneratedGC; } - const char* name() const { return "Shenandoah Degenerated GC"; } - virtual void doit(); + explicit VM_ShenandoahDegeneratedGC(ShenandoahDegenGC* gc); + VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahDegeneratedGC; } + const char* name() const override { return "Shenandoah Degenerated GC"; } + void doit() override; }; class VM_ShenandoahFullGC : public VM_ShenandoahReferenceOperation { -private: GCCause::Cause _gc_cause; ShenandoahFullGC* const _full_gc; public: - VM_ShenandoahFullGC(GCCause::Cause gc_cause, ShenandoahFullGC* full_gc) : - VM_ShenandoahReferenceOperation(), - _gc_cause(gc_cause), - _full_gc(full_gc) {}; - VM_Operation::VMOp_Type type() const { return VMOp_ShenandoahFullGC; } - const char* name() const { return "Shenandoah Full GC"; } - virtual void doit(); + explicit VM_ShenandoahFullGC(GCCause::Cause gc_cause, ShenandoahFullGC* full_gc); + VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahFullGC; } + const char* name() const override { return "Shenandoah Full GC"; } + void doit() override; }; class VM_ShenandoahInitUpdateRefs: public VM_ShenandoahOperation { ShenandoahConcurrentGC* const _gc; public: - VM_ShenandoahInitUpdateRefs(ShenandoahConcurrentGC* gc) : - VM_ShenandoahOperation(), - _gc(gc) {}; - VM_Operation::VMOp_Type type() const { return VMOp_ShenandoahInitUpdateRefs; } - const char* name() const { return "Shenandoah Init Update References"; } - virtual void doit(); + explicit VM_ShenandoahInitUpdateRefs(ShenandoahConcurrentGC* gc); + VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahInitUpdateRefs; } + const char* name() const override { return "Shenandoah Init Update References"; } + void doit() override; }; class VM_ShenandoahFinalUpdateRefs: public VM_ShenandoahOperation { ShenandoahConcurrentGC* const _gc; public: - VM_ShenandoahFinalUpdateRefs(ShenandoahConcurrentGC* gc) : - VM_ShenandoahOperation(), - _gc(gc) {}; - VM_Operation::VMOp_Type type() const { return VMOp_ShenandoahFinalUpdateRefs; } - const char* name() const { return "Shenandoah Final Update References"; } - virtual void doit(); + explicit VM_ShenandoahFinalUpdateRefs(ShenandoahConcurrentGC* gc); + VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahFinalUpdateRefs; } + const char* name() const override { return "Shenandoah Final Update References"; } + void doit() override; }; class VM_ShenandoahFinalRoots: public VM_ShenandoahOperation { ShenandoahConcurrentGC* const _gc; public: - VM_ShenandoahFinalRoots(ShenandoahConcurrentGC* gc) : - VM_ShenandoahOperation(), - _gc(gc) {}; - VM_Operation::VMOp_Type type() const { return VMOp_ShenandoahFinalRoots; } - const char* name() const { return "Shenandoah Final Roots"; } - virtual void doit(); + explicit VM_ShenandoahFinalRoots(ShenandoahConcurrentGC* gc); + VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahFinalRoots; } + const char* name() const override { return "Shenandoah Final Roots"; } + void doit() override; }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHVMOPERATIONS_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index c84a2a65677..fb5fbbd00a1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -70,7 +70,8 @@ private: ShenandoahGeneration* _generation; public: - ShenandoahVerifyOopClosure(ShenandoahVerifierStack* stack, MarkBitMap* map, ShenandoahLivenessData* ld, + ShenandoahVerifyOopClosure(ShenandoahGeneration* generation, ShenandoahVerifierStack* stack, + MarkBitMap* map, ShenandoahLivenessData* ld, const char* phase, ShenandoahVerifier::VerifyOptions options) : _phase(phase), _options(options), @@ -80,7 +81,7 @@ public: _ld(ld), _interior_loc(nullptr), _loc(nullptr), - _generation(nullptr) { + _generation(generation) { if (options._verify_marked == ShenandoahVerifier::_verify_marked_complete_except_references || options._verify_marked == ShenandoahVerifier::_verify_marked_complete_satb_empty || options._verify_marked == ShenandoahVerifier::_verify_marked_disable) { @@ -92,12 +93,6 @@ public: // Otherwise do all fields. _ref_mode = DO_FIELDS; } - - if (_heap->mode()->is_generational()) { - _generation = _heap->gc_generation(); - assert(_generation != nullptr, "Expected active generation in this mode"); - shenandoah_assert_generations_reconciled(); - } } ReferenceIterationMode reference_iteration_mode() override { @@ -131,11 +126,7 @@ private: } } - bool in_generation(oop obj) { - if (_generation == nullptr) { - return true; - } - + bool in_generation(oop obj) const { ShenandoahHeapRegion* region = _heap->heap_region_containing(obj); return _generation->contains(region); } @@ -197,9 +188,8 @@ private: // fallthrough for fast failure for un-live regions: case ShenandoahVerifier::_verify_liveness_conservative: check(ShenandoahAsserts::_safe_oop, obj, obj_reg->has_live() || - (obj_reg->is_old() && _heap->gc_generation()->is_young()), + (obj_reg->is_old() && _generation->is_young()), "Object must belong to region with live data"); - shenandoah_assert_generations_reconciled(); break; default: assert(false, "Unhandled liveness verification"); @@ -276,12 +266,12 @@ private: "Must be marked in incomplete bitmap"); break; case ShenandoahVerifier::_verify_marked_complete: - check(ShenandoahAsserts::_safe_all, obj, _heap->gc_generation()->complete_marking_context()->is_marked(obj), + check(ShenandoahAsserts::_safe_all, obj, _generation->complete_marking_context()->is_marked(obj), "Must be marked in complete bitmap"); break; case ShenandoahVerifier::_verify_marked_complete_except_references: case ShenandoahVerifier::_verify_marked_complete_satb_empty: - check(ShenandoahAsserts::_safe_all, obj, _heap->gc_generation()->complete_marking_context()->is_marked(obj), + check(ShenandoahAsserts::_safe_all, obj, _generation->complete_marking_context()->is_marked(obj), "Must be marked in complete bitmap, except j.l.r.Reference referents"); break; default: @@ -571,9 +561,11 @@ private: ShenandoahLivenessData* _ld; MarkBitMap* _bitmap; volatile size_t _processed; + ShenandoahGeneration* _generation; public: - ShenandoahVerifierReachableTask(MarkBitMap* bitmap, + ShenandoahVerifierReachableTask(ShenandoahGeneration* generation, + MarkBitMap* bitmap, ShenandoahLivenessData* ld, const char* label, ShenandoahVerifier::VerifyOptions options) : @@ -583,7 +575,8 @@ public: _heap(ShenandoahHeap::heap()), _ld(ld), _bitmap(bitmap), - _processed(0) {}; + _processed(0), + _generation(generation) {}; size_t processed() const { return _processed; @@ -599,20 +592,20 @@ public: // extended parallelism would buy us out. if (((ShenandoahVerifyLevel == 2) && (worker_id == 0)) || (ShenandoahVerifyLevel >= 3)) { - ShenandoahVerifyOopClosure cl(&stack, _bitmap, _ld, + ShenandoahVerifyOopClosure cl(_generation, &stack, _bitmap, _ld, ShenandoahMessageBuffer("%s, Roots", _label), _options); if (_heap->unload_classes()) { - ShenandoahRootVerifier::strong_roots_do(&cl); + ShenandoahRootVerifier::strong_roots_do(&cl, _generation); } else { - ShenandoahRootVerifier::roots_do(&cl); + ShenandoahRootVerifier::roots_do(&cl, _generation); } } size_t processed = 0; if (ShenandoahVerifyLevel >= 3) { - ShenandoahVerifyOopClosure cl(&stack, _bitmap, _ld, + ShenandoahVerifyOopClosure cl(_generation, &stack, _bitmap, _ld, ShenandoahMessageBuffer("%s, Reachable", _label), _options); while (!stack.is_empty()) { @@ -648,7 +641,8 @@ private: ShenandoahGeneration* _generation; public: - ShenandoahVerifierMarkedRegionTask(MarkBitMap* bitmap, + ShenandoahVerifierMarkedRegionTask(ShenandoahGeneration* generation, + MarkBitMap* bitmap, ShenandoahLivenessData* ld, const char* label, ShenandoahVerifier::VerifyOptions options) : @@ -660,13 +654,7 @@ public: _ld(ld), _claimed(0), _processed(0), - _generation(nullptr) { - if (_heap->mode()->is_generational()) { - _generation = _heap->gc_generation(); - assert(_generation != nullptr, "Expected active generation in this mode."); - shenandoah_assert_generations_reconciled(); - } - }; + _generation(generation) {} size_t processed() { return AtomicAccess::load(&_processed); @@ -679,7 +667,7 @@ public: } ShenandoahVerifierStack stack; - ShenandoahVerifyOopClosure cl(&stack, _bitmap, _ld, + ShenandoahVerifyOopClosure cl(_generation, &stack, _bitmap, _ld, ShenandoahMessageBuffer("%s, Marked", _label), _options); @@ -702,14 +690,14 @@ public: } } - bool in_generation(ShenandoahHeapRegion* r) { - return _generation == nullptr || _generation->contains(r); + bool in_generation(ShenandoahHeapRegion* r) const { + return _generation->contains(r); } virtual void work_humongous(ShenandoahHeapRegion *r, ShenandoahVerifierStack& stack, ShenandoahVerifyOopClosure& cl) { size_t processed = 0; HeapWord* obj = r->bottom(); - if (_heap->gc_generation()->complete_marking_context()->is_marked(cast_to_oop(obj))) { + if (_generation->complete_marking_context()->is_marked(cast_to_oop(obj))) { verify_and_follow(obj, stack, cl, &processed); } AtomicAccess::add(&_processed, processed, memory_order_relaxed); @@ -717,7 +705,7 @@ public: virtual void work_regular(ShenandoahHeapRegion *r, ShenandoahVerifierStack &stack, ShenandoahVerifyOopClosure &cl) { size_t processed = 0; - ShenandoahMarkingContext* ctx = _heap->gc_generation()->complete_marking_context(); + ShenandoahMarkingContext* ctx = _generation->complete_marking_context(); HeapWord* tams = ctx->top_at_mark_start(r); // Bitmaps, before TAMS @@ -794,7 +782,8 @@ public: } }; -void ShenandoahVerifier::verify_at_safepoint(const char* label, +void ShenandoahVerifier::verify_at_safepoint(ShenandoahGeneration* generation, + const char* label, VerifyRememberedSet remembered, VerifyForwarded forwarded, VerifyMarked marked, @@ -896,16 +885,7 @@ void ShenandoahVerifier::verify_at_safepoint(const char* label, log_debug(gc)("Safepoint verification finished heap usage verification"); - ShenandoahGeneration* generation; if (_heap->mode()->is_generational()) { - generation = _heap->gc_generation(); - guarantee(generation != nullptr, "Need to know which generation to verify."); - shenandoah_assert_generations_reconciled(); - } else { - generation = nullptr; - } - - if (generation != nullptr) { ShenandoahHeapLocker lock(_heap->lock()); switch (remembered) { @@ -952,11 +932,7 @@ void ShenandoahVerifier::verify_at_safepoint(const char* label, // Internal heap region checks if (ShenandoahVerifyLevel >= 1) { ShenandoahVerifyHeapRegionClosure cl(label, regions); - if (generation != nullptr) { - generation->heap_region_iterate(&cl); - } else { - _heap->heap_region_iterate(&cl); - } + generation->heap_region_iterate(&cl); } log_debug(gc)("Safepoint verification finished heap region closure verification"); @@ -980,7 +956,7 @@ void ShenandoahVerifier::verify_at_safepoint(const char* label, // This verifies what application can see, since it only cares about reachable objects. size_t count_reachable = 0; if (ShenandoahVerifyLevel >= 2) { - ShenandoahVerifierReachableTask task(_verification_bit_map, ld, label, options); + ShenandoahVerifierReachableTask task(generation, _verification_bit_map, ld, label, options); _heap->workers()->run_task(&task); count_reachable = task.processed(); } @@ -999,8 +975,8 @@ void ShenandoahVerifier::verify_at_safepoint(const char* label, (marked == _verify_marked_complete || marked == _verify_marked_complete_except_references || marked == _verify_marked_complete_satb_empty)) { - guarantee(_heap->gc_generation()->is_mark_complete(), "Marking context should be complete"); - ShenandoahVerifierMarkedRegionTask task(_verification_bit_map, ld, label, options); + guarantee(generation->is_mark_complete(), "Marking context should be complete"); + ShenandoahVerifierMarkedRegionTask task(generation, _verification_bit_map, ld, label, options); _heap->workers()->run_task(&task); count_marked = task.processed(); } else { @@ -1015,7 +991,7 @@ void ShenandoahVerifier::verify_at_safepoint(const char* label, if (ShenandoahVerifyLevel >= 4 && marked == _verify_marked_complete && liveness == _verify_liveness_complete) { for (size_t i = 0; i < _heap->num_regions(); i++) { ShenandoahHeapRegion* r = _heap->get_region(i); - if (generation != nullptr && !generation->contains(r)) { + if (!generation->contains(r)) { continue; } @@ -1042,16 +1018,15 @@ void ShenandoahVerifier::verify_at_safepoint(const char* label, } log_debug(gc)("Safepoint verification finished accumulation of liveness data"); - - log_info(gc)("Verify %s, Level %zd (%zu reachable, %zu marked)", label, ShenandoahVerifyLevel, count_reachable, count_marked); FREE_C_HEAP_ARRAY(ShenandoahLivenessData, ld); } -void ShenandoahVerifier::verify_generic(VerifyOption vo) { +void ShenandoahVerifier::verify_generic(ShenandoahGeneration* generation, VerifyOption vo) { verify_at_safepoint( + generation, "Generic Verification", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_allow, // conservatively allow forwarded @@ -1064,7 +1039,7 @@ void ShenandoahVerifier::verify_generic(VerifyOption vo) { ); } -void ShenandoahVerifier::verify_before_concmark() { +void ShenandoahVerifier::verify_before_concmark(ShenandoahGeneration* generation) { VerifyRememberedSet verify_remembered_set = _verify_remembered_before_marking; if (_heap->mode()->is_generational() && !_heap->old_generation()->is_mark_complete()) { @@ -1072,6 +1047,7 @@ void ShenandoahVerifier::verify_before_concmark() { verify_remembered_set = _verify_remembered_disable; } verify_at_safepoint( + generation, "Before Mark", verify_remembered_set, // verify read-only remembered set from bottom() to top() @@ -1085,8 +1061,9 @@ void ShenandoahVerifier::verify_before_concmark() { ); } -void ShenandoahVerifier::verify_after_concmark() { +void ShenandoahVerifier::verify_after_concmark(ShenandoahGeneration* generation) { verify_at_safepoint( + generation, "After Mark", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_none, // no forwarded references @@ -1099,8 +1076,9 @@ void ShenandoahVerifier::verify_after_concmark() { ); } -void ShenandoahVerifier::verify_after_concmark_with_promotions() { +void ShenandoahVerifier::verify_after_concmark_with_promotions(ShenandoahGeneration* generation) { verify_at_safepoint( + generation, "After Mark", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_none, // no forwarded references @@ -1114,8 +1092,9 @@ void ShenandoahVerifier::verify_after_concmark_with_promotions() { ); } -void ShenandoahVerifier::verify_before_evacuation() { +void ShenandoahVerifier::verify_before_evacuation(ShenandoahGeneration* generation) { verify_at_safepoint( + generation, "Before Evacuation", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_none, // no forwarded references @@ -1129,13 +1108,14 @@ void ShenandoahVerifier::verify_before_evacuation() { ); } -void ShenandoahVerifier::verify_before_update_refs() { +void ShenandoahVerifier::verify_before_update_refs(ShenandoahGeneration* generation) { VerifyRememberedSet verify_remembered_set = _verify_remembered_before_updating_references; if (_heap->mode()->is_generational() && !_heap->old_generation()->is_mark_complete()) { verify_remembered_set = _verify_remembered_disable; } verify_at_safepoint( + generation, "Before Updating References", verify_remembered_set, // verify read-write remembered set _verify_forwarded_allow, // forwarded references allowed @@ -1149,8 +1129,9 @@ void ShenandoahVerifier::verify_before_update_refs() { } // We have not yet cleanup (reclaimed) the collection set -void ShenandoahVerifier::verify_after_update_refs() { +void ShenandoahVerifier::verify_after_update_refs(ShenandoahGeneration* generation) { verify_at_safepoint( + generation, "After Updating References", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_none, // no forwarded references @@ -1163,8 +1144,9 @@ void ShenandoahVerifier::verify_after_update_refs() { ); } -void ShenandoahVerifier::verify_after_degenerated() { +void ShenandoahVerifier::verify_after_degenerated(ShenandoahGeneration* generation) { verify_at_safepoint( + generation, "After Degenerated GC", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_none, // all objects are non-forwarded @@ -1177,8 +1159,9 @@ void ShenandoahVerifier::verify_after_degenerated() { ); } -void ShenandoahVerifier::verify_before_fullgc() { +void ShenandoahVerifier::verify_before_fullgc(ShenandoahGeneration* generation) { verify_at_safepoint( + generation, "Before Full GC", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_allow, // can have forwarded objects @@ -1191,8 +1174,9 @@ void ShenandoahVerifier::verify_before_fullgc() { ); } -void ShenandoahVerifier::verify_after_fullgc() { +void ShenandoahVerifier::verify_after_fullgc(ShenandoahGeneration* generation) { verify_at_safepoint( + generation, "After Full GC", _verify_remembered_after_full_gc, // verify read-write remembered set _verify_forwarded_none, // all objects are non-forwarded @@ -1257,14 +1241,14 @@ public: void do_oop(oop* p) override { do_oop_work(p); } }; -void ShenandoahVerifier::verify_roots_in_to_space() { +void ShenandoahVerifier::verify_roots_in_to_space(ShenandoahGeneration* generation) { ShenandoahVerifyInToSpaceClosure cl; - ShenandoahRootVerifier::roots_do(&cl); + ShenandoahRootVerifier::roots_do(&cl, generation); } -void ShenandoahVerifier::verify_roots_no_forwarded() { +void ShenandoahVerifier::verify_roots_no_forwarded(ShenandoahGeneration* generation) { ShenandoahVerifyNoForwarded cl; - ShenandoahRootVerifier::roots_do(&cl); + ShenandoahRootVerifier::roots_do(&cl, generation); } template @@ -1300,7 +1284,6 @@ public: template void ShenandoahVerifier::help_verify_region_rem_set(Scanner* scanner, ShenandoahHeapRegion* r, HeapWord* registration_watermark, const char* message) { - shenandoah_assert_generations_reconciled(); ShenandoahOldGeneration* old_gen = _heap->old_generation(); assert(old_gen->is_mark_complete() || old_gen->is_parsable(), "Sanity"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp index aba6379e022..e49990fdc62 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp @@ -196,7 +196,8 @@ public: }; private: - void verify_at_safepoint(const char* label, + void verify_at_safepoint(ShenandoahGeneration* generation, + const char* label, VerifyRememberedSet remembered, VerifyForwarded forwarded, VerifyMarked marked, @@ -210,20 +211,20 @@ public: ShenandoahVerifier(ShenandoahHeap* heap, MarkBitMap* verification_bitmap) : _heap(heap), _verification_bit_map(verification_bitmap) {}; - void verify_before_concmark(); - void verify_after_concmark(); - void verify_after_concmark_with_promotions(); - void verify_before_evacuation(); - void verify_before_update_refs(); - void verify_after_update_refs(); - void verify_before_fullgc(); - void verify_after_fullgc(); - void verify_after_degenerated(); - void verify_generic(VerifyOption option); + void verify_before_concmark(ShenandoahGeneration* generation); + void verify_after_concmark(ShenandoahGeneration* generation); + void verify_after_concmark_with_promotions(ShenandoahGeneration* generation); + void verify_before_evacuation(ShenandoahGeneration* generation); + void verify_before_update_refs(ShenandoahGeneration* generation); + void verify_after_update_refs(ShenandoahGeneration* generation); + void verify_before_fullgc(ShenandoahGeneration* generation); + void verify_after_fullgc(ShenandoahGeneration* generation); + void verify_after_degenerated(ShenandoahGeneration* generation); + void verify_generic(ShenandoahGeneration* generation, VerifyOption option); // Roots should only contain to-space oops - void verify_roots_in_to_space(); - void verify_roots_no_forwarded(); + void verify_roots_in_to_space(ShenandoahGeneration* generation); + void verify_roots_no_forwarded(ShenandoahGeneration* generation); // Check that generation usages are accurate before rebuilding free set void verify_before_rebuilding_free_set(); From 62f11cd4070f21ad82eebbb5319bdbbf4e13f9cf Mon Sep 17 00:00:00 2001 From: Shawn M Emery Date: Thu, 23 Oct 2025 19:36:49 +0000 Subject: [PATCH 046/736] 8326609: New AES implementation with updates specified in FIPS 197 Reviewed-by: valeriep --- src/hotspot/share/classfile/vmIntrinsics.hpp | 4 +- src/hotspot/share/opto/library_call.cpp | 20 +- .../com/sun/crypto/provider/AESCipher.java | 8 +- .../com/sun/crypto/provider/AESCrypt.java | 1437 ----------------- .../sun/crypto/provider/AESKeyGenerator.java | 4 +- .../com/sun/crypto/provider/AESKeyWrap.java | 4 +- .../sun/crypto/provider/AESKeyWrapPadded.java | 4 +- .../com/sun/crypto/provider/AES_Crypt.java | 1392 ++++++++++++++++ .../classes/com/sun/crypto/provider/GCTR.java | 4 +- .../crypto/provider/GaloisCounterMode.java | 12 +- .../sun/crypto/provider/KeyWrapCipher.java | 4 +- .../com/sun/crypto/provider/PBES2Core.java | 4 +- .../sun/crypto/provider/SymmetricCipher.java | 4 +- src/java.base/share/legal/aes.md | 36 - .../compiler/codegen/aes/TestAESMain.java | 4 +- .../compiler/cpuflags/AESIntrinsicsBase.java | 4 +- .../hotspot/test/TestHotSpotJVMCIRuntime.java | 4 +- .../bench/javax/crypto/AESDecrypt.java | 84 + 18 files changed, 1518 insertions(+), 1515 deletions(-) delete mode 100644 src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java create mode 100644 src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java delete mode 100644 src/java.base/share/legal/aes.md create mode 100644 test/micro/org/openjdk/bench/javax/crypto/AESDecrypt.java diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index c9c5c925f86..0895418ef84 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -467,8 +467,8 @@ class methodHandle; do_intrinsic(_Reference_clear0, java_lang_ref_Reference, clear0_name, void_method_signature, F_RN) \ do_intrinsic(_PhantomReference_clear0, java_lang_ref_PhantomReference, clear0_name, void_method_signature, F_RN) \ \ - /* support for com.sun.crypto.provider.AESCrypt and some of its callers */ \ - do_class(com_sun_crypto_provider_aescrypt, "com/sun/crypto/provider/AESCrypt") \ + /* support for com.sun.crypto.provider.AES_Crypt and some of its callers */ \ + do_class(com_sun_crypto_provider_aescrypt, "com/sun/crypto/provider/AES_Crypt") \ do_intrinsic(_aescrypt_encryptBlock, com_sun_crypto_provider_aescrypt, encryptBlock_name, byteArray_int_byteArray_int_signature, F_R) \ do_intrinsic(_aescrypt_decryptBlock, com_sun_crypto_provider_aescrypt, decryptBlock_name, byteArray_int_byteArray_int_signature, F_R) \ do_name( encryptBlock_name, "implEncryptBlock") \ diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index ee3a3d3ba47..bd8a550b9ab 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -7273,7 +7273,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { const TypeInstPtr* tinst = _gvn.type(cipherBlockChaining_object)->isa_instptr(); assert(tinst != nullptr, "CBC obj is null"); assert(tinst->is_loaded(), "CBC obj is not loaded"); - ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AES_Crypt")); assert(klass_AESCrypt->is_loaded(), "predicate checks that this class is loaded"); ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); @@ -7359,7 +7359,7 @@ bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) { const TypeInstPtr* tinst = _gvn.type(electronicCodeBook_object)->isa_instptr(); assert(tinst != nullptr, "ECB obj is null"); assert(tinst->is_loaded(), "ECB obj is not loaded"); - ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AES_Crypt")); assert(klass_AESCrypt->is_loaded(), "predicate checks that this class is loaded"); ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); @@ -7429,7 +7429,7 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { const TypeInstPtr* tinst = _gvn.type(counterMode_object)->isa_instptr(); assert(tinst != nullptr, "CTR obj is null"); assert(tinst->is_loaded(), "CTR obj is not loaded"); - ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AES_Crypt")); assert(klass_AESCrypt->is_loaded(), "predicate checks that this class is loaded"); ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt); @@ -7469,7 +7469,7 @@ Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) // However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption. // The ppc64 and riscv64 stubs of encryption and decryption use the same round keys (sessionK[0]). Node* objSessionK = load_field_from_object(aescrypt_object, "sessionK", "[[I"); - assert (objSessionK != nullptr, "wrong version of com.sun.crypto.provider.AESCrypt"); + assert (objSessionK != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt"); if (objSessionK == nullptr) { return (Node *) nullptr; } @@ -7477,7 +7477,7 @@ Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) #else Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I"); #endif // PPC64 - assert (objAESCryptKey != nullptr, "wrong version of com.sun.crypto.provider.AESCrypt"); + assert (objAESCryptKey != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt"); if (objAESCryptKey == nullptr) return (Node *) nullptr; // now have the array, need to get the start address of the K array @@ -7512,7 +7512,7 @@ Node* LibraryCallKit::inline_cipherBlockChaining_AESCrypt_predicate(bool decrypt assert(tinst->is_loaded(), "CBCobj is not loaded"); // we want to do an instanceof comparison against the AESCrypt class - ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AES_Crypt")); if (!klass_AESCrypt->is_loaded()) { // if AESCrypt is not even loaded, we never take the intrinsic fast path Node* ctrl = control(); @@ -7575,7 +7575,7 @@ Node* LibraryCallKit::inline_electronicCodeBook_AESCrypt_predicate(bool decrypti assert(tinst->is_loaded(), "ECBobj is not loaded"); // we want to do an instanceof comparison against the AESCrypt class - ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AES_Crypt")); if (!klass_AESCrypt->is_loaded()) { // if AESCrypt is not even loaded, we never take the intrinsic fast path Node* ctrl = control(); @@ -7635,7 +7635,7 @@ Node* LibraryCallKit::inline_counterMode_AESCrypt_predicate() { assert(tinst->is_loaded(), "CTRobj is not loaded"); // we want to do an instanceof comparison against the AESCrypt class - ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AES_Crypt")); if (!klass_AESCrypt->is_loaded()) { // if AESCrypt is not even loaded, we never take the intrinsic fast path Node* ctrl = control(); @@ -8608,7 +8608,7 @@ bool LibraryCallKit::inline_galoisCounterMode_AESCrypt() { const TypeInstPtr* tinst = _gvn.type(gctr_object)->isa_instptr(); assert(tinst != nullptr, "GCTR obj is null"); assert(tinst->is_loaded(), "GCTR obj is not loaded"); - ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AES_Crypt")); assert(klass_AESCrypt->is_loaded(), "predicate checks that this class is loaded"); ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt); @@ -8662,7 +8662,7 @@ Node* LibraryCallKit::inline_galoisCounterMode_AESCrypt_predicate() { assert(tinst->is_loaded(), "GCTR obj is not loaded"); // we want to do an instanceof comparison against the AESCrypt class - ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + ciKlass* klass_AESCrypt = tinst->instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AES_Crypt")); if (!klass_AESCrypt->is_loaded()) { // if AESCrypt is not even loaded, we never take the intrinsic fast path Node* ctrl = control(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java index 12359cba7d1..329f367717a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ import java.util.Arrays; * * @author Valerie Peng * - * @see AESCrypt + * @see AES_Crypt * @see CipherBlockChaining * @see ElectronicCodeBook * @see CipherFeedback @@ -174,7 +174,7 @@ class AESCipher extends CipherSpi { * PKCS5Padding. */ protected AESCipher(int keySize) { - core = new CipherCore(new AESCrypt(), AESConstants.AES_BLOCK_SIZE); + core = new CipherCore(new AES_Crypt(), AESConstants.AES_BLOCK_SIZE); fixedKeySize = keySize; } @@ -504,7 +504,7 @@ class AESCipher extends CipherSpi { protected int engineGetKeySize(Key key) throws InvalidKeyException { byte[] encoded = key.getEncoded(); Arrays.fill(encoded, (byte)0); - if (!AESCrypt.isKeySizeValid(encoded.length)) { + if (!AES_Crypt.isKeySizeValid(encoded.length)) { throw new InvalidKeyException("Invalid AES key length: " + encoded.length + " bytes"); } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java b/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java deleted file mode 100644 index 9bbc8c16764..00000000000 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java +++ /dev/null @@ -1,1437 +0,0 @@ -/* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. - * 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. - */ - -/* $Id: Rijndael.java,v 1.6 2000/02/10 01:31:41 gelderen Exp $ - * - * Copyright (C) 1995-2000 The Cryptix Foundation Limited. - * All rights reserved. - * - * Use, modification, copying and distribution of this softwareas is subject - * the terms and conditions of the Cryptix General Licence. You should have - * received a copy of the Cryptix General Licence along with this library; - * if not, you can download a copy from http://www.cryptix.org/ . - */ - -package com.sun.crypto.provider; - -import java.security.InvalidKeyException; -import java.security.MessageDigest; -import java.util.Arrays; - -import jdk.internal.vm.annotation.IntrinsicCandidate; - -/** - * Rijndael --pronounced Reindaal-- is a symmetric cipher with a 128-bit - * block size and variable key-size (128-, 192- and 256-bit). - *

    - * Rijndael was designed by Vincent - * Rijmen and Joan Daemen. - */ -final class AESCrypt extends SymmetricCipher implements AESConstants { - // - // Pre-computed tables, which are copied or derived from FIPS 197. - // - - // the pre-computed substitution table (S-box), 256 bytes - private static final byte[] S = { - (byte)0x63, (byte)0x7C, (byte)0x77, (byte)0x7B, - (byte)0xF2, (byte)0x6B, (byte)0x6F, (byte)0xC5, - (byte)0x30, (byte)0x01, (byte)0x67, (byte)0x2B, - (byte)0xFE, (byte)0xD7, (byte)0xAB, (byte)0x76, - (byte)0xCA, (byte)0x82, (byte)0xC9, (byte)0x7D, - (byte)0xFA, (byte)0x59, (byte)0x47, (byte)0xF0, - (byte)0xAD, (byte)0xD4, (byte)0xA2, (byte)0xAF, - (byte)0x9C, (byte)0xA4, (byte)0x72, (byte)0xC0, - (byte)0xB7, (byte)0xFD, (byte)0x93, (byte)0x26, - (byte)0x36, (byte)0x3F, (byte)0xF7, (byte)0xCC, - (byte)0x34, (byte)0xA5, (byte)0xE5, (byte)0xF1, - (byte)0x71, (byte)0xD8, (byte)0x31, (byte)0x15, - (byte)0x04, (byte)0xC7, (byte)0x23, (byte)0xC3, - (byte)0x18, (byte)0x96, (byte)0x05, (byte)0x9A, - (byte)0x07, (byte)0x12, (byte)0x80, (byte)0xE2, - (byte)0xEB, (byte)0x27, (byte)0xB2, (byte)0x75, - (byte)0x09, (byte)0x83, (byte)0x2C, (byte)0x1A, - (byte)0x1B, (byte)0x6E, (byte)0x5A, (byte)0xA0, - (byte)0x52, (byte)0x3B, (byte)0xD6, (byte)0xB3, - (byte)0x29, (byte)0xE3, (byte)0x2F, (byte)0x84, - (byte)0x53, (byte)0xD1, (byte)0x00, (byte)0xED, - (byte)0x20, (byte)0xFC, (byte)0xB1, (byte)0x5B, - (byte)0x6A, (byte)0xCB, (byte)0xBE, (byte)0x39, - (byte)0x4A, (byte)0x4C, (byte)0x58, (byte)0xCF, - (byte)0xD0, (byte)0xEF, (byte)0xAA, (byte)0xFB, - (byte)0x43, (byte)0x4D, (byte)0x33, (byte)0x85, - (byte)0x45, (byte)0xF9, (byte)0x02, (byte)0x7F, - (byte)0x50, (byte)0x3C, (byte)0x9F, (byte)0xA8, - (byte)0x51, (byte)0xA3, (byte)0x40, (byte)0x8F, - (byte)0x92, (byte)0x9D, (byte)0x38, (byte)0xF5, - (byte)0xBC, (byte)0xB6, (byte)0xDA, (byte)0x21, - (byte)0x10, (byte)0xFF, (byte)0xF3, (byte)0xD2, - (byte)0xCD, (byte)0x0C, (byte)0x13, (byte)0xEC, - (byte)0x5F, (byte)0x97, (byte)0x44, (byte)0x17, - (byte)0xC4, (byte)0xA7, (byte)0x7E, (byte)0x3D, - (byte)0x64, (byte)0x5D, (byte)0x19, (byte)0x73, - (byte)0x60, (byte)0x81, (byte)0x4F, (byte)0xDC, - (byte)0x22, (byte)0x2A, (byte)0x90, (byte)0x88, - (byte)0x46, (byte)0xEE, (byte)0xB8, (byte)0x14, - (byte)0xDE, (byte)0x5E, (byte)0x0B, (byte)0xDB, - (byte)0xE0, (byte)0x32, (byte)0x3A, (byte)0x0A, - (byte)0x49, (byte)0x06, (byte)0x24, (byte)0x5C, - (byte)0xC2, (byte)0xD3, (byte)0xAC, (byte)0x62, - (byte)0x91, (byte)0x95, (byte)0xE4, (byte)0x79, - (byte)0xE7, (byte)0xC8, (byte)0x37, (byte)0x6D, - (byte)0x8D, (byte)0xD5, (byte)0x4E, (byte)0xA9, - (byte)0x6C, (byte)0x56, (byte)0xF4, (byte)0xEA, - (byte)0x65, (byte)0x7A, (byte)0xAE, (byte)0x08, - (byte)0xBA, (byte)0x78, (byte)0x25, (byte)0x2E, - (byte)0x1C, (byte)0xA6, (byte)0xB4, (byte)0xC6, - (byte)0xE8, (byte)0xDD, (byte)0x74, (byte)0x1F, - (byte)0x4B, (byte)0xBD, (byte)0x8B, (byte)0x8A, - (byte)0x70, (byte)0x3E, (byte)0xB5, (byte)0x66, - (byte)0x48, (byte)0x03, (byte)0xF6, (byte)0x0E, - (byte)0x61, (byte)0x35, (byte)0x57, (byte)0xB9, - (byte)0x86, (byte)0xC1, (byte)0x1D, (byte)0x9E, - (byte)0xE1, (byte)0xF8, (byte)0x98, (byte)0x11, - (byte)0x69, (byte)0xD9, (byte)0x8E, (byte)0x94, - (byte)0x9B, (byte)0x1E, (byte)0x87, (byte)0xE9, - (byte)0xCE, (byte)0x55, (byte)0x28, (byte)0xDF, - (byte)0x8C, (byte)0xA1, (byte)0x89, (byte)0x0D, - (byte)0xBF, (byte)0xE6, (byte)0x42, (byte)0x68, - (byte)0x41, (byte)0x99, (byte)0x2D, (byte)0x0F, - (byte)0xB0, (byte)0x54, (byte)0xBB, (byte)0x16, - }; - - // the pre-computed substitution table (inverse S-box), 256 bytes - private static final byte[] Si = { - (byte)0x52, (byte)0x09, (byte)0x6A, (byte)0xD5, - (byte)0x30, (byte)0x36, (byte)0xA5, (byte)0x38, - (byte)0xBF, (byte)0x40, (byte)0xA3, (byte)0x9E, - (byte)0x81, (byte)0xF3, (byte)0xD7, (byte)0xFB, - (byte)0x7C, (byte)0xE3, (byte)0x39, (byte)0x82, - (byte)0x9B, (byte)0x2F, (byte)0xFF, (byte)0x87, - (byte)0x34, (byte)0x8E, (byte)0x43, (byte)0x44, - (byte)0xC4, (byte)0xDE, (byte)0xE9, (byte)0xCB, - (byte)0x54, (byte)0x7B, (byte)0x94, (byte)0x32, - (byte)0xA6, (byte)0xC2, (byte)0x23, (byte)0x3D, - (byte)0xEE, (byte)0x4C, (byte)0x95, (byte)0x0B, - (byte)0x42, (byte)0xFA, (byte)0xC3, (byte)0x4E, - (byte)0x08, (byte)0x2E, (byte)0xA1, (byte)0x66, - (byte)0x28, (byte)0xD9, (byte)0x24, (byte)0xB2, - (byte)0x76, (byte)0x5B, (byte)0xA2, (byte)0x49, - (byte)0x6D, (byte)0x8B, (byte)0xD1, (byte)0x25, - (byte)0x72, (byte)0xF8, (byte)0xF6, (byte)0x64, - (byte)0x86, (byte)0x68, (byte)0x98, (byte)0x16, - (byte)0xD4, (byte)0xA4, (byte)0x5C, (byte)0xCC, - (byte)0x5D, (byte)0x65, (byte)0xB6, (byte)0x92, - (byte)0x6C, (byte)0x70, (byte)0x48, (byte)0x50, - (byte)0xFD, (byte)0xED, (byte)0xB9, (byte)0xDA, - (byte)0x5E, (byte)0x15, (byte)0x46, (byte)0x57, - (byte)0xA7, (byte)0x8D, (byte)0x9D, (byte)0x84, - (byte)0x90, (byte)0xD8, (byte)0xAB, (byte)0x00, - (byte)0x8C, (byte)0xBC, (byte)0xD3, (byte)0x0A, - (byte)0xF7, (byte)0xE4, (byte)0x58, (byte)0x05, - (byte)0xB8, (byte)0xB3, (byte)0x45, (byte)0x06, - (byte)0xD0, (byte)0x2C, (byte)0x1E, (byte)0x8F, - (byte)0xCA, (byte)0x3F, (byte)0x0F, (byte)0x02, - (byte)0xC1, (byte)0xAF, (byte)0xBD, (byte)0x03, - (byte)0x01, (byte)0x13, (byte)0x8A, (byte)0x6B, - (byte)0x3A, (byte)0x91, (byte)0x11, (byte)0x41, - (byte)0x4F, (byte)0x67, (byte)0xDC, (byte)0xEA, - (byte)0x97, (byte)0xF2, (byte)0xCF, (byte)0xCE, - (byte)0xF0, (byte)0xB4, (byte)0xE6, (byte)0x73, - (byte)0x96, (byte)0xAC, (byte)0x74, (byte)0x22, - (byte)0xE7, (byte)0xAD, (byte)0x35, (byte)0x85, - (byte)0xE2, (byte)0xF9, (byte)0x37, (byte)0xE8, - (byte)0x1C, (byte)0x75, (byte)0xDF, (byte)0x6E, - (byte)0x47, (byte)0xF1, (byte)0x1A, (byte)0x71, - (byte)0x1D, (byte)0x29, (byte)0xC5, (byte)0x89, - (byte)0x6F, (byte)0xB7, (byte)0x62, (byte)0x0E, - (byte)0xAA, (byte)0x18, (byte)0xBE, (byte)0x1B, - (byte)0xFC, (byte)0x56, (byte)0x3E, (byte)0x4B, - (byte)0xC6, (byte)0xD2, (byte)0x79, (byte)0x20, - (byte)0x9A, (byte)0xDB, (byte)0xC0, (byte)0xFE, - (byte)0x78, (byte)0xCD, (byte)0x5A, (byte)0xF4, - (byte)0x1F, (byte)0xDD, (byte)0xA8, (byte)0x33, - (byte)0x88, (byte)0x07, (byte)0xC7, (byte)0x31, - (byte)0xB1, (byte)0x12, (byte)0x10, (byte)0x59, - (byte)0x27, (byte)0x80, (byte)0xEC, (byte)0x5F, - (byte)0x60, (byte)0x51, (byte)0x7F, (byte)0xA9, - (byte)0x19, (byte)0xB5, (byte)0x4A, (byte)0x0D, - (byte)0x2D, (byte)0xE5, (byte)0x7A, (byte)0x9F, - (byte)0x93, (byte)0xC9, (byte)0x9C, (byte)0xEF, - (byte)0xA0, (byte)0xE0, (byte)0x3B, (byte)0x4D, - (byte)0xAE, (byte)0x2A, (byte)0xF5, (byte)0xB0, - (byte)0xC8, (byte)0xEB, (byte)0xBB, (byte)0x3C, - (byte)0x83, (byte)0x53, (byte)0x99, (byte)0x61, - (byte)0x17, (byte)0x2B, (byte)0x04, (byte)0x7E, - (byte)0xBA, (byte)0x77, (byte)0xD6, (byte)0x26, - (byte)0xE1, (byte)0x69, (byte)0x14, (byte)0x63, - (byte)0x55, (byte)0x21, (byte)0x0C, (byte)0x7D, - }; - - // pre-computed tables (T-box) - private static final int[] T1 = { - 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, - 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, - 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, - 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, - 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, - 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, - 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, - 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, - 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, - 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, - 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, - 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, - 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, - 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, - 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, - 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, - 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, - 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, - 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, - 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, - 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, - 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, - 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, - 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, - 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, - 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, - 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, - 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, - 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, - 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, - 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, - 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, - 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, - 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, - 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, - 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, - 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, - 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, - 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, - 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, - 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, - 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, - 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, - 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, - 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, - 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, - 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, - 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, - 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, - 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, - 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, - 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, - 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, - 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, - 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, - 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, - 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, - 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, - 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, - 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, - 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, - 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, - 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, - 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A, - }; - - private static final int[] T2 = { - 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, - 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, - 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, - 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, - 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, - 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, - 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, - 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, - 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, - 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, - 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, - 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, - 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, - 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, - 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, - 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, - 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, - 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, - 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, - 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, - 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, - 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, - 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, - 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, - 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, - 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, - 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, - 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, - 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, - 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, - 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, - 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, - 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, - 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, - 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, - 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, - 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, - 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, - 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, - 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, - 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, - 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, - 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, - 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, - 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, - 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, - 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, - 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, - 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, - 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, - 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, - 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, - 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, - 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, - 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, - 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, - 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, - 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, - 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, - 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, - 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, - 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, - 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, - 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616, - }; - - private static final int[] T3 = { - 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, - 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, - 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, - 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, - 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, - 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, - 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, - 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, - 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, - 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, - 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, - 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, - 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, - 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, - 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, - 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, - 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, - 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, - 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, - 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, - 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, - 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, - 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, - 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, - 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, - 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, - 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, - 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, - 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, - 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, - 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, - 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, - 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, - 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, - 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, - 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, - 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, - 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, - 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, - 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, - 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, - 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, - 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, - 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, - 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, - 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, - 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, - 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, - 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, - 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, - 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, - 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, - 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, - 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, - 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, - 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, - 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, - 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, - 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, - 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, - 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, - 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, - 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, - 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16, - }; - - private static final int[] T4 = { - 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, - 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, - 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, - 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, - 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, - 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, - 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, - 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, - 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, - 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, - 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, - 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, - 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, - 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, - 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, - 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, - 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, - 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, - 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, - 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, - 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, - 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, - 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, - 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, - 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, - 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, - 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, - 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, - 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, - 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, - 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, - 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, - 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, - 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, - 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, - 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, - 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, - 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, - 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, - 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, - 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, - 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, - 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, - 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, - 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, - 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, - 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, - 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, - 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, - 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, - 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, - 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, - 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, - 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, - 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, - 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, - 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, - 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, - 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, - 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, - 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, - 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, - 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, - 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C, - }; - - - // pre-computed inverse tables (inverse T-box) - private static final int[] T5 = { - 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, - 0x3BAB6BCB, 0x1F9D45F1, 0xACFA58AB, 0x4BE30393, - 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, - 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, - 0xDEB15A49, 0x25BA1B67, 0x45EA0E98, 0x5DFEC0E1, - 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, - 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, - 0xD4BE832D, 0x587421D3, 0x49E06929, 0x8EC9C844, - 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, - 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, - 0x63DF4A18, 0xE51A3182, 0x97513360, 0x62537F45, - 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, - 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, - 0xAB73D323, 0x724B02E2, 0xE31F8F57, 0x6655AB2A, - 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, - 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, - 0x8ACF1C2B, 0xA779B492, 0xF307F2F0, 0x4E69E2A1, - 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, - 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, - 0x0B83EC39, 0x4060EFAA, 0x5E719F06, 0xBD6E1051, - 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, - 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, - 0x1998FB24, 0xD6BDE997, 0x894043CC, 0x67D99E77, - 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, - 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, - 0x09808683, 0x322BED48, 0x1E1170AC, 0x6C5A724E, - 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, - 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, - 0x0C0A67B1, 0x9357E70F, 0xB4EE96D2, 0x1B9B919E, - 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, - 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, - 0x0E090D0B, 0xF28BC7AD, 0x2DB6A8B9, 0x141EA9C8, - 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, - 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, - 0x8B432976, 0xCB23C6DC, 0xB6EDFC68, 0xB8E4F163, - 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, - 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, - 0x1D9E2F4B, 0xDCB230F3, 0x0D8652EC, 0x77C1E3D0, - 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, - 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, - 0x87494EC7, 0xD938D1C1, 0x8CCAA2FE, 0x98D40B36, - 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, - 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, - 0xF68D13C2, 0x90D8B8E8, 0x2E39F75E, 0x82C3AFF5, - 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, - 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, - 0xCD267809, 0x6E5918F4, 0xEC9AB701, 0x834F9AA8, - 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, - 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, - 0x31A4B2AF, 0x2A3F2331, 0xC6A59430, 0x35A266C0, - 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, - 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, - 0x764DD68D, 0x43EFB04D, 0xCCAA4D54, 0xE49604DF, - 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, - 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, - 0xB3671D5A, 0x92DBD252, 0xE9105633, 0x6DD64713, - 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, - 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, - 0x9CD2DF59, 0x55F2733F, 0x1814CE79, 0x73C737BF, - 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, - 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, - 0x161DC372, 0xBCE2250C, 0x283C498B, 0xFF0D9541, - 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, - 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742, - }; - - private static final int[] T6 = { - 0x5051F4A7, 0x537E4165, 0xC31A17A4, 0x963A275E, - 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303, - 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, - 0xFC4FE5D7, 0xD7C52ACB, 0x80263544, 0x8FB562A3, - 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, - 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, - 0xE7038F5F, 0x9515929C, 0xEBBF6D7A, 0xDA955259, - 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8, - 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, - 0xB6BEE14F, 0x17F088AD, 0x66C920AC, 0xB47DCE3A, - 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, - 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, - 0x58704868, 0x198F45FD, 0x8794DE6C, 0xB7527BF8, - 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB, - 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, - 0xF2302887, 0xB223BFA5, 0xBA02036A, 0x5CED1682, - 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, - 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, - 0x9D342E53, 0xA0A2F355, 0x32058AE1, 0x75A4F6EB, - 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, - 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, - 0xB591548D, 0x0571C45D, 0x6F0406D4, 0xFF605015, - 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, - 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, - 0x47A17C0A, 0xE97C420F, 0xC9F8841E, 0x00000000, - 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, - 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, - 0x640A0FD9, 0x21685CA6, 0xD19B5B54, 0x3A24362E, - 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, - 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, - 0x0AE293BA, 0xE5C0A02A, 0x433C22E0, 0x1D121B17, - 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, - 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, - 0x9FF70126, 0xBC5C72F5, 0xC544663B, 0x345BFB7E, - 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, - 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, - 0x7D854A24, 0xF8D2BB3D, 0x11AEF932, 0x6DC729A1, - 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3, - 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, - 0xC4A8FC8C, 0x1AA0F03F, 0xD8567D2C, 0xEF223390, - 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, - 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, - 0xE42C3A9D, 0x0D507892, 0x9B6A5FCC, 0x62547E46, - 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF, - 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, - 0x3BC8AC99, 0xA710187D, 0x6EE89C63, 0x7BDB3BBB, - 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, - 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, - 0xD9BAE79B, 0xCE4A6F36, 0xD4EA9F09, 0xD629B07C, - 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, - 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, - 0x4AF10498, 0xF741ECDA, 0x0E7FCD50, 0x2F1791F6, - 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, - 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, - 0x049D5EEA, 0x5D018C35, 0x73FA8774, 0x2EFB0B41, - 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, - 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, - 0xEECEA927, 0x35B761C9, 0xEDE11CE5, 0x3C7A47B1, - 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, - 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, - 0x81CAAFF3, 0x3EB968C4, 0x2C382434, 0x5FC2A340, - 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95, - 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, - 0x617BCB84, 0x70D532B6, 0x74486C5C, 0x42D0B857, - }; - - private static final int[] T7 = { - 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, - 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, - 0xFA552030, 0x6DF6AD76, 0x769188CC, 0x4C25F502, - 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562, - 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, - 0x7502C32F, 0xF012814C, 0x97A38D46, 0xF9C66BD3, - 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, - 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, - 0x896A75C2, 0x7978F48E, 0x3E6B9958, 0x71DD27B9, - 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, - 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, - 0x77E0B164, 0xAE84BB6B, 0xA01CFE81, 0x2B94F908, - 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, - 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, - 0x2807B2EB, 0xC2032FB5, 0x7B9A86C5, 0x08A5D337, - 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, - 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, - 0xF4CD65DA, 0xBED50605, 0x621FD134, 0xFE8AC4A6, - 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, - 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, - 0x8AF93E21, 0x063D96DD, 0x05AEDD3E, 0xBD464DE6, - 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050, - 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, - 0x42BDB0E8, 0x8B880789, 0x5B38E719, 0xEEDB79C8, - 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, - 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, - 0xFFFBFD0E, 0x38560F85, 0xD51E3DAE, 0x3927362D, - 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436, - 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, - 0xC54F80C0, 0x20A261DC, 0x4B695A77, 0x1A161C12, - 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, - 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, - 0x198557F1, 0x074CAF75, 0xDDBBEE99, 0x60FDA37F, - 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB, - 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, - 0xDCCAD731, 0x85104263, 0x22401397, 0x112084C6, - 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, - 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, - 0x166C2BB3, 0xB999A970, 0x48FA1194, 0x642247E9, - 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, - 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, - 0x81CFA6F5, 0xDE28A57A, 0x8E26DAB7, 0xBFA43FAD, - 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, - 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, - 0x80BE9F5D, 0x937C69D0, 0x2DA96FD5, 0x12B3CF25, - 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, - 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, - 0x6E65E695, 0xE67EAAFF, 0xCF0821BC, 0xE8E6EF15, - 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, - 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, - 0xBC37744E, 0xCAA6FC82, 0xD0B0E090, 0xD81533A7, - 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791, - 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, - 0xB5E39ED1, 0x881B4C6A, 0x1FB8C12C, 0x517F4665, - 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, - 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, - 0x618C9AD7, 0x0C7A37A1, 0x148E59F8, 0x3C89EB13, - 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47, - 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, - 0xCDEA53F7, 0xAA5B5FFD, 0x6F14DF3D, 0xDB867844, - 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, - 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, - 0x017139A8, 0xB3DE080C, 0xE49CD8B4, 0xC1906456, - 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8, - }; - - private static final int[] T8 = { - 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, - 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, - 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, - 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, - 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, - 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, - 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, - 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, - 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, - 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, - 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, - 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, - 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, - 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, - 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, - 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, - 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, - 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, - 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, - 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, - 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, - 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, - 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, - 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, - 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, - 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, - 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, - 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, - 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, - 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, - 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, - 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, - 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, - 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, - 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, - 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, - 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, - 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, - 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, - 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, - 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, - 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, - 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, - 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, - 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, - 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, - 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, - 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, - 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, - 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, - 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, - 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, - 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, - 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, - 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, - 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, - 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, - 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, - 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, - 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, - 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, - 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, - 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, - 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0, - }; - - private static final int[] U1 = { - 0x00000000, 0x0E090D0B, 0x1C121A16, 0x121B171D, - 0x3824342C, 0x362D3927, 0x24362E3A, 0x2A3F2331, - 0x70486858, 0x7E416553, 0x6C5A724E, 0x62537F45, - 0x486C5C74, 0x4665517F, 0x547E4662, 0x5A774B69, - 0xE090D0B0, 0xEE99DDBB, 0xFC82CAA6, 0xF28BC7AD, - 0xD8B4E49C, 0xD6BDE997, 0xC4A6FE8A, 0xCAAFF381, - 0x90D8B8E8, 0x9ED1B5E3, 0x8CCAA2FE, 0x82C3AFF5, - 0xA8FC8CC4, 0xA6F581CF, 0xB4EE96D2, 0xBAE79BD9, - 0xDB3BBB7B, 0xD532B670, 0xC729A16D, 0xC920AC66, - 0xE31F8F57, 0xED16825C, 0xFF0D9541, 0xF104984A, - 0xAB73D323, 0xA57ADE28, 0xB761C935, 0xB968C43E, - 0x9357E70F, 0x9D5EEA04, 0x8F45FD19, 0x814CF012, - 0x3BAB6BCB, 0x35A266C0, 0x27B971DD, 0x29B07CD6, - 0x038F5FE7, 0x0D8652EC, 0x1F9D45F1, 0x119448FA, - 0x4BE30393, 0x45EA0E98, 0x57F11985, 0x59F8148E, - 0x73C737BF, 0x7DCE3AB4, 0x6FD52DA9, 0x61DC20A2, - 0xAD766DF6, 0xA37F60FD, 0xB16477E0, 0xBF6D7AEB, - 0x955259DA, 0x9B5B54D1, 0x894043CC, 0x87494EC7, - 0xDD3E05AE, 0xD33708A5, 0xC12C1FB8, 0xCF2512B3, - 0xE51A3182, 0xEB133C89, 0xF9082B94, 0xF701269F, - 0x4DE6BD46, 0x43EFB04D, 0x51F4A750, 0x5FFDAA5B, - 0x75C2896A, 0x7BCB8461, 0x69D0937C, 0x67D99E77, - 0x3DAED51E, 0x33A7D815, 0x21BCCF08, 0x2FB5C203, - 0x058AE132, 0x0B83EC39, 0x1998FB24, 0x1791F62F, - 0x764DD68D, 0x7844DB86, 0x6A5FCC9B, 0x6456C190, - 0x4E69E2A1, 0x4060EFAA, 0x527BF8B7, 0x5C72F5BC, - 0x0605BED5, 0x080CB3DE, 0x1A17A4C3, 0x141EA9C8, - 0x3E218AF9, 0x302887F2, 0x223390EF, 0x2C3A9DE4, - 0x96DD063D, 0x98D40B36, 0x8ACF1C2B, 0x84C61120, - 0xAEF93211, 0xA0F03F1A, 0xB2EB2807, 0xBCE2250C, - 0xE6956E65, 0xE89C636E, 0xFA877473, 0xF48E7978, - 0xDEB15A49, 0xD0B85742, 0xC2A3405F, 0xCCAA4D54, - 0x41ECDAF7, 0x4FE5D7FC, 0x5DFEC0E1, 0x53F7CDEA, - 0x79C8EEDB, 0x77C1E3D0, 0x65DAF4CD, 0x6BD3F9C6, - 0x31A4B2AF, 0x3FADBFA4, 0x2DB6A8B9, 0x23BFA5B2, - 0x09808683, 0x07898B88, 0x15929C95, 0x1B9B919E, - 0xA17C0A47, 0xAF75074C, 0xBD6E1051, 0xB3671D5A, - 0x99583E6B, 0x97513360, 0x854A247D, 0x8B432976, - 0xD134621F, 0xDF3D6F14, 0xCD267809, 0xC32F7502, - 0xE9105633, 0xE7195B38, 0xF5024C25, 0xFB0B412E, - 0x9AD7618C, 0x94DE6C87, 0x86C57B9A, 0x88CC7691, - 0xA2F355A0, 0xACFA58AB, 0xBEE14FB6, 0xB0E842BD, - 0xEA9F09D4, 0xE49604DF, 0xF68D13C2, 0xF8841EC9, - 0xD2BB3DF8, 0xDCB230F3, 0xCEA927EE, 0xC0A02AE5, - 0x7A47B13C, 0x744EBC37, 0x6655AB2A, 0x685CA621, - 0x42638510, 0x4C6A881B, 0x5E719F06, 0x5078920D, - 0x0A0FD964, 0x0406D46F, 0x161DC372, 0x1814CE79, - 0x322BED48, 0x3C22E043, 0x2E39F75E, 0x2030FA55, - 0xEC9AB701, 0xE293BA0A, 0xF088AD17, 0xFE81A01C, - 0xD4BE832D, 0xDAB78E26, 0xC8AC993B, 0xC6A59430, - 0x9CD2DF59, 0x92DBD252, 0x80C0C54F, 0x8EC9C844, - 0xA4F6EB75, 0xAAFFE67E, 0xB8E4F163, 0xB6EDFC68, - 0x0C0A67B1, 0x02036ABA, 0x10187DA7, 0x1E1170AC, - 0x342E539D, 0x3A275E96, 0x283C498B, 0x26354480, - 0x7C420FE9, 0x724B02E2, 0x605015FF, 0x6E5918F4, - 0x44663BC5, 0x4A6F36CE, 0x587421D3, 0x567D2CD8, - 0x37A10C7A, 0x39A80171, 0x2BB3166C, 0x25BA1B67, - 0x0F853856, 0x018C355D, 0x13972240, 0x1D9E2F4B, - 0x47E96422, 0x49E06929, 0x5BFB7E34, 0x55F2733F, - 0x7FCD500E, 0x71C45D05, 0x63DF4A18, 0x6DD64713, - 0xD731DCCA, 0xD938D1C1, 0xCB23C6DC, 0xC52ACBD7, - 0xEF15E8E6, 0xE11CE5ED, 0xF307F2F0, 0xFD0EFFFB, - 0xA779B492, 0xA970B999, 0xBB6BAE84, 0xB562A38F, - 0x9F5D80BE, 0x91548DB5, 0x834F9AA8, 0x8D4697A3, - }; - - private static final int[] U2 = { - 0x00000000, 0x0B0E090D, 0x161C121A, 0x1D121B17, - 0x2C382434, 0x27362D39, 0x3A24362E, 0x312A3F23, - 0x58704868, 0x537E4165, 0x4E6C5A72, 0x4562537F, - 0x74486C5C, 0x7F466551, 0x62547E46, 0x695A774B, - 0xB0E090D0, 0xBBEE99DD, 0xA6FC82CA, 0xADF28BC7, - 0x9CD8B4E4, 0x97D6BDE9, 0x8AC4A6FE, 0x81CAAFF3, - 0xE890D8B8, 0xE39ED1B5, 0xFE8CCAA2, 0xF582C3AF, - 0xC4A8FC8C, 0xCFA6F581, 0xD2B4EE96, 0xD9BAE79B, - 0x7BDB3BBB, 0x70D532B6, 0x6DC729A1, 0x66C920AC, - 0x57E31F8F, 0x5CED1682, 0x41FF0D95, 0x4AF10498, - 0x23AB73D3, 0x28A57ADE, 0x35B761C9, 0x3EB968C4, - 0x0F9357E7, 0x049D5EEA, 0x198F45FD, 0x12814CF0, - 0xCB3BAB6B, 0xC035A266, 0xDD27B971, 0xD629B07C, - 0xE7038F5F, 0xEC0D8652, 0xF11F9D45, 0xFA119448, - 0x934BE303, 0x9845EA0E, 0x8557F119, 0x8E59F814, - 0xBF73C737, 0xB47DCE3A, 0xA96FD52D, 0xA261DC20, - 0xF6AD766D, 0xFDA37F60, 0xE0B16477, 0xEBBF6D7A, - 0xDA955259, 0xD19B5B54, 0xCC894043, 0xC787494E, - 0xAEDD3E05, 0xA5D33708, 0xB8C12C1F, 0xB3CF2512, - 0x82E51A31, 0x89EB133C, 0x94F9082B, 0x9FF70126, - 0x464DE6BD, 0x4D43EFB0, 0x5051F4A7, 0x5B5FFDAA, - 0x6A75C289, 0x617BCB84, 0x7C69D093, 0x7767D99E, - 0x1E3DAED5, 0x1533A7D8, 0x0821BCCF, 0x032FB5C2, - 0x32058AE1, 0x390B83EC, 0x241998FB, 0x2F1791F6, - 0x8D764DD6, 0x867844DB, 0x9B6A5FCC, 0x906456C1, - 0xA14E69E2, 0xAA4060EF, 0xB7527BF8, 0xBC5C72F5, - 0xD50605BE, 0xDE080CB3, 0xC31A17A4, 0xC8141EA9, - 0xF93E218A, 0xF2302887, 0xEF223390, 0xE42C3A9D, - 0x3D96DD06, 0x3698D40B, 0x2B8ACF1C, 0x2084C611, - 0x11AEF932, 0x1AA0F03F, 0x07B2EB28, 0x0CBCE225, - 0x65E6956E, 0x6EE89C63, 0x73FA8774, 0x78F48E79, - 0x49DEB15A, 0x42D0B857, 0x5FC2A340, 0x54CCAA4D, - 0xF741ECDA, 0xFC4FE5D7, 0xE15DFEC0, 0xEA53F7CD, - 0xDB79C8EE, 0xD077C1E3, 0xCD65DAF4, 0xC66BD3F9, - 0xAF31A4B2, 0xA43FADBF, 0xB92DB6A8, 0xB223BFA5, - 0x83098086, 0x8807898B, 0x9515929C, 0x9E1B9B91, - 0x47A17C0A, 0x4CAF7507, 0x51BD6E10, 0x5AB3671D, - 0x6B99583E, 0x60975133, 0x7D854A24, 0x768B4329, - 0x1FD13462, 0x14DF3D6F, 0x09CD2678, 0x02C32F75, - 0x33E91056, 0x38E7195B, 0x25F5024C, 0x2EFB0B41, - 0x8C9AD761, 0x8794DE6C, 0x9A86C57B, 0x9188CC76, - 0xA0A2F355, 0xABACFA58, 0xB6BEE14F, 0xBDB0E842, - 0xD4EA9F09, 0xDFE49604, 0xC2F68D13, 0xC9F8841E, - 0xF8D2BB3D, 0xF3DCB230, 0xEECEA927, 0xE5C0A02A, - 0x3C7A47B1, 0x37744EBC, 0x2A6655AB, 0x21685CA6, - 0x10426385, 0x1B4C6A88, 0x065E719F, 0x0D507892, - 0x640A0FD9, 0x6F0406D4, 0x72161DC3, 0x791814CE, - 0x48322BED, 0x433C22E0, 0x5E2E39F7, 0x552030FA, - 0x01EC9AB7, 0x0AE293BA, 0x17F088AD, 0x1CFE81A0, - 0x2DD4BE83, 0x26DAB78E, 0x3BC8AC99, 0x30C6A594, - 0x599CD2DF, 0x5292DBD2, 0x4F80C0C5, 0x448EC9C8, - 0x75A4F6EB, 0x7EAAFFE6, 0x63B8E4F1, 0x68B6EDFC, - 0xB10C0A67, 0xBA02036A, 0xA710187D, 0xAC1E1170, - 0x9D342E53, 0x963A275E, 0x8B283C49, 0x80263544, - 0xE97C420F, 0xE2724B02, 0xFF605015, 0xF46E5918, - 0xC544663B, 0xCE4A6F36, 0xD3587421, 0xD8567D2C, - 0x7A37A10C, 0x7139A801, 0x6C2BB316, 0x6725BA1B, - 0x560F8538, 0x5D018C35, 0x40139722, 0x4B1D9E2F, - 0x2247E964, 0x2949E069, 0x345BFB7E, 0x3F55F273, - 0x0E7FCD50, 0x0571C45D, 0x1863DF4A, 0x136DD647, - 0xCAD731DC, 0xC1D938D1, 0xDCCB23C6, 0xD7C52ACB, - 0xE6EF15E8, 0xEDE11CE5, 0xF0F307F2, 0xFBFD0EFF, - 0x92A779B4, 0x99A970B9, 0x84BB6BAE, 0x8FB562A3, - 0xBE9F5D80, 0xB591548D, 0xA8834F9A, 0xA38D4697, - }; - - private static final int[] U3 = { - 0x00000000, 0x0D0B0E09, 0x1A161C12, 0x171D121B, - 0x342C3824, 0x3927362D, 0x2E3A2436, 0x23312A3F, - 0x68587048, 0x65537E41, 0x724E6C5A, 0x7F456253, - 0x5C74486C, 0x517F4665, 0x4662547E, 0x4B695A77, - 0xD0B0E090, 0xDDBBEE99, 0xCAA6FC82, 0xC7ADF28B, - 0xE49CD8B4, 0xE997D6BD, 0xFE8AC4A6, 0xF381CAAF, - 0xB8E890D8, 0xB5E39ED1, 0xA2FE8CCA, 0xAFF582C3, - 0x8CC4A8FC, 0x81CFA6F5, 0x96D2B4EE, 0x9BD9BAE7, - 0xBB7BDB3B, 0xB670D532, 0xA16DC729, 0xAC66C920, - 0x8F57E31F, 0x825CED16, 0x9541FF0D, 0x984AF104, - 0xD323AB73, 0xDE28A57A, 0xC935B761, 0xC43EB968, - 0xE70F9357, 0xEA049D5E, 0xFD198F45, 0xF012814C, - 0x6BCB3BAB, 0x66C035A2, 0x71DD27B9, 0x7CD629B0, - 0x5FE7038F, 0x52EC0D86, 0x45F11F9D, 0x48FA1194, - 0x03934BE3, 0x0E9845EA, 0x198557F1, 0x148E59F8, - 0x37BF73C7, 0x3AB47DCE, 0x2DA96FD5, 0x20A261DC, - 0x6DF6AD76, 0x60FDA37F, 0x77E0B164, 0x7AEBBF6D, - 0x59DA9552, 0x54D19B5B, 0x43CC8940, 0x4EC78749, - 0x05AEDD3E, 0x08A5D337, 0x1FB8C12C, 0x12B3CF25, - 0x3182E51A, 0x3C89EB13, 0x2B94F908, 0x269FF701, - 0xBD464DE6, 0xB04D43EF, 0xA75051F4, 0xAA5B5FFD, - 0x896A75C2, 0x84617BCB, 0x937C69D0, 0x9E7767D9, - 0xD51E3DAE, 0xD81533A7, 0xCF0821BC, 0xC2032FB5, - 0xE132058A, 0xEC390B83, 0xFB241998, 0xF62F1791, - 0xD68D764D, 0xDB867844, 0xCC9B6A5F, 0xC1906456, - 0xE2A14E69, 0xEFAA4060, 0xF8B7527B, 0xF5BC5C72, - 0xBED50605, 0xB3DE080C, 0xA4C31A17, 0xA9C8141E, - 0x8AF93E21, 0x87F23028, 0x90EF2233, 0x9DE42C3A, - 0x063D96DD, 0x0B3698D4, 0x1C2B8ACF, 0x112084C6, - 0x3211AEF9, 0x3F1AA0F0, 0x2807B2EB, 0x250CBCE2, - 0x6E65E695, 0x636EE89C, 0x7473FA87, 0x7978F48E, - 0x5A49DEB1, 0x5742D0B8, 0x405FC2A3, 0x4D54CCAA, - 0xDAF741EC, 0xD7FC4FE5, 0xC0E15DFE, 0xCDEA53F7, - 0xEEDB79C8, 0xE3D077C1, 0xF4CD65DA, 0xF9C66BD3, - 0xB2AF31A4, 0xBFA43FAD, 0xA8B92DB6, 0xA5B223BF, - 0x86830980, 0x8B880789, 0x9C951592, 0x919E1B9B, - 0x0A47A17C, 0x074CAF75, 0x1051BD6E, 0x1D5AB367, - 0x3E6B9958, 0x33609751, 0x247D854A, 0x29768B43, - 0x621FD134, 0x6F14DF3D, 0x7809CD26, 0x7502C32F, - 0x5633E910, 0x5B38E719, 0x4C25F502, 0x412EFB0B, - 0x618C9AD7, 0x6C8794DE, 0x7B9A86C5, 0x769188CC, - 0x55A0A2F3, 0x58ABACFA, 0x4FB6BEE1, 0x42BDB0E8, - 0x09D4EA9F, 0x04DFE496, 0x13C2F68D, 0x1EC9F884, - 0x3DF8D2BB, 0x30F3DCB2, 0x27EECEA9, 0x2AE5C0A0, - 0xB13C7A47, 0xBC37744E, 0xAB2A6655, 0xA621685C, - 0x85104263, 0x881B4C6A, 0x9F065E71, 0x920D5078, - 0xD9640A0F, 0xD46F0406, 0xC372161D, 0xCE791814, - 0xED48322B, 0xE0433C22, 0xF75E2E39, 0xFA552030, - 0xB701EC9A, 0xBA0AE293, 0xAD17F088, 0xA01CFE81, - 0x832DD4BE, 0x8E26DAB7, 0x993BC8AC, 0x9430C6A5, - 0xDF599CD2, 0xD25292DB, 0xC54F80C0, 0xC8448EC9, - 0xEB75A4F6, 0xE67EAAFF, 0xF163B8E4, 0xFC68B6ED, - 0x67B10C0A, 0x6ABA0203, 0x7DA71018, 0x70AC1E11, - 0x539D342E, 0x5E963A27, 0x498B283C, 0x44802635, - 0x0FE97C42, 0x02E2724B, 0x15FF6050, 0x18F46E59, - 0x3BC54466, 0x36CE4A6F, 0x21D35874, 0x2CD8567D, - 0x0C7A37A1, 0x017139A8, 0x166C2BB3, 0x1B6725BA, - 0x38560F85, 0x355D018C, 0x22401397, 0x2F4B1D9E, - 0x642247E9, 0x692949E0, 0x7E345BFB, 0x733F55F2, - 0x500E7FCD, 0x5D0571C4, 0x4A1863DF, 0x47136DD6, - 0xDCCAD731, 0xD1C1D938, 0xC6DCCB23, 0xCBD7C52A, - 0xE8E6EF15, 0xE5EDE11C, 0xF2F0F307, 0xFFFBFD0E, - 0xB492A779, 0xB999A970, 0xAE84BB6B, 0xA38FB562, - 0x80BE9F5D, 0x8DB59154, 0x9AA8834F, 0x97A38D46, - }; - - private static final int[] U4 = { - 0x00000000, 0x090D0B0E, 0x121A161C, 0x1B171D12, - 0x24342C38, 0x2D392736, 0x362E3A24, 0x3F23312A, - 0x48685870, 0x4165537E, 0x5A724E6C, 0x537F4562, - 0x6C5C7448, 0x65517F46, 0x7E466254, 0x774B695A, - 0x90D0B0E0, 0x99DDBBEE, 0x82CAA6FC, 0x8BC7ADF2, - 0xB4E49CD8, 0xBDE997D6, 0xA6FE8AC4, 0xAFF381CA, - 0xD8B8E890, 0xD1B5E39E, 0xCAA2FE8C, 0xC3AFF582, - 0xFC8CC4A8, 0xF581CFA6, 0xEE96D2B4, 0xE79BD9BA, - 0x3BBB7BDB, 0x32B670D5, 0x29A16DC7, 0x20AC66C9, - 0x1F8F57E3, 0x16825CED, 0x0D9541FF, 0x04984AF1, - 0x73D323AB, 0x7ADE28A5, 0x61C935B7, 0x68C43EB9, - 0x57E70F93, 0x5EEA049D, 0x45FD198F, 0x4CF01281, - 0xAB6BCB3B, 0xA266C035, 0xB971DD27, 0xB07CD629, - 0x8F5FE703, 0x8652EC0D, 0x9D45F11F, 0x9448FA11, - 0xE303934B, 0xEA0E9845, 0xF1198557, 0xF8148E59, - 0xC737BF73, 0xCE3AB47D, 0xD52DA96F, 0xDC20A261, - 0x766DF6AD, 0x7F60FDA3, 0x6477E0B1, 0x6D7AEBBF, - 0x5259DA95, 0x5B54D19B, 0x4043CC89, 0x494EC787, - 0x3E05AEDD, 0x3708A5D3, 0x2C1FB8C1, 0x2512B3CF, - 0x1A3182E5, 0x133C89EB, 0x082B94F9, 0x01269FF7, - 0xE6BD464D, 0xEFB04D43, 0xF4A75051, 0xFDAA5B5F, - 0xC2896A75, 0xCB84617B, 0xD0937C69, 0xD99E7767, - 0xAED51E3D, 0xA7D81533, 0xBCCF0821, 0xB5C2032F, - 0x8AE13205, 0x83EC390B, 0x98FB2419, 0x91F62F17, - 0x4DD68D76, 0x44DB8678, 0x5FCC9B6A, 0x56C19064, - 0x69E2A14E, 0x60EFAA40, 0x7BF8B752, 0x72F5BC5C, - 0x05BED506, 0x0CB3DE08, 0x17A4C31A, 0x1EA9C814, - 0x218AF93E, 0x2887F230, 0x3390EF22, 0x3A9DE42C, - 0xDD063D96, 0xD40B3698, 0xCF1C2B8A, 0xC6112084, - 0xF93211AE, 0xF03F1AA0, 0xEB2807B2, 0xE2250CBC, - 0x956E65E6, 0x9C636EE8, 0x877473FA, 0x8E7978F4, - 0xB15A49DE, 0xB85742D0, 0xA3405FC2, 0xAA4D54CC, - 0xECDAF741, 0xE5D7FC4F, 0xFEC0E15D, 0xF7CDEA53, - 0xC8EEDB79, 0xC1E3D077, 0xDAF4CD65, 0xD3F9C66B, - 0xA4B2AF31, 0xADBFA43F, 0xB6A8B92D, 0xBFA5B223, - 0x80868309, 0x898B8807, 0x929C9515, 0x9B919E1B, - 0x7C0A47A1, 0x75074CAF, 0x6E1051BD, 0x671D5AB3, - 0x583E6B99, 0x51336097, 0x4A247D85, 0x4329768B, - 0x34621FD1, 0x3D6F14DF, 0x267809CD, 0x2F7502C3, - 0x105633E9, 0x195B38E7, 0x024C25F5, 0x0B412EFB, - 0xD7618C9A, 0xDE6C8794, 0xC57B9A86, 0xCC769188, - 0xF355A0A2, 0xFA58ABAC, 0xE14FB6BE, 0xE842BDB0, - 0x9F09D4EA, 0x9604DFE4, 0x8D13C2F6, 0x841EC9F8, - 0xBB3DF8D2, 0xB230F3DC, 0xA927EECE, 0xA02AE5C0, - 0x47B13C7A, 0x4EBC3774, 0x55AB2A66, 0x5CA62168, - 0x63851042, 0x6A881B4C, 0x719F065E, 0x78920D50, - 0x0FD9640A, 0x06D46F04, 0x1DC37216, 0x14CE7918, - 0x2BED4832, 0x22E0433C, 0x39F75E2E, 0x30FA5520, - 0x9AB701EC, 0x93BA0AE2, 0x88AD17F0, 0x81A01CFE, - 0xBE832DD4, 0xB78E26DA, 0xAC993BC8, 0xA59430C6, - 0xD2DF599C, 0xDBD25292, 0xC0C54F80, 0xC9C8448E, - 0xF6EB75A4, 0xFFE67EAA, 0xE4F163B8, 0xEDFC68B6, - 0x0A67B10C, 0x036ABA02, 0x187DA710, 0x1170AC1E, - 0x2E539D34, 0x275E963A, 0x3C498B28, 0x35448026, - 0x420FE97C, 0x4B02E272, 0x5015FF60, 0x5918F46E, - 0x663BC544, 0x6F36CE4A, 0x7421D358, 0x7D2CD856, - 0xA10C7A37, 0xA8017139, 0xB3166C2B, 0xBA1B6725, - 0x8538560F, 0x8C355D01, 0x97224013, 0x9E2F4B1D, - 0xE9642247, 0xE0692949, 0xFB7E345B, 0xF2733F55, - 0xCD500E7F, 0xC45D0571, 0xDF4A1863, 0xD647136D, - 0x31DCCAD7, 0x38D1C1D9, 0x23C6DCCB, 0x2ACBD7C5, - 0x15E8E6EF, 0x1CE5EDE1, 0x07F2F0F3, 0x0EFFFBFD, - 0x79B492A7, 0x70B999A9, 0x6BAE84BB, 0x62A38FB5, - 0x5D80BE9F, 0x548DB591, 0x4F9AA883, 0x4697A38D, - }; - - private static final int[] rcon = { - 0x00000001, 0x00000002, 0x00000004, 0x00000008, - 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x0000001B, 0x00000036, 0x0000006C, 0x000000D8, - 0x000000AB, 0x0000004D, 0x0000009A, 0x0000002F, - 0x0000005E, 0x000000BC, 0x00000063, 0x000000C6, - 0x00000097, 0x00000035, 0x0000006A, 0x000000D4, - 0x000000B3, 0x0000007D, 0x000000FA, 0x000000EF, - 0x000000C5, 0x00000091, - }; - - private boolean ROUNDS_12 = false; - private boolean ROUNDS_14 = false; - - /** Session and Sub keys */ - private int[][] sessionK = null; - private int[] K = null; - - /** Cipher encryption/decryption key */ - // skip re-generating Session and Sub keys if the cipher key is - // the same - private byte[] lastKey = null; - - /** ROUNDS * 4 */ - private int limit = 0; - - AESCrypt() { - // empty - } - - /** - * Returns this cipher's block size. - * - * @return this cipher's block size - */ - int getBlockSize() { - return AES_BLOCK_SIZE; - } - - void init(boolean decrypting, String algorithm, byte[] key) - throws InvalidKeyException { - if (!algorithm.equalsIgnoreCase("AES") - && !algorithm.equalsIgnoreCase("Rijndael")) { - throw new InvalidKeyException - ("Wrong algorithm: AES or Rijndael required"); - } - - if (key == null) { // Unlikely, but just double check it. - throw new InvalidKeyException("Empty key"); - } - - if (!MessageDigest.isEqual(key, lastKey)) { - // re-generate session key 'sessionK' when cipher key changes - makeSessionKey(key); - if (lastKey != null) { - Arrays.fill(lastKey, (byte)0); - } - lastKey = key.clone(); // save cipher key - } - - // set sub key to the corresponding session Key - this.K = sessionK[(decrypting? 1:0)]; - } - - // check if the specified length (in bytes) is a valid keysize for AES - static boolean isKeySizeValid(int len) { - for (int aesKeysize : AES_KEYSIZES) { - if (len == aesKeysize) { - return true; - } - } - return false; - } - - /** - * Encrypt exactly one block of plaintext. - */ - void encryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) { - // Array bound checks are done in caller code, i.e. - // FeedbackCipher.encrypt/decrypt(...) to improve performance. - implEncryptBlock(in, inOffset, out, outOffset); - } - - // Encryption operation. Possibly replaced with a compiler intrinsic. - @IntrinsicCandidate - private void implEncryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) - { - int keyOffset = 0; - int t0 = ((in[inOffset++] ) << 24 | - (in[inOffset++] & 0xFF) << 16 | - (in[inOffset++] & 0xFF) << 8 | - (in[inOffset++] & 0xFF) ) ^ K[keyOffset++]; - int t1 = ((in[inOffset++] ) << 24 | - (in[inOffset++] & 0xFF) << 16 | - (in[inOffset++] & 0xFF) << 8 | - (in[inOffset++] & 0xFF) ) ^ K[keyOffset++]; - int t2 = ((in[inOffset++] ) << 24 | - (in[inOffset++] & 0xFF) << 16 | - (in[inOffset++] & 0xFF) << 8 | - (in[inOffset++] & 0xFF) ) ^ K[keyOffset++]; - int t3 = ((in[inOffset++] ) << 24 | - (in[inOffset++] & 0xFF) << 16 | - (in[inOffset++] & 0xFF) << 8 | - (in[inOffset] & 0xFF) ) ^ K[keyOffset++]; - - // apply round transforms - while( keyOffset < limit ) - { - int a0, a1, a2; - a0 = T1[(t0 >>> 24) ] ^ - T2[(t1 >>> 16) & 0xFF] ^ - T3[(t2 >>> 8) & 0xFF] ^ - T4[(t3 ) & 0xFF] ^ K[keyOffset++]; - a1 = T1[(t1 >>> 24) ] ^ - T2[(t2 >>> 16) & 0xFF] ^ - T3[(t3 >>> 8) & 0xFF] ^ - T4[(t0 ) & 0xFF] ^ K[keyOffset++]; - a2 = T1[(t2 >>> 24) ] ^ - T2[(t3 >>> 16) & 0xFF] ^ - T3[(t0 >>> 8) & 0xFF] ^ - T4[(t1 ) & 0xFF] ^ K[keyOffset++]; - t3 = T1[(t3 >>> 24) ] ^ - T2[(t0 >>> 16) & 0xFF] ^ - T3[(t1 >>> 8) & 0xFF] ^ - T4[(t2 ) & 0xFF] ^ K[keyOffset++]; - t0 = a0; t1 = a1; t2 = a2; - } - - // last round is special - int tt = K[keyOffset++]; - out[outOffset++] = (byte)(S[(t0 >>> 24) ] ^ (tt >>> 24)); - out[outOffset++] = (byte)(S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); - out[outOffset++] = (byte)(S[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); - out[outOffset++] = (byte)(S[(t3 ) & 0xFF] ^ (tt )); - tt = K[keyOffset++]; - out[outOffset++] = (byte)(S[(t1 >>> 24) ] ^ (tt >>> 24)); - out[outOffset++] = (byte)(S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); - out[outOffset++] = (byte)(S[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); - out[outOffset++] = (byte)(S[(t0 ) & 0xFF] ^ (tt )); - tt = K[keyOffset++]; - out[outOffset++] = (byte)(S[(t2 >>> 24) ] ^ (tt >>> 24)); - out[outOffset++] = (byte)(S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); - out[outOffset++] = (byte)(S[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); - out[outOffset++] = (byte)(S[(t1 ) & 0xFF] ^ (tt )); - tt = K[keyOffset]; - out[outOffset++] = (byte)(S[(t3 >>> 24) ] ^ (tt >>> 24)); - out[outOffset++] = (byte)(S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); - out[outOffset++] = (byte)(S[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); - out[outOffset ] = (byte)(S[(t2 ) & 0xFF] ^ (tt )); - } - - /** - * Decrypt exactly one block of plaintext. - */ - void decryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) { - // Array bound checks are done in caller code, i.e. - // FeedbackCipher.encrypt/decrypt(...) to improve performance. - implDecryptBlock(in, inOffset, out, outOffset); - } - - // Decrypt operation. Possibly replaced with a compiler intrinsic. - @IntrinsicCandidate - private void implDecryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) - { - int keyOffset = 4; - int t0 = ((in[inOffset++] ) << 24 | - (in[inOffset++] & 0xFF) << 16 | - (in[inOffset++] & 0xFF) << 8 | - (in[inOffset++] & 0xFF) ) ^ K[keyOffset++]; - int t1 = ((in[inOffset++] ) << 24 | - (in[inOffset++] & 0xFF) << 16 | - (in[inOffset++] & 0xFF) << 8 | - (in[inOffset++] & 0xFF) ) ^ K[keyOffset++]; - int t2 = ((in[inOffset++] ) << 24 | - (in[inOffset++] & 0xFF) << 16 | - (in[inOffset++] & 0xFF) << 8 | - (in[inOffset++] & 0xFF) ) ^ K[keyOffset++]; - int t3 = ((in[inOffset++] ) << 24 | - (in[inOffset++] & 0xFF) << 16 | - (in[inOffset++] & 0xFF) << 8 | - (in[inOffset ] & 0xFF) ) ^ K[keyOffset++]; - - int a0, a1, a2; - if(ROUNDS_12) - { - a0 = T5[(t0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(t2>>> 8)&0xFF] ^ T8[(t1 )&0xFF] ^ K[keyOffset++]; - a1 = T5[(t1>>>24) ] ^ T6[(t0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(t2 )&0xFF] ^ K[keyOffset++]; - a2 = T5[(t2>>>24) ] ^ T6[(t1>>>16)&0xFF] ^ - T7[(t0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(t2>>>16)&0xFF] ^ - T7[(t1>>> 8)&0xFF] ^ T8[(t0 )&0xFF] ^ K[keyOffset++]; - t0 = T5[(a0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(a2>>> 8)&0xFF] ^ T8[(a1 )&0xFF] ^ K[keyOffset++]; - t1 = T5[(a1>>>24) ] ^ T6[(a0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(a2 )&0xFF] ^ K[keyOffset++]; - t2 = T5[(a2>>>24) ] ^ T6[(a1>>>16)&0xFF] ^ - T7[(a0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(a2>>>16)&0xFF] ^ - T7[(a1>>> 8)&0xFF] ^ T8[(a0 )&0xFF] ^ K[keyOffset++]; - - if(ROUNDS_14) - { - a0 = T5[(t0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(t2>>> 8)&0xFF] ^ T8[(t1 )&0xFF] ^ K[keyOffset++]; - a1 = T5[(t1>>>24) ] ^ T6[(t0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(t2 )&0xFF] ^ K[keyOffset++]; - a2 = T5[(t2>>>24) ] ^ T6[(t1>>>16)&0xFF] ^ - T7[(t0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(t2>>>16)&0xFF] ^ - T7[(t1>>> 8)&0xFF] ^ T8[(t0 )&0xFF] ^ K[keyOffset++]; - t0 = T5[(a0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(a2>>> 8)&0xFF] ^ T8[(a1 )&0xFF] ^ K[keyOffset++]; - t1 = T5[(a1>>>24) ] ^ T6[(a0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(a2 )&0xFF] ^ K[keyOffset++]; - t2 = T5[(a2>>>24) ] ^ T6[(a1>>>16)&0xFF] ^ - T7[(a0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(a2>>>16)&0xFF] ^ - T7[(a1>>> 8)&0xFF] ^ T8[(a0 )&0xFF] ^ K[keyOffset++]; - } - } - a0 = T5[(t0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(t2>>> 8)&0xFF] ^ T8[(t1 )&0xFF] ^ K[keyOffset++]; - a1 = T5[(t1>>>24) ] ^ T6[(t0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(t2 )&0xFF] ^ K[keyOffset++]; - a2 = T5[(t2>>>24) ] ^ T6[(t1>>>16)&0xFF] ^ - T7[(t0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(t2>>>16)&0xFF] ^ - T7[(t1>>> 8)&0xFF] ^ T8[(t0 )&0xFF] ^ K[keyOffset++]; - t0 = T5[(a0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(a2>>> 8)&0xFF] ^ T8[(a1 )&0xFF] ^ K[keyOffset++]; - t1 = T5[(a1>>>24) ] ^ T6[(a0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(a2 )&0xFF] ^ K[keyOffset++]; - t2 = T5[(a2>>>24) ] ^ T6[(a1>>>16)&0xFF] ^ - T7[(a0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(a2>>>16)&0xFF] ^ - T7[(a1>>> 8)&0xFF] ^ T8[(a0 )&0xFF] ^ K[keyOffset++]; - a0 = T5[(t0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(t2>>> 8)&0xFF] ^ T8[(t1 )&0xFF] ^ K[keyOffset++]; - a1 = T5[(t1>>>24) ] ^ T6[(t0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(t2 )&0xFF] ^ K[keyOffset++]; - a2 = T5[(t2>>>24) ] ^ T6[(t1>>>16)&0xFF] ^ - T7[(t0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(t2>>>16)&0xFF] ^ - T7[(t1>>> 8)&0xFF] ^ T8[(t0 )&0xFF] ^ K[keyOffset++]; - t0 = T5[(a0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(a2>>> 8)&0xFF] ^ T8[(a1 )&0xFF] ^ K[keyOffset++]; - t1 = T5[(a1>>>24) ] ^ T6[(a0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(a2 )&0xFF] ^ K[keyOffset++]; - t2 = T5[(a2>>>24) ] ^ T6[(a1>>>16)&0xFF] ^ - T7[(a0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(a2>>>16)&0xFF] ^ - T7[(a1>>> 8)&0xFF] ^ T8[(a0 )&0xFF] ^ K[keyOffset++]; - a0 = T5[(t0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(t2>>> 8)&0xFF] ^ T8[(t1 )&0xFF] ^ K[keyOffset++]; - a1 = T5[(t1>>>24) ] ^ T6[(t0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(t2 )&0xFF] ^ K[keyOffset++]; - a2 = T5[(t2>>>24) ] ^ T6[(t1>>>16)&0xFF] ^ - T7[(t0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(t2>>>16)&0xFF] ^ - T7[(t1>>> 8)&0xFF] ^ T8[(t0 )&0xFF] ^ K[keyOffset++]; - t0 = T5[(a0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(a2>>> 8)&0xFF] ^ T8[(a1 )&0xFF] ^ K[keyOffset++]; - t1 = T5[(a1>>>24) ] ^ T6[(a0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(a2 )&0xFF] ^ K[keyOffset++]; - t2 = T5[(a2>>>24) ] ^ T6[(a1>>>16)&0xFF] ^ - T7[(a0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(a2>>>16)&0xFF] ^ - T7[(a1>>> 8)&0xFF] ^ T8[(a0 )&0xFF] ^ K[keyOffset++]; - a0 = T5[(t0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(t2>>> 8)&0xFF] ^ T8[(t1 )&0xFF] ^ K[keyOffset++]; - a1 = T5[(t1>>>24) ] ^ T6[(t0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(t2 )&0xFF] ^ K[keyOffset++]; - a2 = T5[(t2>>>24) ] ^ T6[(t1>>>16)&0xFF] ^ - T7[(t0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(t2>>>16)&0xFF] ^ - T7[(t1>>> 8)&0xFF] ^ T8[(t0 )&0xFF] ^ K[keyOffset++]; - t0 = T5[(a0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(a2>>> 8)&0xFF] ^ T8[(a1 )&0xFF] ^ K[keyOffset++]; - t1 = T5[(a1>>>24) ] ^ T6[(a0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(a2 )&0xFF] ^ K[keyOffset++]; - t2 = T5[(a2>>>24) ] ^ T6[(a1>>>16)&0xFF] ^ - T7[(a0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(a2>>>16)&0xFF] ^ - T7[(a1>>> 8)&0xFF] ^ T8[(a0 )&0xFF] ^ K[keyOffset++]; - a0 = T5[(t0>>>24) ] ^ T6[(t3>>>16)&0xFF] ^ - T7[(t2>>> 8)&0xFF] ^ T8[(t1 )&0xFF] ^ K[keyOffset++]; - a1 = T5[(t1>>>24) ] ^ T6[(t0>>>16)&0xFF] ^ - T7[(t3>>> 8)&0xFF] ^ T8[(t2 )&0xFF] ^ K[keyOffset++]; - a2 = T5[(t2>>>24) ] ^ T6[(t1>>>16)&0xFF] ^ - T7[(t0>>> 8)&0xFF] ^ T8[(t3 )&0xFF] ^ K[keyOffset++]; - t3 = T5[(t3>>>24) ] ^ T6[(t2>>>16)&0xFF] ^ - T7[(t1>>> 8)&0xFF] ^ T8[(t0 )&0xFF] ^ K[keyOffset]; - - t1 = K[0]; - out[outOffset++] = (byte)(Si[(a0 >>> 24) ] ^ (t1 >>> 24)); - out[outOffset++] = (byte)(Si[(t3 >>> 16) & 0xFF] ^ (t1 >>> 16)); - out[outOffset++] = (byte)(Si[(a2 >>> 8) & 0xFF] ^ (t1 >>> 8)); - out[outOffset++] = (byte)(Si[(a1 ) & 0xFF] ^ (t1 )); - t1 = K[1]; - out[outOffset++] = (byte)(Si[(a1 >>> 24) ] ^ (t1 >>> 24)); - out[outOffset++] = (byte)(Si[(a0 >>> 16) & 0xFF] ^ (t1 >>> 16)); - out[outOffset++] = (byte)(Si[(t3 >>> 8) & 0xFF] ^ (t1 >>> 8)); - out[outOffset++] = (byte)(Si[(a2 ) & 0xFF] ^ (t1 )); - t1 = K[2]; - out[outOffset++] = (byte)(Si[(a2 >>> 24) ] ^ (t1 >>> 24)); - out[outOffset++] = (byte)(Si[(a1 >>> 16) & 0xFF] ^ (t1 >>> 16)); - out[outOffset++] = (byte)(Si[(a0 >>> 8) & 0xFF] ^ (t1 >>> 8)); - out[outOffset++] = (byte)(Si[(t3 ) & 0xFF] ^ (t1 )); - t1 = K[3]; - out[outOffset++] = (byte)(Si[(t3 >>> 24) ] ^ (t1 >>> 24)); - out[outOffset++] = (byte)(Si[(a2 >>> 16) & 0xFF] ^ (t1 >>> 16)); - out[outOffset++] = (byte)(Si[(a1 >>> 8) & 0xFF] ^ (t1 >>> 8)); - out[outOffset ] = (byte)(Si[(a0 ) & 0xFF] ^ (t1 )); - } - - /** - * Expand a user-supplied key material into a session key. - * - * @param k The 128/192/256-bit cipher key to use. - * @exception InvalidKeyException If the key is invalid. - */ - private void makeSessionKey(byte[] k) throws InvalidKeyException { - if (!isKeySizeValid(k.length)) { - throw new InvalidKeyException("Invalid AES key length: " + - k.length + " bytes"); - } - - final int BC = 4; - - int ROUNDS = getRounds(k.length); - int ROUND_KEY_COUNT = (ROUNDS + 1) * BC; - - int[] Ke = new int[ROUND_KEY_COUNT]; // encryption round keys - int[] Kd = new int[ROUND_KEY_COUNT]; // decryption round keys - - int KC = k.length/4; // keylen in 32-bit elements - - int[] tk = new int[KC]; - int i, j; - - // copy user material bytes into temporary ints - for (i = 0, j = 0; i < KC; i++, j+=4) { - tk[i] = (k[j] ) << 24 | - (k[j+1] & 0xFF) << 16 | - (k[j+2] & 0xFF) << 8 | - (k[j+3] & 0xFF); - } - - // copy values into round key arrays - int t = 0; - for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { - Ke[t] = tk[j]; - Kd[(ROUNDS - (t / BC))*BC + (t % BC)] = tk[j]; - } - int tt, rconpointer = 0; - while (t < ROUND_KEY_COUNT) { - // extrapolate using phi (the round key evolution function) - tt = tk[KC - 1]; - tk[0] ^= (S[(tt >>> 16) & 0xFF] ) << 24 ^ - (S[(tt >>> 8) & 0xFF] & 0xFF) << 16 ^ - (S[(tt ) & 0xFF] & 0xFF) << 8 ^ - (S[(tt >>> 24) ] & 0xFF) ^ - (rcon[rconpointer++] ) << 24; - if (KC != 8) - for (i = 1, j = 0; i < KC; i++, j++) tk[i] ^= tk[j]; - else { - for (i = 1, j = 0; i < KC / 2; i++, j++) tk[i] ^= tk[j]; - tt = tk[KC / 2 - 1]; - tk[KC / 2] ^= (S[(tt ) & 0xFF] & 0xFF) ^ - (S[(tt >>> 8) & 0xFF] & 0xFF) << 8 ^ - (S[(tt >>> 16) & 0xFF] & 0xFF) << 16 ^ - (S[(tt >>> 24) ] ) << 24; - for (j = KC / 2, i = j + 1; i < KC; i++, j++) tk[i] ^= tk[j]; - } - // copy values into round key arrays - for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { - Ke[t] = tk[j]; - Kd[(ROUNDS - (t / BC))*BC + (t % BC)] = tk[j]; - } - } - for (int r = 1; r < ROUNDS; r++) { - // inverse MixColumn where needed - for (j = 0; j < BC; j++) { - int idx = r*BC + j; - tt = Kd[idx]; - Kd[idx] = U1[(tt >>> 24) & 0xFF] ^ - U2[(tt >>> 16) & 0xFF] ^ - U3[(tt >>> 8) & 0xFF] ^ - U4[ tt & 0xFF]; - } - } - - // For decryption round keys, need to rotate right by 4 ints. - // Do that without allocating and zeroing the small buffer. - int KdTail_0 = Kd[Kd.length - 4]; - int KdTail_1 = Kd[Kd.length - 3]; - int KdTail_2 = Kd[Kd.length - 2]; - int KdTail_3 = Kd[Kd.length - 1]; - System.arraycopy(Kd, 0, Kd, 4, Kd.length - 4); - Kd[0] = KdTail_0; - Kd[1] = KdTail_1; - Kd[2] = KdTail_2; - Kd[3] = KdTail_3; - - Arrays.fill(tk, 0); - ROUNDS_12 = (ROUNDS>=12); - ROUNDS_14 = (ROUNDS==14); - limit = ROUNDS*4; - - // store the expanded sub keys into 'sessionK' - if (sessionK != null) { - // erase the previous values in sessionK - Arrays.fill(sessionK[0], 0); - Arrays.fill(sessionK[1], 0); - } else { - sessionK = new int[2][]; - } - sessionK[0] = Ke; - sessionK[1] = Kd; - } - - /** - * Return The number of rounds for a given Rijndael keysize. - * - * @param keySize The size of the user key material in bytes. - * MUST be one of (16, 24, 32). - * @return The number of rounds. - */ - private static int getRounds(int keySize) { - return (keySize >> 2) + 6; - } -} diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java index 51671fdf25d..915d329d33d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,7 +91,7 @@ public final class AESKeyGenerator extends KeyGeneratorSpi { */ protected void engineInit(int keysize, SecureRandom random) { if (((keysize % 8) != 0) || - (!AESCrypt.isKeySizeValid(keysize/8))) { + (!AES_Crypt.isKeySizeValid(keysize/8))) { throw new InvalidParameterException ("Wrong keysize: must be equal to 128, 192 or 256"); } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java index 7ba4420f973..2828183802f 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ class AESKeyWrap extends FeedbackCipher { }; AESKeyWrap() { - super(new AESCrypt()); + super(new AES_Crypt()); } /** diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java index 4f25849d850..f6fec405b2f 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ class AESKeyWrapPadded extends FeedbackCipher { } AESKeyWrapPadded() { - super(new AESCrypt()); + super(new AES_Crypt()); } /** diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java b/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java new file mode 100644 index 00000000000..6e3e6144aff --- /dev/null +++ b/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java @@ -0,0 +1,1392 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.crypto.provider; + +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.util.Arrays; + +import jdk.internal.vm.annotation.IntrinsicCandidate; + +/** + * Implementation of the AES cipher, which is based on the following documents: + * + * @spec https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf + * + * @spec https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf + * + * https://www.internationaljournalcorner.com/index.php/ijird_ojs/article/view/134688 + */ +final class AES_Crypt extends SymmetricCipher { + + // Number of words in a block + private static final int WB = 4; + // Number of bytes in a word + private static final int BW = 4; + + private static final int AES_128_ROUNDS = 10; + private static final int AES_192_ROUNDS = 12; + private static final int AES_256_ROUNDS = 14; + + private int rounds; + private byte[] prevKey = null; + + // Following two attributes are specific to Intrinsics where sessionK is + // used for PPC64, S390, and RISCV64 architectures, whereas K is used for + // everything else. + private int[][] sessionK = null; + private int[] K = null; + + // Round constant + private static final int[] RCON = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, + }; + + private static final byte[][] SBOX = { + { (byte)0x63, (byte)0x7C, (byte)0x77, (byte)0x7B, (byte)0xF2, + (byte)0x6B, (byte)0x6F, (byte)0xC5, (byte)0x30, (byte)0x01, + (byte)0x67, (byte)0x2B, (byte)0xFE, (byte)0xD7, (byte)0xAB, + (byte)0x76 }, + { (byte)0xCA, (byte)0x82, (byte)0xC9, (byte)0x7D, (byte)0xFA, + (byte)0x59, (byte)0x47, (byte)0xF0, (byte)0xAD, (byte)0xD4, + (byte)0xA2, (byte)0xAF, (byte)0x9C, (byte)0xA4, (byte)0x72, + (byte)0xC0 }, + { (byte)0xB7, (byte)0xFD, (byte)0x93, (byte)0x26, (byte)0x36, + (byte)0x3F, (byte)0xF7, (byte)0xCC, (byte)0x34, (byte)0xA5, + (byte)0xE5, (byte)0xF1, (byte)0x71, (byte)0xD8, (byte)0x31, + (byte)0x15 }, + { (byte)0x04, (byte)0xC7, (byte)0x23, (byte)0xC3, (byte)0x18, + (byte)0x96, (byte)0x05, (byte)0x9A, (byte)0x07, (byte)0x12, + (byte)0x80, (byte)0xE2, (byte)0xEB, (byte)0x27, (byte)0xB2, + (byte)0x75 }, + { (byte)0x09, (byte)0x83, (byte)0x2C, (byte)0x1A, (byte)0x1B, + (byte)0x6E, (byte)0x5A, (byte)0xA0, (byte)0x52, (byte)0x3B, + (byte)0xD6, (byte)0xB3, (byte)0x29, (byte)0xE3, (byte)0x2F, + (byte)0x84 }, + { (byte)0x53, (byte)0xD1, (byte)0x00, (byte)0xED, (byte)0x20, + (byte)0xFC, (byte)0xB1, (byte)0x5B, (byte)0x6A, (byte)0xCB, + (byte)0xBE, (byte)0x39, (byte)0x4A, (byte)0x4C, (byte)0x58, + (byte)0xCF }, + { (byte)0xD0, (byte)0xEF, (byte)0xAA, (byte)0xFB, (byte)0x43, + (byte)0x4D, (byte)0x33, (byte)0x85, (byte)0x45, (byte)0xF9, + (byte)0x02, (byte)0x7F, (byte)0x50, (byte)0x3C, (byte)0x9F, + (byte)0xA8 }, + { (byte)0x51, (byte)0xA3, (byte)0x40, (byte)0x8F, (byte)0x92, + (byte)0x9D, (byte)0x38, (byte)0xF5, (byte)0xBC, (byte)0xB6, + (byte)0xDA, (byte)0x21, (byte)0x10, (byte)0xFF, (byte)0xF3, + (byte)0xD2 }, + { (byte)0xCD, (byte)0x0C, (byte)0x13, (byte)0xEC, (byte)0x5F, + (byte)0x97, (byte)0x44, (byte)0x17, (byte)0xC4, (byte)0xA7, + (byte)0x7E, (byte)0x3D, (byte)0x64, (byte)0x5D, (byte)0x19, + (byte)0x73 }, + { (byte)0x60, (byte)0x81, (byte)0x4F, (byte)0xDC, (byte)0x22, + (byte)0x2A, (byte)0x90, (byte)0x88, (byte)0x46, (byte)0xEE, + (byte)0xB8, (byte)0x14, (byte)0xDE, (byte)0x5E, (byte)0x0B, + (byte)0xDB }, + { (byte)0xE0, (byte)0x32, (byte)0x3A, (byte)0x0A, (byte)0x49, + (byte)0x06, (byte)0x24, (byte)0x5C, (byte)0xC2, (byte)0xD3, + (byte)0xAC, (byte)0x62, (byte)0x91, (byte)0x95, (byte)0xE4, + (byte)0x79 }, + { (byte)0xE7, (byte)0xC8, (byte)0x37, (byte)0x6D, (byte)0x8D, + (byte)0xD5, (byte)0x4E, (byte)0xA9, (byte)0x6C, (byte)0x56, + (byte)0xF4, (byte)0xEA, (byte)0x65, (byte)0x7A, (byte)0xAE, + (byte)0x08 }, + { (byte)0xBA, (byte)0x78, (byte)0x25, (byte)0x2E, (byte)0x1C, + (byte)0xA6, (byte)0xB4, (byte)0xC6, (byte)0xE8, (byte)0xDD, + (byte)0x74, (byte)0x1F, (byte)0x4B, (byte)0xBD, (byte)0x8B, + (byte)0x8A }, + { (byte)0x70, (byte)0x3E, (byte)0xB5, (byte)0x66, (byte)0x48, + (byte)0x03, (byte)0xF6, (byte)0x0E, (byte)0x61, (byte)0x35, + (byte)0x57, (byte)0xB9, (byte)0x86, (byte)0xC1, (byte)0x1D, + (byte)0x9E }, + { (byte)0xE1, (byte)0xF8, (byte)0x98, (byte)0x11, (byte)0x69, + (byte)0xD9, (byte)0x8E, (byte)0x94, (byte)0x9B, (byte)0x1E, + (byte)0x87, (byte)0xE9, (byte)0xCE, (byte)0x55, (byte)0x28, + (byte)0xDF }, + { (byte)0x8C, (byte)0xA1, (byte)0x89, (byte)0x0D, (byte)0xBF, + (byte)0xE6, (byte)0x42, (byte)0x68, (byte)0x41, (byte)0x99, + (byte)0x2D, (byte)0x0F, (byte)0xB0, (byte)0x54, (byte)0xBB, + (byte)0x16 } + }; + + // Lookup table for row 0 transforms, see section 5.2.1 of original spec. + private static final int[] T0 = { + 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, + 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, 0x60303050, 0x02010103, + 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, + 0xEC76769A, 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, + 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, 0x41ADADEC, + 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, + 0xE4727296, 0x9BC0C05B, 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, + 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, + 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, + 0xABD8D873, 0x62313153, 0x2A15153F, 0x0804040C, 0x95C7C752, + 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, + 0x2F9A9AB5, 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, + 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 0x1209091B, + 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, + 0xB45A5AEE, 0x5BA0A0FB, 0xA45252F6, 0x763B3B4D, 0xB7D6D661, + 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, + 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, + 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, 0xD46A6ABE, 0x8DCBCB46, + 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, + 0x85CFCF4A, 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, + 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, 0x8A4545CF, + 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, + 0x259F9FBA, 0x4BA8A8E3, 0xA25151F3, 0x5DA3A3FE, 0x804040C0, + 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, + 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, + 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, 0x81CDCD4C, 0x180C0C14, + 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, + 0x2E171739, 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, + 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, 0xC06060A0, + 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, + 0x3B9090AB, 0x0B888883, 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, + 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, + 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, + 0x0C06060A, 0x4824246C, 0xB85C5CE4, 0x9FC2C25D, 0xBDD3D36E, + 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, + 0xF279798B, 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, + 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, 0xD86C6CB4, + 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, + 0x47AEAEE9, 0x10080818, 0x6FBABAD5, 0xF0787888, 0x4A25256F, + 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, + 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, + 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, 0xE0707090, 0x7C3E3E42, + 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, + 0x1C0E0E12, 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, + 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, 0xD9E1E138, + 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, + 0x078E8E89, 0x339494A7, 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, + 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, + 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, + 0xD7E6E631, 0x844242C6, 0xD06868B8, 0x824141C3, 0x299999B0, + 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, + 0x2C16163A, + }; + + // Lookup table for row 1 transforms, see section 5.2.1 of original spec. + private static final int[] T1 = { + 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, + 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, 0x50603030, 0x03020101, + 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, + 0x9AEC7676, 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, + 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, 0xEC41ADAD, + 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, + 0x96E47272, 0x5B9BC0C0, 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, + 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, + 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, + 0x73ABD8D8, 0x53623131, 0x3F2A1515, 0x0C080404, 0x5295C7C7, + 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, + 0xB52F9A9A, 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, + 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, 0x1B120909, + 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, + 0xEEB45A5A, 0xFB5BA0A0, 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, + 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, + 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, + 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, 0xBED46A6A, 0x468DCBCB, + 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, + 0x4A85CFCF, 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, + 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, 0xCF8A4545, + 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, + 0xBA259F9F, 0xE34BA8A8, 0xF3A25151, 0xFE5DA3A3, 0xC0804040, + 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, + 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, + 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, 0x4C81CDCD, 0x14180C0C, + 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, + 0x392E1717, 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, + 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, 0xA0C06060, + 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, + 0xAB3B9090, 0x830B8888, 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, + 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, + 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, + 0x0A0C0606, 0x6C482424, 0xE4B85C5C, 0x5D9FC2C2, 0x6EBDD3D3, + 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, + 0x8BF27979, 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, + 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, 0xB4D86C6C, + 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, + 0xE947AEAE, 0x18100808, 0xD56FBABA, 0x88F07878, 0x6F4A2525, + 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, + 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, + 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, 0x90E07070, 0x427C3E3E, + 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, + 0x121C0E0E, 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, + 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, 0x38D9E1E1, + 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, + 0x89078E8E, 0xA7339494, 0xB62D9B9B, 0x223C1E1E, 0x92158787, + 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, + 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, + 0x31D7E6E6, 0xC6844242, 0xB8D06868, 0xC3824141, 0xB0299999, + 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, + 0x3A2C1616, + }; + + // Lookup table for row 2 transforms, see section 5.2.1 of original spec. + private static final int[] T2 = { + 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, + 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, 0x30506030, 0x01030201, + 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, + 0x769AEC76, 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, + 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, 0xADEC41AD, + 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, + 0x7296E472, 0xC05B9BC0, 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, + 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, + 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, + 0xD873ABD8, 0x31536231, 0x153F2A15, 0x040C0804, 0xC75295C7, + 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, + 0x9AB52F9A, 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, + 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, 0x091B1209, + 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, + 0x5AEEB45A, 0xA0FB5BA0, 0x52F6A452, 0x3B4D763B, 0xD661B7D6, + 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, + 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, + 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, 0x6ABED46A, 0xCB468DCB, + 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, + 0xCF4A85CF, 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, + 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, 0x45CF8A45, + 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, + 0x9FBA259F, 0xA8E34BA8, 0x51F3A251, 0xA3FE5DA3, 0x40C08040, + 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, + 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, + 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, 0xCD4C81CD, 0x0C14180C, + 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, + 0x17392E17, 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, + 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, 0x60A0C060, + 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, + 0x90AB3B90, 0x88830B88, 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, + 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, + 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, + 0x060A0C06, 0x246C4824, 0x5CE4B85C, 0xC25D9FC2, 0xD36EBDD3, + 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, + 0x798BF279, 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, + 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, 0x6CB4D86C, + 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, + 0xAEE947AE, 0x08181008, 0xBAD56FBA, 0x7888F078, 0x256F4A25, + 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, + 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, + 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, 0x7090E070, 0x3E427C3E, + 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, + 0x0E121C0E, 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, + 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, 0xE138D9E1, + 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, + 0x8E89078E, 0x94A73394, 0x9BB62D9B, 0x1E223C1E, 0x87921587, + 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, + 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, + 0xE631D7E6, 0x42C68442, 0x68B8D068, 0x41C38241, 0x99B02999, + 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, + 0x163A2C16, + }; + + // Lookup table for row 3 transforms, see section 5.2.1 of original spec. + private static final int[] T3 = { + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, + 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, 0x30305060, 0x01010302, + 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, + 0x76769AEC, 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, + 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, 0xADADEC41, + 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, + 0x727296E4, 0xC0C05B9B, 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, + 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, + 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, + 0xD8D873AB, 0x31315362, 0x15153F2A, 0x04040C08, 0xC7C75295, + 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, + 0x9A9AB52F, 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, + 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 0x09091B12, + 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, + 0x5A5AEEB4, 0xA0A0FB5B, 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, + 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, + 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, + 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 0x6A6ABED4, 0xCBCB468D, + 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, + 0xCFCF4A85, 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, + 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, 0x4545CF8A, + 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, + 0x9F9FBA25, 0xA8A8E34B, 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, + 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, + 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, 0xCDCD4C81, 0x0C0C1418, + 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, + 0x1717392E, 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, + 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, 0x6060A0C0, + 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, + 0x9090AB3B, 0x8888830B, 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, + 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, + 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, + 0x06060A0C, 0x24246C48, 0x5C5CE4B8, 0xC2C25D9F, 0xD3D36EBD, + 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, + 0x79798BF2, 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, + 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 0x6C6CB4D8, + 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, + 0xAEAEE947, 0x08081810, 0xBABAD56F, 0x787888F0, 0x25256F4A, + 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, + 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, + 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 0x707090E0, 0x3E3E427C, + 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, + 0x0E0E121C, 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, + 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, 0xE1E138D9, + 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, + 0x8E8E8907, 0x9494A733, 0x9B9BB62D, 0x1E1E223C, 0x87879215, + 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, + 0xE6E631D7, 0x4242C684, 0x6868B8D0, 0x4141C382, 0x9999B029, + 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, + 0x16163A2C, + }; + + // Lookup table for row 0 inverse transforms, see section 5.2.1 of original + // spec. + private static final int[] TI0 = { + 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, + 0x1F9D45F1, 0xACFA58AB, 0x4BE30393, 0x2030FA55, 0xAD766DF6, + 0x88CC7691, 0xF5024C25, 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, + 0xB562A38F, 0xDEB15A49, 0x25BA1B67, 0x45EA0E98, 0x5DFEC0E1, + 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, 0x038F5FE7, + 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, + 0x49E06929, 0x8EC9C844, 0x75C2896A, 0xF48E7978, 0x99583E6B, + 0x27B971DD, 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, + 0x63DF4A18, 0xE51A3182, 0x97513360, 0x62537F45, 0xB16477E0, + 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, 0x70486858, 0x8F45FD19, + 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, 0xE31F8F57, + 0x6655AB2A, 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, + 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, 0x8ACF1C2B, + 0xA779B492, 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, + 0xD134621F, 0xC4A6FE8A, 0x342E539D, 0xA2F355A0, 0x058AE132, + 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, 0x5E719F06, 0xBD6E1051, + 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, 0x91548DB5, + 0x71C45D05, 0x0406D46F, 0x605015FF, 0x1998FB24, 0xD6BDE997, + 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, + 0x79C8EEDB, 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, + 0x09808683, 0x322BED48, 0x1E1170AC, 0x6C5A724E, 0xFD0EFFFB, + 0x0F853856, 0x3DAED51E, 0x362D3927, 0x0A0FD964, 0x685CA621, + 0x9B5B54D1, 0x24362E3A, 0x0C0A67B1, 0x9357E70F, 0xB4EE96D2, + 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, + 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, + 0xF28BC7AD, 0x2DB6A8B9, 0x141EA9C8, 0x57F11985, 0xAF75074C, + 0xEE99DDBB, 0xA37F60FD, 0xF701269F, 0x5C72F5BC, 0x44663BC5, + 0x5BFB7E34, 0x8B432976, 0xCB23C6DC, 0xB6EDFC68, 0xB8E4F163, + 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, 0x854A247D, + 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, + 0x0D8652EC, 0x77C1E3D0, 0x2BB3166C, 0xA970B999, 0x119448FA, + 0x47E96422, 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, + 0x87494EC7, 0xD938D1C1, 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, + 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, 0x2C3A9DE4, 0x5078920D, + 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, 0x2E39F75E, + 0x82C3AFF5, 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, + 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, 0xCD267809, + 0x6E5918F4, 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, + 0x21BCCF08, 0xEF15E8E6, 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, + 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, 0xC6A59430, 0x35A266C0, + 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, 0xF104984A, + 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, 0x764DD68D, 0x43EFB04D, + 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, + 0x4665517F, 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, + 0xB3671D5A, 0x92DBD252, 0xE9105633, 0x6DD64713, 0x9AD7618C, + 0x37A10C7A, 0x59F8148E, 0xEB133C89, 0xCEA927EE, 0xB761C935, + 0xE11CE5ED, 0x7A47B13C, 0x9CD2DF59, 0x55F2733F, 0x1814CE79, + 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, + 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, + 0xBCE2250C, 0x283C498B, 0xFF0D9541, 0x39A80171, 0x080CB3DE, + 0xD8B4E49C, 0x6456C190, 0x7BCB8461, 0xD532B670, 0x486C5C74, + 0xD0B85742, + }; + + // Lookup table for row 1 inverse transforms, see section 5.2.1 of original + // spec. + private static final int[] TI1 = { + 0x5051F4A7, 0x537E4165, 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, + 0xF11F9D45, 0xABACFA58, 0x934BE303, 0x552030FA, 0xF6AD766D, + 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, 0x80263544, + 0x8FB562A3, 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, + 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, 0xE7038F5F, + 0x9515929C, 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, + 0x2949E069, 0x448EC9C8, 0x6A75C289, 0x78F48E79, 0x6B99583E, + 0xDD27B971, 0xB6BEE14F, 0x17F088AD, 0x66C920AC, 0xB47DCE3A, + 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, 0xE0B16477, + 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, 0x58704868, 0x198F45FD, + 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, + 0x2A6655AB, 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, + 0xF2302887, 0xB223BFA5, 0xBA02036A, 0x5CED1682, 0x2B8ACF1C, + 0x92A779B4, 0xF0F307F2, 0xA14E69E2, 0xCD65DAF4, 0xD50605BE, + 0x1FD13462, 0x8AC4A6FE, 0x9D342E53, 0xA0A2F355, 0x32058AE1, + 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, + 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, + 0x0571C45D, 0x6F0406D4, 0xFF605015, 0x241998FB, 0x97D6BDE9, + 0xCC894043, 0x7767D99E, 0xBDB0E842, 0x8807898B, 0x38E7195B, + 0xDB79C8EE, 0x47A17C0A, 0xE97C420F, 0xC9F8841E, 0x00000000, + 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, 0xFBFD0EFF, + 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, + 0xD19B5B54, 0x3A24362E, 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, + 0x9E1B9B91, 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, + 0x0AE293BA, 0xE5C0A02A, 0x433C22E0, 0x1D121B17, 0x0B0E090D, + 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, 0x8557F119, 0x4CAF7507, + 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, 0xC544663B, + 0x345BFB7E, 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, + 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, 0x7D854A24, + 0xF8D2BB3D, 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, + 0xEC0D8652, 0xD077C1E3, 0x6C2BB316, 0x99A970B9, 0xFA119448, + 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, 0xD8567D2C, 0xEF223390, + 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, 0xCFA6F581, + 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, 0xE42C3A9D, 0x0D507892, + 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, + 0xF582C3AF, 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, + 0x3BC8AC99, 0xA710187D, 0x6EE89C63, 0x7BDB3BBB, 0x09CD2678, + 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, 0x65E6956E, 0x7EAAFFE6, + 0x0821BCCF, 0xE6EF15E8, 0xD9BAE79B, 0xCE4A6F36, 0xD4EA9F09, + 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, + 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, + 0xF741ECDA, 0x0E7FCD50, 0x2F1791F6, 0x8D764DD6, 0x4D43EFB0, + 0x54CCAA4D, 0xDFE49604, 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, + 0x7F466551, 0x049D5EEA, 0x5D018C35, 0x73FA8774, 0x2EFB0B41, + 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, 0x8C9AD761, + 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, + 0xEDE11CE5, 0x3C7A47B1, 0x599CD2DF, 0x3F55F273, 0x791814CE, + 0xBF73C737, 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, + 0x81CAAFF3, 0x3EB968C4, 0x2C382434, 0x5FC2A340, 0x72161DC3, + 0x0CBCE225, 0x8B283C49, 0x41FF0D95, 0x7139A801, 0xDE080CB3, + 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, 0x74486C5C, + 0x42D0B857, + }; + + // Lookup table for row 2 inverse transforms, see section 5.2.1 of original + // spec. + private static final int[] TI2 = { + 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, 0x6BCB3BAB, + 0x45F11F9D, 0x58ABACFA, 0x03934BE3, 0xFA552030, 0x6DF6AD76, + 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, + 0xA38FB562, 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, + 0x7502C32F, 0xF012814C, 0x97A38D46, 0xF9C66BD3, 0x5FE7038F, + 0x9C951592, 0x7AEBBF6D, 0x59DA9552, 0x832DD4BE, 0x21D35874, + 0x692949E0, 0xC8448EC9, 0x896A75C2, 0x7978F48E, 0x3E6B9958, + 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, + 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, + 0xAE84BB6B, 0xA01CFE81, 0x2B94F908, 0x68587048, 0xFD198F45, + 0x6C8794DE, 0xF8B7527B, 0xD323AB73, 0x02E2724B, 0x8F57E31F, + 0xAB2A6655, 0x2807B2EB, 0xC2032FB5, 0x7B9A86C5, 0x08A5D337, + 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, 0x1C2B8ACF, + 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, + 0x621FD134, 0xFE8AC4A6, 0x539D342E, 0x55A0A2F3, 0xE132058A, + 0xEB75A4F6, 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, + 0x8AF93E21, 0x063D96DD, 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, + 0x5D0571C4, 0xD46F0406, 0x15FF6050, 0xFB241998, 0xE997D6BD, + 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, 0x5B38E719, + 0xEEDB79C8, 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, + 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, 0xFFFBFD0E, + 0x38560F85, 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, + 0x54D19B5B, 0x2E3A2436, 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, + 0x919E1B9B, 0xC54F80C0, 0x20A261DC, 0x4B695A77, 0x1A161C12, + 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, 0x0D0B0E09, + 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, 0x198557F1, 0x074CAF75, + 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, + 0x7E345BFB, 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, + 0xDCCAD731, 0x85104263, 0x22401397, 0x112084C6, 0x247D854A, + 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, 0x2F4B1D9E, 0x30F3DCB2, + 0x52EC0D86, 0xE3D077C1, 0x166C2BB3, 0xB999A970, 0x48FA1194, + 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, + 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, + 0xDE28A57A, 0x8E26DAB7, 0xBFA43FAD, 0x9DE42C3A, 0x920D5078, + 0xCC9B6A5F, 0x4662547E, 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, + 0xAFF582C3, 0x80BE9F5D, 0x937C69D0, 0x2DA96FD5, 0x12B3CF25, + 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, 0x7809CD26, + 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, + 0xCF0821BC, 0xE8E6EF15, 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, + 0x7CD629B0, 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, + 0xBC37744E, 0xCAA6FC82, 0xD0B0E090, 0xD81533A7, 0x984AF104, + 0xDAF741EC, 0x500E7FCD, 0xF62F1791, 0xD68D764D, 0xB04D43EF, + 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, 0x1FB8C12C, + 0x517F4665, 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, + 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, 0x618C9AD7, + 0x0C7A37A1, 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, + 0xE5EDE11C, 0xB13C7A47, 0xDF599CD2, 0x733F55F2, 0xCE791814, + 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, 0x6F14DF3D, 0xDB867844, + 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, 0xC372161D, + 0x250CBCE2, 0x498B283C, 0x9541FF0D, 0x017139A8, 0xB3DE080C, + 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, + 0x5742D0B8, + }; + + // Lookup table for row 3 inverse transforms, see section 5.2.1 of original + // spec. + private static final int[] TI3 = { + 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, + 0x9D45F11F, 0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, + 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, + 0x62A38FB5, 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, + 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, 0x8F5FE703, + 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, + 0xE0692949, 0xC9C8448E, 0xC2896A75, 0x8E7978F4, 0x583E6B99, + 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, + 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, + 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, 0x48685870, 0x45FD198F, + 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, + 0x55AB2A66, 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, + 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 0xCF1C2B8A, + 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, + 0x34621FD1, 0xA6FE8AC4, 0x2E539D34, 0xF355A0A2, 0x8AE13205, + 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, + 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, + 0xC45D0571, 0x06D46F04, 0x5015FF60, 0x98FB2419, 0xBDE997D6, + 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, + 0xC8EEDB79, 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, + 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, 0x0EFFFBFD, + 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, + 0x5B54D19B, 0x362E3A24, 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, + 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, + 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, + 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, 0xF1198557, 0x75074CAF, + 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, + 0xFB7E345B, 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, + 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, 0x4A247D85, + 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, + 0x8652EC0D, 0xC1E3D077, 0xB3166C2B, 0x70B999A9, 0x9448FA11, + 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, + 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, + 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, 0x3A9DE42C, 0x78920D50, + 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, + 0xC3AFF582, 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, + 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 0x267809CD, + 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, + 0xBCCF0821, 0x15E8E6EF, 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, + 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, + 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, + 0xECDAF741, 0xCD500E7F, 0x91F62F17, 0x4DD68D76, 0xEFB04D43, + 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, + 0x65517F46, 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, + 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, 0xD7618C9A, + 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, + 0x1CE5EDE1, 0x47B13C7A, 0xD2DF599C, 0xF2733F55, 0x14CE7918, + 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, + 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, + 0xE2250CBC, 0x3C498B28, 0x0D9541FF, 0xA8017139, 0x0CB3DE08, + 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, + 0xB85742D0, + }; + + // Lookup table for inverse substitution transform of last round as + // described in the international journal article referenced. + private static final int[] TI4 = { + 0x52525252, 0x09090909, 0x6A6A6A6A, 0xD5D5D5D5, 0x30303030, + 0x36363636, 0xA5A5A5A5, 0x38383838, 0xBFBFBFBF, 0x40404040, + 0xA3A3A3A3, 0x9E9E9E9E, 0x81818181, 0xF3F3F3F3, 0xD7D7D7D7, + 0xFBFBFBFB, 0x7C7C7C7C, 0xE3E3E3E3, 0x39393939, 0x82828282, + 0x9B9B9B9B, 0x2F2F2F2F, 0xFFFFFFFF, 0x87878787, 0x34343434, + 0x8E8E8E8E, 0x43434343, 0x44444444, 0xC4C4C4C4, 0xDEDEDEDE, + 0xE9E9E9E9, 0xCBCBCBCB, 0x54545454, 0x7B7B7B7B, 0x94949494, + 0x32323232, 0xA6A6A6A6, 0xC2C2C2C2, 0x23232323, 0x3D3D3D3D, + 0xEEEEEEEE, 0x4C4C4C4C, 0x95959595, 0x0B0B0B0B, 0x42424242, + 0xFAFAFAFA, 0xC3C3C3C3, 0x4E4E4E4E, 0x08080808, 0x2E2E2E2E, + 0xA1A1A1A1, 0x66666666, 0x28282828, 0xD9D9D9D9, 0x24242424, + 0xB2B2B2B2, 0x76767676, 0x5B5B5B5B, 0xA2A2A2A2, 0x49494949, + 0x6D6D6D6D, 0x8B8B8B8B, 0xD1D1D1D1, 0x25252525, 0x72727272, + 0xF8F8F8F8, 0xF6F6F6F6, 0x64646464, 0x86868686, 0x68686868, + 0x98989898, 0x16161616, 0xD4D4D4D4, 0xA4A4A4A4, 0x5C5C5C5C, + 0xCCCCCCCC, 0x5D5D5D5D, 0x65656565, 0xB6B6B6B6, 0x92929292, + 0x6C6C6C6C, 0x70707070, 0x48484848, 0x50505050, 0xFDFDFDFD, + 0xEDEDEDED, 0xB9B9B9B9, 0xDADADADA, 0x5E5E5E5E, 0x15151515, + 0x46464646, 0x57575757, 0xA7A7A7A7, 0x8D8D8D8D, 0x9D9D9D9D, + 0x84848484, 0x90909090, 0xD8D8D8D8, 0xABABABAB, 0x00000000, + 0x8C8C8C8C, 0xBCBCBCBC, 0xD3D3D3D3, 0x0A0A0A0A, 0xF7F7F7F7, + 0xE4E4E4E4, 0x58585858, 0x05050505, 0xB8B8B8B8, 0xB3B3B3B3, + 0x45454545, 0x06060606, 0xD0D0D0D0, 0x2C2C2C2C, 0x1E1E1E1E, + 0x8F8F8F8F, 0xCACACACA, 0x3F3F3F3F, 0x0F0F0F0F, 0x02020202, + 0xC1C1C1C1, 0xAFAFAFAF, 0xBDBDBDBD, 0x03030303, 0x01010101, + 0x13131313, 0x8A8A8A8A, 0x6B6B6B6B, 0x3A3A3A3A, 0x91919191, + 0x11111111, 0x41414141, 0x4F4F4F4F, 0x67676767, 0xDCDCDCDC, + 0xEAEAEAEA, 0x97979797, 0xF2F2F2F2, 0xCFCFCFCF, 0xCECECECE, + 0xF0F0F0F0, 0xB4B4B4B4, 0xE6E6E6E6, 0x73737373, 0x96969696, + 0xACACACAC, 0x74747474, 0x22222222, 0xE7E7E7E7, 0xADADADAD, + 0x35353535, 0x85858585, 0xE2E2E2E2, 0xF9F9F9F9, 0x37373737, + 0xE8E8E8E8, 0x1C1C1C1C, 0x75757575, 0xDFDFDFDF, 0x6E6E6E6E, + 0x47474747, 0xF1F1F1F1, 0x1A1A1A1A, 0x71717171, 0x1D1D1D1D, + 0x29292929, 0xC5C5C5C5, 0x89898989, 0x6F6F6F6F, 0xB7B7B7B7, + 0x62626262, 0x0E0E0E0E, 0xAAAAAAAA, 0x18181818, 0xBEBEBEBE, + 0x1B1B1B1B, 0xFCFCFCFC, 0x56565656, 0x3E3E3E3E, 0x4B4B4B4B, + 0xC6C6C6C6, 0xD2D2D2D2, 0x79797979, 0x20202020, 0x9A9A9A9A, + 0xDBDBDBDB, 0xC0C0C0C0, 0xFEFEFEFE, 0x78787878, 0xCDCDCDCD, + 0x5A5A5A5A, 0xF4F4F4F4, 0x1F1F1F1F, 0xDDDDDDDD, 0xA8A8A8A8, + 0x33333333, 0x88888888, 0x07070707, 0xC7C7C7C7, 0x31313131, + 0xB1B1B1B1, 0x12121212, 0x10101010, 0x59595959, 0x27272727, + 0x80808080, 0xECECECEC, 0x5F5F5F5F, 0x60606060, 0x51515151, + 0x7F7F7F7F, 0xA9A9A9A9, 0x19191919, 0xB5B5B5B5, 0x4A4A4A4A, + 0x0D0D0D0D, 0x2D2D2D2D, 0xE5E5E5E5, 0x7A7A7A7A, 0x9F9F9F9F, + 0x93939393, 0xC9C9C9C9, 0x9C9C9C9C, 0xEFEFEFEF, 0xA0A0A0A0, + 0xE0E0E0E0, 0x3B3B3B3B, 0x4D4D4D4D, 0xAEAEAEAE, 0x2A2A2A2A, + 0xF5F5F5F5, 0xB0B0B0B0, 0xC8C8C8C8, 0xEBEBEBEB, 0xBBBBBBBB, + 0x3C3C3C3C, 0x83838383, 0x53535353, 0x99999999, 0x61616161, + 0x17171717, 0x2B2B2B2B, 0x04040404, 0x7E7E7E7E, 0xBABABABA, + 0x77777777, 0xD6D6D6D6, 0x26262626, 0xE1E1E1E1, 0x69696969, + 0x14141414, 0x63636363, 0x55555555, 0x21212121, 0x0C0C0C0C, + 0x7D7D7D7D, + }; + + // Lookup table for row 0 of the inverse mix column transform. + private static final int[] TMI0 = { + 0x00000000, 0x0E090D0B, 0x1C121A16, 0x121B171D, 0x3824342C, + 0x362D3927, 0x24362E3A, 0x2A3F2331, 0x70486858, 0x7E416553, + 0x6C5A724E, 0x62537F45, 0x486C5C74, 0x4665517F, 0x547E4662, + 0x5A774B69, 0xE090D0B0, 0xEE99DDBB, 0xFC82CAA6, 0xF28BC7AD, + 0xD8B4E49C, 0xD6BDE997, 0xC4A6FE8A, 0xCAAFF381, 0x90D8B8E8, + 0x9ED1B5E3, 0x8CCAA2FE, 0x82C3AFF5, 0xA8FC8CC4, 0xA6F581CF, + 0xB4EE96D2, 0xBAE79BD9, 0xDB3BBB7B, 0xD532B670, 0xC729A16D, + 0xC920AC66, 0xE31F8F57, 0xED16825C, 0xFF0D9541, 0xF104984A, + 0xAB73D323, 0xA57ADE28, 0xB761C935, 0xB968C43E, 0x9357E70F, + 0x9D5EEA04, 0x8F45FD19, 0x814CF012, 0x3BAB6BCB, 0x35A266C0, + 0x27B971DD, 0x29B07CD6, 0x038F5FE7, 0x0D8652EC, 0x1F9D45F1, + 0x119448FA, 0x4BE30393, 0x45EA0E98, 0x57F11985, 0x59F8148E, + 0x73C737BF, 0x7DCE3AB4, 0x6FD52DA9, 0x61DC20A2, 0xAD766DF6, + 0xA37F60FD, 0xB16477E0, 0xBF6D7AEB, 0x955259DA, 0x9B5B54D1, + 0x894043CC, 0x87494EC7, 0xDD3E05AE, 0xD33708A5, 0xC12C1FB8, + 0xCF2512B3, 0xE51A3182, 0xEB133C89, 0xF9082B94, 0xF701269F, + 0x4DE6BD46, 0x43EFB04D, 0x51F4A750, 0x5FFDAA5B, 0x75C2896A, + 0x7BCB8461, 0x69D0937C, 0x67D99E77, 0x3DAED51E, 0x33A7D815, + 0x21BCCF08, 0x2FB5C203, 0x058AE132, 0x0B83EC39, 0x1998FB24, + 0x1791F62F, 0x764DD68D, 0x7844DB86, 0x6A5FCC9B, 0x6456C190, + 0x4E69E2A1, 0x4060EFAA, 0x527BF8B7, 0x5C72F5BC, 0x0605BED5, + 0x080CB3DE, 0x1A17A4C3, 0x141EA9C8, 0x3E218AF9, 0x302887F2, + 0x223390EF, 0x2C3A9DE4, 0x96DD063D, 0x98D40B36, 0x8ACF1C2B, + 0x84C61120, 0xAEF93211, 0xA0F03F1A, 0xB2EB2807, 0xBCE2250C, + 0xE6956E65, 0xE89C636E, 0xFA877473, 0xF48E7978, 0xDEB15A49, + 0xD0B85742, 0xC2A3405F, 0xCCAA4D54, 0x41ECDAF7, 0x4FE5D7FC, + 0x5DFEC0E1, 0x53F7CDEA, 0x79C8EEDB, 0x77C1E3D0, 0x65DAF4CD, + 0x6BD3F9C6, 0x31A4B2AF, 0x3FADBFA4, 0x2DB6A8B9, 0x23BFA5B2, + 0x09808683, 0x07898B88, 0x15929C95, 0x1B9B919E, 0xA17C0A47, + 0xAF75074C, 0xBD6E1051, 0xB3671D5A, 0x99583E6B, 0x97513360, + 0x854A247D, 0x8B432976, 0xD134621F, 0xDF3D6F14, 0xCD267809, + 0xC32F7502, 0xE9105633, 0xE7195B38, 0xF5024C25, 0xFB0B412E, + 0x9AD7618C, 0x94DE6C87, 0x86C57B9A, 0x88CC7691, 0xA2F355A0, + 0xACFA58AB, 0xBEE14FB6, 0xB0E842BD, 0xEA9F09D4, 0xE49604DF, + 0xF68D13C2, 0xF8841EC9, 0xD2BB3DF8, 0xDCB230F3, 0xCEA927EE, + 0xC0A02AE5, 0x7A47B13C, 0x744EBC37, 0x6655AB2A, 0x685CA621, + 0x42638510, 0x4C6A881B, 0x5E719F06, 0x5078920D, 0x0A0FD964, + 0x0406D46F, 0x161DC372, 0x1814CE79, 0x322BED48, 0x3C22E043, + 0x2E39F75E, 0x2030FA55, 0xEC9AB701, 0xE293BA0A, 0xF088AD17, + 0xFE81A01C, 0xD4BE832D, 0xDAB78E26, 0xC8AC993B, 0xC6A59430, + 0x9CD2DF59, 0x92DBD252, 0x80C0C54F, 0x8EC9C844, 0xA4F6EB75, + 0xAAFFE67E, 0xB8E4F163, 0xB6EDFC68, 0x0C0A67B1, 0x02036ABA, + 0x10187DA7, 0x1E1170AC, 0x342E539D, 0x3A275E96, 0x283C498B, + 0x26354480, 0x7C420FE9, 0x724B02E2, 0x605015FF, 0x6E5918F4, + 0x44663BC5, 0x4A6F36CE, 0x587421D3, 0x567D2CD8, 0x37A10C7A, + 0x39A80171, 0x2BB3166C, 0x25BA1B67, 0x0F853856, 0x018C355D, + 0x13972240, 0x1D9E2F4B, 0x47E96422, 0x49E06929, 0x5BFB7E34, + 0x55F2733F, 0x7FCD500E, 0x71C45D05, 0x63DF4A18, 0x6DD64713, + 0xD731DCCA, 0xD938D1C1, 0xCB23C6DC, 0xC52ACBD7, 0xEF15E8E6, + 0xE11CE5ED, 0xF307F2F0, 0xFD0EFFFB, 0xA779B492, 0xA970B999, + 0xBB6BAE84, 0xB562A38F, 0x9F5D80BE, 0x91548DB5, 0x834F9AA8, + 0x8D4697A3, + }; + + // Lookup table for row 1 of the inverse mix column transform. + private static final int[] TMI1 = { + 0x00000000, 0x0B0E090D, 0x161C121A, 0x1D121B17, 0x2C382434, + 0x27362D39, 0x3A24362E, 0x312A3F23, 0x58704868, 0x537E4165, + 0x4E6C5A72, 0x4562537F, 0x74486C5C, 0x7F466551, 0x62547E46, + 0x695A774B, 0xB0E090D0, 0xBBEE99DD, 0xA6FC82CA, 0xADF28BC7, + 0x9CD8B4E4, 0x97D6BDE9, 0x8AC4A6FE, 0x81CAAFF3, 0xE890D8B8, + 0xE39ED1B5, 0xFE8CCAA2, 0xF582C3AF, 0xC4A8FC8C, 0xCFA6F581, + 0xD2B4EE96, 0xD9BAE79B, 0x7BDB3BBB, 0x70D532B6, 0x6DC729A1, + 0x66C920AC, 0x57E31F8F, 0x5CED1682, 0x41FF0D95, 0x4AF10498, + 0x23AB73D3, 0x28A57ADE, 0x35B761C9, 0x3EB968C4, 0x0F9357E7, + 0x049D5EEA, 0x198F45FD, 0x12814CF0, 0xCB3BAB6B, 0xC035A266, + 0xDD27B971, 0xD629B07C, 0xE7038F5F, 0xEC0D8652, 0xF11F9D45, + 0xFA119448, 0x934BE303, 0x9845EA0E, 0x8557F119, 0x8E59F814, + 0xBF73C737, 0xB47DCE3A, 0xA96FD52D, 0xA261DC20, 0xF6AD766D, + 0xFDA37F60, 0xE0B16477, 0xEBBF6D7A, 0xDA955259, 0xD19B5B54, + 0xCC894043, 0xC787494E, 0xAEDD3E05, 0xA5D33708, 0xB8C12C1F, + 0xB3CF2512, 0x82E51A31, 0x89EB133C, 0x94F9082B, 0x9FF70126, + 0x464DE6BD, 0x4D43EFB0, 0x5051F4A7, 0x5B5FFDAA, 0x6A75C289, + 0x617BCB84, 0x7C69D093, 0x7767D99E, 0x1E3DAED5, 0x1533A7D8, + 0x0821BCCF, 0x032FB5C2, 0x32058AE1, 0x390B83EC, 0x241998FB, + 0x2F1791F6, 0x8D764DD6, 0x867844DB, 0x9B6A5FCC, 0x906456C1, + 0xA14E69E2, 0xAA4060EF, 0xB7527BF8, 0xBC5C72F5, 0xD50605BE, + 0xDE080CB3, 0xC31A17A4, 0xC8141EA9, 0xF93E218A, 0xF2302887, + 0xEF223390, 0xE42C3A9D, 0x3D96DD06, 0x3698D40B, 0x2B8ACF1C, + 0x2084C611, 0x11AEF932, 0x1AA0F03F, 0x07B2EB28, 0x0CBCE225, + 0x65E6956E, 0x6EE89C63, 0x73FA8774, 0x78F48E79, 0x49DEB15A, + 0x42D0B857, 0x5FC2A340, 0x54CCAA4D, 0xF741ECDA, 0xFC4FE5D7, + 0xE15DFEC0, 0xEA53F7CD, 0xDB79C8EE, 0xD077C1E3, 0xCD65DAF4, + 0xC66BD3F9, 0xAF31A4B2, 0xA43FADBF, 0xB92DB6A8, 0xB223BFA5, + 0x83098086, 0x8807898B, 0x9515929C, 0x9E1B9B91, 0x47A17C0A, + 0x4CAF7507, 0x51BD6E10, 0x5AB3671D, 0x6B99583E, 0x60975133, + 0x7D854A24, 0x768B4329, 0x1FD13462, 0x14DF3D6F, 0x09CD2678, + 0x02C32F75, 0x33E91056, 0x38E7195B, 0x25F5024C, 0x2EFB0B41, + 0x8C9AD761, 0x8794DE6C, 0x9A86C57B, 0x9188CC76, 0xA0A2F355, + 0xABACFA58, 0xB6BEE14F, 0xBDB0E842, 0xD4EA9F09, 0xDFE49604, + 0xC2F68D13, 0xC9F8841E, 0xF8D2BB3D, 0xF3DCB230, 0xEECEA927, + 0xE5C0A02A, 0x3C7A47B1, 0x37744EBC, 0x2A6655AB, 0x21685CA6, + 0x10426385, 0x1B4C6A88, 0x065E719F, 0x0D507892, 0x640A0FD9, + 0x6F0406D4, 0x72161DC3, 0x791814CE, 0x48322BED, 0x433C22E0, + 0x5E2E39F7, 0x552030FA, 0x01EC9AB7, 0x0AE293BA, 0x17F088AD, + 0x1CFE81A0, 0x2DD4BE83, 0x26DAB78E, 0x3BC8AC99, 0x30C6A594, + 0x599CD2DF, 0x5292DBD2, 0x4F80C0C5, 0x448EC9C8, 0x75A4F6EB, + 0x7EAAFFE6, 0x63B8E4F1, 0x68B6EDFC, 0xB10C0A67, 0xBA02036A, + 0xA710187D, 0xAC1E1170, 0x9D342E53, 0x963A275E, 0x8B283C49, + 0x80263544, 0xE97C420F, 0xE2724B02, 0xFF605015, 0xF46E5918, + 0xC544663B, 0xCE4A6F36, 0xD3587421, 0xD8567D2C, 0x7A37A10C, + 0x7139A801, 0x6C2BB316, 0x6725BA1B, 0x560F8538, 0x5D018C35, + 0x40139722, 0x4B1D9E2F, 0x2247E964, 0x2949E069, 0x345BFB7E, + 0x3F55F273, 0x0E7FCD50, 0x0571C45D, 0x1863DF4A, 0x136DD647, + 0xCAD731DC, 0xC1D938D1, 0xDCCB23C6, 0xD7C52ACB, 0xE6EF15E8, + 0xEDE11CE5, 0xF0F307F2, 0xFBFD0EFF, 0x92A779B4, 0x99A970B9, + 0x84BB6BAE, 0x8FB562A3, 0xBE9F5D80, 0xB591548D, 0xA8834F9A, + 0xA38D4697, + }; + + // Lookup table for row 2 of the inverse mix column transform. + private static final int[] TMI2 = { + 0x00000000, 0x0D0B0E09, 0x1A161C12, 0x171D121B, 0x342C3824, + 0x3927362D, 0x2E3A2436, 0x23312A3F, 0x68587048, 0x65537E41, + 0x724E6C5A, 0x7F456253, 0x5C74486C, 0x517F4665, 0x4662547E, + 0x4B695A77, 0xD0B0E090, 0xDDBBEE99, 0xCAA6FC82, 0xC7ADF28B, + 0xE49CD8B4, 0xE997D6BD, 0xFE8AC4A6, 0xF381CAAF, 0xB8E890D8, + 0xB5E39ED1, 0xA2FE8CCA, 0xAFF582C3, 0x8CC4A8FC, 0x81CFA6F5, + 0x96D2B4EE, 0x9BD9BAE7, 0xBB7BDB3B, 0xB670D532, 0xA16DC729, + 0xAC66C920, 0x8F57E31F, 0x825CED16, 0x9541FF0D, 0x984AF104, + 0xD323AB73, 0xDE28A57A, 0xC935B761, 0xC43EB968, 0xE70F9357, + 0xEA049D5E, 0xFD198F45, 0xF012814C, 0x6BCB3BAB, 0x66C035A2, + 0x71DD27B9, 0x7CD629B0, 0x5FE7038F, 0x52EC0D86, 0x45F11F9D, + 0x48FA1194, 0x03934BE3, 0x0E9845EA, 0x198557F1, 0x148E59F8, + 0x37BF73C7, 0x3AB47DCE, 0x2DA96FD5, 0x20A261DC, 0x6DF6AD76, + 0x60FDA37F, 0x77E0B164, 0x7AEBBF6D, 0x59DA9552, 0x54D19B5B, + 0x43CC8940, 0x4EC78749, 0x05AEDD3E, 0x08A5D337, 0x1FB8C12C, + 0x12B3CF25, 0x3182E51A, 0x3C89EB13, 0x2B94F908, 0x269FF701, + 0xBD464DE6, 0xB04D43EF, 0xA75051F4, 0xAA5B5FFD, 0x896A75C2, + 0x84617BCB, 0x937C69D0, 0x9E7767D9, 0xD51E3DAE, 0xD81533A7, + 0xCF0821BC, 0xC2032FB5, 0xE132058A, 0xEC390B83, 0xFB241998, + 0xF62F1791, 0xD68D764D, 0xDB867844, 0xCC9B6A5F, 0xC1906456, + 0xE2A14E69, 0xEFAA4060, 0xF8B7527B, 0xF5BC5C72, 0xBED50605, + 0xB3DE080C, 0xA4C31A17, 0xA9C8141E, 0x8AF93E21, 0x87F23028, + 0x90EF2233, 0x9DE42C3A, 0x063D96DD, 0x0B3698D4, 0x1C2B8ACF, + 0x112084C6, 0x3211AEF9, 0x3F1AA0F0, 0x2807B2EB, 0x250CBCE2, + 0x6E65E695, 0x636EE89C, 0x7473FA87, 0x7978F48E, 0x5A49DEB1, + 0x5742D0B8, 0x405FC2A3, 0x4D54CCAA, 0xDAF741EC, 0xD7FC4FE5, + 0xC0E15DFE, 0xCDEA53F7, 0xEEDB79C8, 0xE3D077C1, 0xF4CD65DA, + 0xF9C66BD3, 0xB2AF31A4, 0xBFA43FAD, 0xA8B92DB6, 0xA5B223BF, + 0x86830980, 0x8B880789, 0x9C951592, 0x919E1B9B, 0x0A47A17C, + 0x074CAF75, 0x1051BD6E, 0x1D5AB367, 0x3E6B9958, 0x33609751, + 0x247D854A, 0x29768B43, 0x621FD134, 0x6F14DF3D, 0x7809CD26, + 0x7502C32F, 0x5633E910, 0x5B38E719, 0x4C25F502, 0x412EFB0B, + 0x618C9AD7, 0x6C8794DE, 0x7B9A86C5, 0x769188CC, 0x55A0A2F3, + 0x58ABACFA, 0x4FB6BEE1, 0x42BDB0E8, 0x09D4EA9F, 0x04DFE496, + 0x13C2F68D, 0x1EC9F884, 0x3DF8D2BB, 0x30F3DCB2, 0x27EECEA9, + 0x2AE5C0A0, 0xB13C7A47, 0xBC37744E, 0xAB2A6655, 0xA621685C, + 0x85104263, 0x881B4C6A, 0x9F065E71, 0x920D5078, 0xD9640A0F, + 0xD46F0406, 0xC372161D, 0xCE791814, 0xED48322B, 0xE0433C22, + 0xF75E2E39, 0xFA552030, 0xB701EC9A, 0xBA0AE293, 0xAD17F088, + 0xA01CFE81, 0x832DD4BE, 0x8E26DAB7, 0x993BC8AC, 0x9430C6A5, + 0xDF599CD2, 0xD25292DB, 0xC54F80C0, 0xC8448EC9, 0xEB75A4F6, + 0xE67EAAFF, 0xF163B8E4, 0xFC68B6ED, 0x67B10C0A, 0x6ABA0203, + 0x7DA71018, 0x70AC1E11, 0x539D342E, 0x5E963A27, 0x498B283C, + 0x44802635, 0x0FE97C42, 0x02E2724B, 0x15FF6050, 0x18F46E59, + 0x3BC54466, 0x36CE4A6F, 0x21D35874, 0x2CD8567D, 0x0C7A37A1, + 0x017139A8, 0x166C2BB3, 0x1B6725BA, 0x38560F85, 0x355D018C, + 0x22401397, 0x2F4B1D9E, 0x642247E9, 0x692949E0, 0x7E345BFB, + 0x733F55F2, 0x500E7FCD, 0x5D0571C4, 0x4A1863DF, 0x47136DD6, + 0xDCCAD731, 0xD1C1D938, 0xC6DCCB23, 0xCBD7C52A, 0xE8E6EF15, + 0xE5EDE11C, 0xF2F0F307, 0xFFFBFD0E, 0xB492A779, 0xB999A970, + 0xAE84BB6B, 0xA38FB562, 0x80BE9F5D, 0x8DB59154, 0x9AA8834F, + 0x97A38D46, + }; + + // Lookup table for row 3 of the inverse mix column transform. + private static final int[] TMI3 = { + 0x00000000, 0x090D0B0E, 0x121A161C, 0x1B171D12, 0x24342C38, + 0x2D392736, 0x362E3A24, 0x3F23312A, 0x48685870, 0x4165537E, + 0x5A724E6C, 0x537F4562, 0x6C5C7448, 0x65517F46, 0x7E466254, + 0x774B695A, 0x90D0B0E0, 0x99DDBBEE, 0x82CAA6FC, 0x8BC7ADF2, + 0xB4E49CD8, 0xBDE997D6, 0xA6FE8AC4, 0xAFF381CA, 0xD8B8E890, + 0xD1B5E39E, 0xCAA2FE8C, 0xC3AFF582, 0xFC8CC4A8, 0xF581CFA6, + 0xEE96D2B4, 0xE79BD9BA, 0x3BBB7BDB, 0x32B670D5, 0x29A16DC7, + 0x20AC66C9, 0x1F8F57E3, 0x16825CED, 0x0D9541FF, 0x04984AF1, + 0x73D323AB, 0x7ADE28A5, 0x61C935B7, 0x68C43EB9, 0x57E70F93, + 0x5EEA049D, 0x45FD198F, 0x4CF01281, 0xAB6BCB3B, 0xA266C035, + 0xB971DD27, 0xB07CD629, 0x8F5FE703, 0x8652EC0D, 0x9D45F11F, + 0x9448FA11, 0xE303934B, 0xEA0E9845, 0xF1198557, 0xF8148E59, + 0xC737BF73, 0xCE3AB47D, 0xD52DA96F, 0xDC20A261, 0x766DF6AD, + 0x7F60FDA3, 0x6477E0B1, 0x6D7AEBBF, 0x5259DA95, 0x5B54D19B, + 0x4043CC89, 0x494EC787, 0x3E05AEDD, 0x3708A5D3, 0x2C1FB8C1, + 0x2512B3CF, 0x1A3182E5, 0x133C89EB, 0x082B94F9, 0x01269FF7, + 0xE6BD464D, 0xEFB04D43, 0xF4A75051, 0xFDAA5B5F, 0xC2896A75, + 0xCB84617B, 0xD0937C69, 0xD99E7767, 0xAED51E3D, 0xA7D81533, + 0xBCCF0821, 0xB5C2032F, 0x8AE13205, 0x83EC390B, 0x98FB2419, + 0x91F62F17, 0x4DD68D76, 0x44DB8678, 0x5FCC9B6A, 0x56C19064, + 0x69E2A14E, 0x60EFAA40, 0x7BF8B752, 0x72F5BC5C, 0x05BED506, + 0x0CB3DE08, 0x17A4C31A, 0x1EA9C814, 0x218AF93E, 0x2887F230, + 0x3390EF22, 0x3A9DE42C, 0xDD063D96, 0xD40B3698, 0xCF1C2B8A, + 0xC6112084, 0xF93211AE, 0xF03F1AA0, 0xEB2807B2, 0xE2250CBC, + 0x956E65E6, 0x9C636EE8, 0x877473FA, 0x8E7978F4, 0xB15A49DE, + 0xB85742D0, 0xA3405FC2, 0xAA4D54CC, 0xECDAF741, 0xE5D7FC4F, + 0xFEC0E15D, 0xF7CDEA53, 0xC8EEDB79, 0xC1E3D077, 0xDAF4CD65, + 0xD3F9C66B, 0xA4B2AF31, 0xADBFA43F, 0xB6A8B92D, 0xBFA5B223, + 0x80868309, 0x898B8807, 0x929C9515, 0x9B919E1B, 0x7C0A47A1, + 0x75074CAF, 0x6E1051BD, 0x671D5AB3, 0x583E6B99, 0x51336097, + 0x4A247D85, 0x4329768B, 0x34621FD1, 0x3D6F14DF, 0x267809CD, + 0x2F7502C3, 0x105633E9, 0x195B38E7, 0x024C25F5, 0x0B412EFB, + 0xD7618C9A, 0xDE6C8794, 0xC57B9A86, 0xCC769188, 0xF355A0A2, + 0xFA58ABAC, 0xE14FB6BE, 0xE842BDB0, 0x9F09D4EA, 0x9604DFE4, + 0x8D13C2F6, 0x841EC9F8, 0xBB3DF8D2, 0xB230F3DC, 0xA927EECE, + 0xA02AE5C0, 0x47B13C7A, 0x4EBC3774, 0x55AB2A66, 0x5CA62168, + 0x63851042, 0x6A881B4C, 0x719F065E, 0x78920D50, 0x0FD9640A, + 0x06D46F04, 0x1DC37216, 0x14CE7918, 0x2BED4832, 0x22E0433C, + 0x39F75E2E, 0x30FA5520, 0x9AB701EC, 0x93BA0AE2, 0x88AD17F0, + 0x81A01CFE, 0xBE832DD4, 0xB78E26DA, 0xAC993BC8, 0xA59430C6, + 0xD2DF599C, 0xDBD25292, 0xC0C54F80, 0xC9C8448E, 0xF6EB75A4, + 0xFFE67EAA, 0xE4F163B8, 0xEDFC68B6, 0x0A67B10C, 0x036ABA02, + 0x187DA710, 0x1170AC1E, 0x2E539D34, 0x275E963A, 0x3C498B28, + 0x35448026, 0x420FE97C, 0x4B02E272, 0x5015FF60, 0x5918F46E, + 0x663BC544, 0x6F36CE4A, 0x7421D358, 0x7D2CD856, 0xA10C7A37, + 0xA8017139, 0xB3166C2B, 0xBA1B6725, 0x8538560F, 0x8C355D01, + 0x97224013, 0x9E2F4B1D, 0xE9642247, 0xE0692949, 0xFB7E345B, + 0xF2733F55, 0xCD500E7F, 0xC45D0571, 0xDF4A1863, 0xD647136D, + 0x31DCCAD7, 0x38D1C1D9, 0x23C6DCCB, 0x2ACBD7C5, 0x15E8E6EF, + 0x1CE5EDE1, 0x07F2F0F3, 0x0EFFFBFD, 0x79B492A7, 0x70B999A9, + 0x6BAE84BB, 0x62A38FB5, 0x5D80BE9F, 0x548DB591, 0x4F9AA883, + 0x4697A38D, + }; + + /** + * Return the block cipher size. + * + * @return the AES block cipher size (in bytes). + */ + int getBlockSize() { + return AESConstants.AES_BLOCK_SIZE; + } + + /** + * Verifies if the length argument is a valid key size or not. + * + * @param len the size of the key (in bytes) to be validated. + * + * @return {@code true} if the size of the key is valid else {@code false}. + */ + static boolean isKeySizeValid(int len) { + for (int kLength : AESConstants.AES_KEYSIZES) { + if (len == kLength) { + return true; + } + } + return false; + } + + /** + * Check algorithm and initalize round keys for decryption and encryption. + * + * @param decrypting [in] indicates if encrypting ({@code false}) or + * decrypting ({@code true}). + * @param algorithm [in] the case insentive string name for the AES cipher. + * @param key [in] the symmetric key byte array for encryption/decryption. + * + * @throws InvalidKeyException if an incorrect algorithm is given or if + * an invalid key size is provided. + */ + void init(boolean decrypting, String algorithm, byte[] key) + throws InvalidKeyException { + int decrypt = decrypting ? 1 : 0; + + if (!algorithm.equalsIgnoreCase("AES") + && !algorithm.equalsIgnoreCase("Rijndael")) { + throw new InvalidKeyException ("Invalid algorithm name."); + } + if (key.length == AESConstants.AES_KEYSIZES[0]) { + rounds = AES_128_ROUNDS; + } else if (key.length == AESConstants.AES_KEYSIZES[1]) { + rounds = AES_192_ROUNDS; + } else if (key.length == AESConstants.AES_KEYSIZES[2]) { + rounds = AES_256_ROUNDS; + } else { + throw new InvalidKeyException("Invalid key length (" + key.length + + ")."); + } + if (!MessageDigest.isEqual(prevKey, key)) { + if (sessionK == null) { + sessionK = new int[2][]; + } else { + Arrays.fill(sessionK[0], 0); + Arrays.fill(sessionK[1], 0); + } + sessionK[0] = genRoundKeys(key, rounds); + sessionK[1] = genInvRoundKeys(sessionK[0], rounds); + if (prevKey != null) { + Arrays.fill(prevKey, (byte) 0); + } + prevKey = key.clone(); + } + K = sessionK[decrypt]; + } + + /** + * Generate the cipher's round keys as outlined in section 5.2 of the spec. + * + * @param key [in] the symmetric key byte array. + * + * @return w the cipher round keys. + */ + private static int[] genRoundKeys(byte[] key, int rounds) { + int wLen = WB * (rounds + 1); + int[] w = new int[wLen]; + int nk = key.length / BW; + + for (int i = 0, j = 0; i < nk; i++, j += BW) { + w[i] = ((key[j] & 0xFF) << 24) | ((key[j + 1] & 0xFF) << 16) + | ((key[j + 2] & 0xFF) << 8) | (key[j + 3] & 0xFF); + } + for (int i = nk; i < wLen; i++) { + int tmp = w[i - 1]; + if (i % nk == 0) { + int rW = (tmp << 8) & 0xFFFFFF00 | (tmp >>> 24); + tmp = subWord(rW) ^ RCON[(i / nk) - 1]; + } else if ((nk > 6) && ((i % nk) == WB)) { + tmp = subWord(tmp); + } + w[i] = w[i - nk] ^ tmp; + } + + return w; + } + + /** + * Generate the inverse cipher round keys. + * + * @return w1 the inverse cipher round keys. + */ + private static int[] genInvRoundKeys(int[] w, int rounds) { + int kLen = w.length;; + int[] temp = new int[WB]; + int[] dw = new int[kLen]; + + // Intrinsics requires the inverse key expansion to be reverse order + // except for the first and last round key as the first two round keys + // are without a mix column transform. + for (int i = 1; i < rounds; i++) { + System.arraycopy(w, i * WB, temp, 0, WB); + temp[0] = TMI0[temp[0] >>> 24] ^ TMI1[(temp[0] >> 16) & 0xFF] + ^ TMI2[(temp[0] >> 8) & 0xFF] ^ TMI3[temp[0] & 0xFF]; + temp[1] = TMI0[temp[1] >>> 24] ^ TMI1[(temp[1] >> 16) & 0xFF] + ^ TMI2[(temp[1] >> 8) & 0xFF] ^ TMI3[temp[1] & 0xFF]; + temp[2] = TMI0[temp[2] >>> 24] ^ TMI1[(temp[2] >> 16) & 0xFF] + ^ TMI2[(temp[2] >> 8) & 0xFF] ^ TMI3[temp[2] & 0xFF]; + temp[3] = TMI0[temp[3] >>> 24] ^ TMI1[(temp[3] >> 16) & 0xFF] + ^ TMI2[(temp[3] >> 8) & 0xFF] ^ TMI3[temp[3] & 0xFF]; + System.arraycopy(temp, 0, dw, kLen - (i * WB), WB); + } + System.arraycopy(w, kLen - WB, dw, WB, WB); + System.arraycopy(w, 0, dw, 0, WB); + Arrays.fill(temp, 0); + + return dw; + } + + /** + * Subtitute the word as a step of key expansion. + * + * @param state [in] the targeted word for substituion. + * @param sub [in] the substitute table for cipher and inverse cipher. + * + * @return the substituted word. + */ + private static int subWord(int word) { + byte b0 = (byte) (word >>> 24); + byte b1 = (byte) ((word >> 16) & 0xFF); + byte b2 = (byte) ((word >> 8) & 0xFF); + byte b3 = (byte) (word & 0xFF); + + return ((SBOX[(b0 & 0xF0) >> 4][b0 & 0x0F] & 0xFF) << 24) + | ((SBOX[(b1 & 0xF0) >> 4][b1 & 0x0F] & 0xFF) << 16) + | ((SBOX[(b2 & 0xF0) >> 4][b2 & 0x0F] & 0xFF) << 8) + | (SBOX[(b3 & 0xF0) >> 4][b3 & 0x0F] & 0xFF); + } + + /** + * Method for one block of encryption. + * + * @param p [in] the plaintext to be encrypted. + * @param po [in] the plaintext offset in the array of bytes. + * @param c [out] the ciphertext output. + * @param co [in] the ciphertext offset in the array of bytes. + */ + @IntrinsicCandidate + private void implEncryptBlock(byte[] p, int po, byte[] c, int co) { + int ti0, ti1, ti2, ti3; + int a0, a1, a2, a3; + int w = K.length - WB; + + a0 = ((p[po] & 0xFF) << 24) ^ ((p[po + 1] & 0xFF) << 16) + ^ ((p[po + 2] & 0xFF) << 8) ^ (p[po + 3] & 0xFF) ^ K[0]; + a1 = ((p[po + 4] & 0xFF) << 24) ^ ((p[po + 5] & 0xFF) << 16) + ^ ((p[po + 6] & 0xFF) << 8) ^ (p[po + 7] & 0xFF) ^ K[1]; + a2 = ((p[po + 8] & 0xFF) << 24) ^ ((p[po + 9] & 0xFF) << 16) + ^ ((p[po + 10] & 0xFF) << 8) ^ (p[po + 11] & 0xFF) ^ K[2]; + a3 = ((p[po + 12] & 0xFF) << 24) ^ ((p[po + 13] & 0xFF) << 16) + ^ ((p[po + 14] & 0xFF) << 8) ^ (p[po + 15] & 0xFF) ^ K[3]; + + ti0 = T0[a0 >>> 24] ^ T1[(a1 >> 16) & 0xFF] + ^ T2[(a2 >> 8) & 0xFF] ^ T3[a3 & 0xFF] ^ K[4]; + ti1 = T0[a1 >>> 24] ^ T1[(a2 >> 16) & 0xFF] + ^ T2[(a3 >> 8) & 0xFF] ^ T3[a0 & 0xFF] ^ K[5]; + ti2 = T0[a2 >>> 24] ^ T1[(a3 >> 16) & 0xFF] + ^ T2[(a0 >> 8) & 0xFF] ^ T3[a1 & 0xFF] ^ K[6]; + ti3 = T0[a3 >>> 24] ^ T1[(a0 >> 16) & 0xFF] + ^ T2[(a1 >> 8) & 0xFF] ^ T3[a2 & 0xFF] ^ K[7]; + + a0 = T0[ti0 >>> 24] ^ T1[(ti1 >> 16) & 0xFF] + ^ T2[(ti2 >> 8) & 0xFF] ^ T3[ti3 & 0xFF] ^ K[8]; + a1 = T0[ti1 >>> 24] ^ T1[(ti2 >> 16) & 0xFF] + ^ T2[(ti3 >> 8) & 0xFF] ^ T3[ti0 & 0xFF] ^ K[9]; + a2 = T0[ti2 >>> 24] ^ T1[(ti3 >> 16) & 0xFF] + ^ T2[(ti0 >> 8) & 0xFF] ^ T3[ti1 & 0xFF] ^ K[10]; + a3 = T0[ti3 >>> 24] ^ T1[(ti0 >> 16) & 0xFF] + ^ T2[(ti1 >> 8) & 0xFF] ^ T3[ti2 & 0xFF] ^ K[11]; + + ti0 = T0[a0 >>> 24] ^ T1[(a1 >> 16) & 0xFF] + ^ T2[(a2 >> 8) & 0xFF] ^ T3[a3 & 0xFF] ^ K[12]; + ti1 = T0[a1 >>> 24] ^ T1[(a2 >> 16) & 0xFF] + ^ T2[(a3 >> 8) & 0xFF] ^ T3[a0 & 0xFF] ^ K[13]; + ti2 = T0[a2 >>> 24] ^ T1[(a3 >> 16) & 0xFF] + ^ T2[(a0 >> 8) & 0xFF] ^ T3[a1 & 0xFF] ^ K[14]; + ti3 = T0[a3 >>> 24] ^ T1[(a0 >> 16) & 0xFF] + ^ T2[(a1 >> 8) & 0xFF] ^ T3[a2 & 0xFF] ^ K[15]; + + a0 = T0[ti0 >>> 24] ^ T1[(ti1 >> 16) & 0xFF] + ^ T2[(ti2 >> 8) & 0xFF] ^ T3[ti3 & 0xFF] ^ K[16]; + a1 = T0[ti1 >>> 24] ^ T1[(ti2 >> 16) & 0xFF] + ^ T2[(ti3 >> 8) & 0xFF] ^ T3[ti0 & 0xFF] ^ K[17]; + a2 = T0[ti2 >>> 24] ^ T1[(ti3 >> 16) & 0xFF] + ^ T2[(ti0 >> 8) & 0xFF] ^ T3[ti1 & 0xFF] ^ K[18]; + a3 = T0[ti3 >>> 24] ^ T1[(ti0 >> 16) & 0xFF] + ^ T2[(ti1 >> 8) & 0xFF] ^ T3[ti2 & 0xFF] ^ K[19]; + + ti0 = T0[a0 >>> 24] ^ T1[(a1 >> 16) & 0xFF] + ^ T2[(a2 >> 8) & 0xFF] ^ T3[a3 & 0xFF] ^ K[20]; + ti1 = T0[a1 >>> 24] ^ T1[(a2 >> 16) & 0xFF] + ^ T2[(a3 >> 8) & 0xFF] ^ T3[a0 & 0xFF] ^ K[21]; + ti2 = T0[a2 >>> 24] ^ T1[(a3 >> 16) & 0xFF] + ^ T2[(a0 >> 8) & 0xFF] ^ T3[a1 & 0xFF] ^ K[22]; + ti3 = T0[a3 >>> 24] ^ T1[(a0 >> 16) & 0xFF] + ^ T2[(a1 >> 8) & 0xFF] ^ T3[a2 & 0xFF] ^ K[23]; + + a0 = T0[ti0 >>> 24] ^ T1[(ti1 >> 16) & 0xFF] + ^ T2[(ti2 >> 8) & 0xFF] ^ T3[ti3 & 0xFF] ^ K[24]; + a1 = T0[ti1 >>> 24] ^ T1[(ti2 >> 16) & 0xFF] + ^ T2[(ti3 >> 8) & 0xFF] ^ T3[ti0 & 0xFF] ^ K[25]; + a2 = T0[ti2 >>> 24] ^ T1[(ti3 >> 16) & 0xFF] + ^ T2[(ti0 >> 8) & 0xFF] ^ T3[ti1 & 0xFF] ^ K[26]; + a3 = T0[ti3 >>> 24] ^ T1[(ti0 >> 16) & 0xFF] + ^ T2[(ti1 >> 8) & 0xFF] ^ T3[ti2 & 0xFF] ^ K[27]; + + ti0 = T0[a0 >>> 24] ^ T1[(a1 >> 16) & 0xFF] + ^ T2[(a2 >> 8) & 0xFF] ^ T3[a3 & 0xFF] ^ K[28]; + ti1 = T0[a1 >>> 24] ^ T1[(a2 >> 16) & 0xFF] + ^ T2[(a3 >> 8) & 0xFF] ^ T3[a0 & 0xFF] ^ K[29]; + ti2 = T0[a2 >>> 24] ^ T1[(a3 >> 16) & 0xFF] + ^ T2[(a0 >> 8) & 0xFF] ^ T3[a1 & 0xFF] ^ K[30]; + ti3 = T0[a3 >>> 24] ^ T1[(a0 >> 16) & 0xFF] + ^ T2[(a1 >> 8) & 0xFF] ^ T3[a2 & 0xFF] ^ K[31]; + + a0 = T0[ti0 >>> 24] ^ T1[(ti1 >> 16) & 0xFF] + ^ T2[(ti2 >> 8) & 0xFF] ^ T3[ti3 & 0xFF] ^ K[32]; + a1 = T0[ti1 >>> 24] ^ T1[(ti2 >> 16) & 0xFF] + ^ T2[(ti3 >> 8) & 0xFF] ^ T3[ti0 & 0xFF] ^ K[33]; + a2 = T0[ti2 >>> 24] ^ T1[(ti3 >> 16) & 0xFF] + ^ T2[(ti0 >> 8) & 0xFF] ^ T3[ti1 & 0xFF] ^ K[34]; + a3 = T0[ti3 >>> 24] ^ T1[(ti0 >> 16) & 0xFF] + ^ T2[(ti1 >> 8) & 0xFF] ^ T3[ti2 & 0xFF] ^ K[35]; + + ti0 = T0[a0 >>> 24] ^ T1[(a1 >> 16) & 0xFF] + ^ T2[(a2 >> 8) & 0xFF] ^ T3[a3 & 0xFF] ^ K[36]; + ti1 = T0[a1 >>> 24] ^ T1[(a2 >> 16) & 0xFF] + ^ T2[(a3 >> 8) & 0xFF] ^ T3[a0 & 0xFF] ^ K[37]; + ti2 = T0[a2 >>> 24] ^ T1[(a3 >> 16) & 0xFF] + ^ T2[(a0 >> 8) & 0xFF] ^ T3[a1 & 0xFF] ^ K[38]; + ti3 = T0[a3 >>> 24] ^ T1[(a0 >> 16) & 0xFF] + ^ T2[(a1 >> 8) & 0xFF] ^ T3[a2 & 0xFF] ^ K[39]; + + if (rounds > AES_128_ROUNDS) { + a0 = T0[ti0 >>> 24] ^ T1[(ti1 >> 16) & 0xFF] + ^ T2[(ti2 >> 8) & 0xFF] ^ T3[ti3 & 0xFF] ^ K[40]; + a1 = T0[ti1 >>> 24] ^ T1[(ti2 >> 16) & 0xFF] + ^ T2[(ti3 >> 8) & 0xFF] ^ T3[ti0 & 0xFF] ^ K[41]; + a2 = T0[ti2 >>> 24] ^ T1[(ti3 >> 16) & 0xFF] + ^ T2[(ti0 >> 8) & 0xFF] ^ T3[ti1 & 0xFF] ^ K[42]; + a3 = T0[ti3 >>> 24] ^ T1[(ti0 >> 16) & 0xFF] + ^ T2[(ti1 >> 8) & 0xFF] ^ T3[ti2 & 0xFF] ^ K[43]; + + ti0 = T0[a0 >>> 24] ^ T1[(a1 >> 16) & 0xFF] + ^ T2[(a2 >> 8) & 0xFF] ^ T3[a3 & 0xFF] ^ K[44]; + ti1 = T0[a1 >>> 24] ^ T1[(a2 >> 16) & 0xFF] + ^ T2[(a3 >> 8) & 0xFF] ^ T3[a0 & 0xFF] ^ K[45]; + ti2 = T0[a2 >>> 24] ^ T1[(a3 >> 16) & 0xFF] + ^ T2[(a0 >> 8) & 0xFF] ^ T3[a1 & 0xFF] ^ K[46]; + ti3 = T0[a3 >>> 24] ^ T1[(a0 >> 16) & 0xFF] + ^ T2[(a1 >> 8) & 0xFF] ^ T3[a2 & 0xFF] ^ K[47]; + } + if (rounds > AES_192_ROUNDS) { + a0 = T0[ti0 >>> 24] ^ T1[(ti1 >> 16) & 0xFF] + ^ T2[(ti2 >> 8) & 0xFF] ^ T3[ti3 & 0xFF] ^ K[48]; + a1 = T0[ti1 >>> 24] ^ T1[(ti2 >> 16) & 0xFF] + ^ T2[(ti3 >> 8) & 0xFF] ^ T3[ti0 & 0xFF] ^ K[49]; + a2 = T0[ti2 >>> 24] ^ T1[(ti3 >> 16) & 0xFF] + ^ T2[(ti0 >> 8) & 0xFF] ^ T3[ti1 & 0xFF] ^ K[50]; + a3 = T0[ti3 >>> 24] ^ T1[(ti0 >> 16) & 0xFF] + ^ T2[(ti1 >> 8) & 0xFF] ^ T3[ti2 & 0xFF] ^ K[51]; + + ti0 = T0[a0 >>> 24] ^ T1[(a1 >> 16) & 0xFF] + ^ T2[(a2 >> 8) & 0xFF] ^ T3[a3 & 0xFF] ^ K[52]; + ti1 = T0[a1 >>> 24] ^ T1[(a2 >> 16) & 0xFF] + ^ T2[(a3 >> 8) & 0xFF] ^ T3[a0 & 0xFF] ^ K[53]; + ti2 = T0[a2 >>> 24] ^ T1[(a3 >> 16) & 0xFF] + ^ T2[(a0 >> 8) & 0xFF] ^ T3[a1 & 0xFF] ^ K[54]; + ti3 = T0[a3 >>> 24] ^ T1[(a0 >> 16) & 0xFF] + ^ T2[(a1 >> 8) & 0xFF] ^ T3[a2 & 0xFF] ^ K[55]; + } + + a0 = T2[ti0 >>> 24] & 0xFF000000 + ^ T3[(ti1 >> 16) & 0xFF] & 0xFF0000 + ^ T0[(ti2 >> 8) & 0xFF] & 0xFF00 + ^ T1[ti3 & 0xFF] & 0xFF ^ K[w]; + a1 = T2[ti1 >>> 24] & 0xFF000000 + ^ T3[(ti2 >> 16) & 0xFF] & 0xFF0000 + ^ T0[(ti3 >> 8) & 0xFF] & 0xFF00 + ^ T1[ti0 & 0xFF] & 0xFF ^ K[w + 1]; + a2 = T2[ti2 >>> 24] & 0xFF000000 + ^ T3[(ti3 >> 16) & 0xFF] & 0xFF0000 + ^ T0[(ti0 >> 8) & 0xFF] & 0xFF00 + ^ T1[ti1 & 0xFF] & 0xFF ^ K[w + 2]; + a3 = T2[ti3 >>> 24] & 0xFF000000 + ^ T3[(ti0 >> 16) & 0xFF] & 0xFF0000 + ^ T0[(ti1 >> 8) & 0xFF] & 0xFF00 + ^ T1[ti2 & 0xFF] & 0xFF ^ K[w + 3]; + + c[co] = (byte) (a0 >>> 24); + c[co + 1] = (byte) ((a0 >> 16) & 0xFF); + c[co + 2] = (byte) ((a0 >> 8) & 0xFF); + c[co + 3] = (byte) (a0 & 0xFF); + c[co + 4] = (byte) (a1 >>> 24); + c[co + 5] = (byte) ((a1 >> 16) & 0xFF); + c[co + 6] = (byte) ((a1 >> 8) & 0xFF); + c[co + 7] = (byte) (a1 & 0xFF); + c[co + 8] = (byte) (a2 >>> 24); + c[co + 9] = (byte) ((a2 >> 16) & 0xFF); + c[co + 10] = (byte) ((a2 >> 8) & 0xFF); + c[co + 11] = (byte) (a2 & 0xFF); + c[co + 12] = (byte) (a3 >> 24); + c[co + 13] = (byte) ((a3 >> 16) & 0xFF); + c[co + 14] = (byte) ((a3 >> 8) & 0xFF); + c[co + 15] = (byte) (a3 & 0xFF); + } + + /** + * Method for one block of decryption. + * + * @param c [in] the ciphertext to be decrypted. + * @param co [in] the ciphertext offset in the array of bytes. + * @param p [out] the plaintext output. + * @param po [in] the plaintext offset in the array of bytes. + */ + @IntrinsicCandidate + private void implDecryptBlock(byte[] c, int co, byte[] p, int po) { + int ti0, ti1, ti2, ti3; + int a0, a1, a2, a3; + + ti0 = ((c[co] & 0xFF) << 24) ^ ((c[co + 1] & 0xFF) << 16) + ^ ((c[co + 2] & 0xFF) << 8) ^ (c[co + 3] & 0xFF) ^ K[4]; + ti1 = ((c[co + 4] & 0xFF) << 24) ^ ((c[co + 5] & 0xFF) << 16) + ^ ((c[co + 6] & 0xFF) << 8) ^ (c[co + 7] & 0xFF) ^ K[5]; + ti2 = ((c[co + 8] & 0xFF) << 24) ^ ((c[co + 9] & 0xFF) << 16) + ^ ((c[co + 10] & 0xFF) << 8) ^ (c[co + 11] & 0xFF) ^ K[6]; + ti3 = ((c[co + 12] & 0xFF) << 24) ^ ((c[co + 13] & 0xFF) << 16) + ^ ((c[co + 14] & 0xFF) << 8) ^ (c[co + 15] & 0xFF) ^ K[7]; + + a0 = TI0[ti0 >>> 24] ^ TI1[(ti3 >> 16) & 0xFF] + ^ TI2[(ti2 >> 8) & 0xFF] ^ TI3[ti1 & 0xFF] ^ K[8]; + a1 = TI0[ti1 >>> 24] ^ TI1[(ti0 >> 16) & 0xFF] + ^ TI2[(ti3 >> 8) & 0xFF] ^ TI3[ti2 & 0xFF] ^ K[9]; + a2 = TI0[ti2 >>> 24] ^ TI1[(ti1 >> 16) & 0xFF] + ^ TI2[(ti0 >> 8) & 0xFF] ^ TI3[ti3 & 0xFF] ^ K[10]; + a3 = TI0[ti3 >>> 24] ^ TI1[(ti2 >> 16) & 0xFF] + ^ TI2[(ti1 >> 8) & 0xFF] ^ TI3[ti0 & 0xFF] ^ K[11]; + + ti0 = TI0[a0 >>> 24] ^ TI1[(a3 >> 16) & 0xFF] + ^ TI2[(a2 >> 8) & 0xFF] ^ TI3[a1 & 0xFF] ^ K[12]; + ti1 = TI0[a1 >>> 24] ^ TI1[(a0 >> 16) & 0xFF] + ^ TI2[(a3 >> 8) & 0xFF] ^ TI3[a2 & 0xFF] ^ K[13]; + ti2 = TI0[a2 >>> 24] ^ TI1[(a1 >> 16) & 0xFF] + ^ TI2[(a0 >> 8) & 0xFF] ^ TI3[a3 & 0xFF] ^ K[14]; + ti3 = TI0[a3 >>> 24] ^ TI1[(a2 >> 16) & 0xFF] + ^ TI2[(a1 >> 8) & 0xFF] ^ TI3[a0 & 0xFF] ^ K[15]; + + a0 = TI0[ti0 >>> 24] ^ TI1[(ti3 >> 16) & 0xFF] + ^ TI2[(ti2 >> 8) & 0xFF] ^ TI3[ti1 & 0xFF] ^ K[16]; + a1 = TI0[ti1 >>> 24] ^ TI1[(ti0 >> 16) & 0xFF] + ^ TI2[(ti3 >> 8) & 0xFF] ^ TI3[ti2 & 0xFF] ^ K[17]; + a2 = TI0[ti2 >>> 24] ^ TI1[(ti1 >> 16) & 0xFF] + ^ TI2[(ti0 >> 8) & 0xFF] ^ TI3[ti3 & 0xFF] ^ K[18]; + a3 = TI0[ti3 >>> 24] ^ TI1[(ti2 >> 16) & 0xFF] + ^ TI2[(ti1 >> 8) & 0xFF] ^ TI3[ti0 & 0xFF] ^ K[19]; + + ti0 = TI0[a0 >>> 24] ^ TI1[(a3 >> 16) & 0xFF] + ^ TI2[(a2 >> 8) & 0xFF] ^ TI3[a1 & 0xFF] ^ K[20]; + ti1 = TI0[a1 >>> 24] ^ TI1[(a0 >> 16) & 0xFF] + ^ TI2[(a3 >> 8) & 0xFF] ^ TI3[a2 & 0xFF] ^ K[21]; + ti2 = TI0[a2 >>> 24] ^ TI1[(a1 >> 16) & 0xFF] + ^ TI2[(a0 >> 8) & 0xFF] ^ TI3[a3 & 0xFF] ^ K[22]; + ti3 = TI0[a3 >>> 24] ^ TI1[(a2 >> 16) & 0xFF] + ^ TI2[(a1 >> 8) & 0xFF] ^ TI3[a0 & 0xFF] ^ K[23]; + + a0 = TI0[ti0 >>> 24] ^ TI1[(ti3 >> 16) & 0xFF] + ^ TI2[(ti2 >> 8) & 0xFF] ^ TI3[ti1 & 0xFF] ^ K[24]; + a1 = TI0[ti1 >>> 24] ^ TI1[(ti0 >> 16) & 0xFF] + ^ TI2[(ti3 >> 8) & 0xFF] ^ TI3[ti2 & 0xFF] ^ K[25]; + a2 = TI0[ti2 >>> 24] ^ TI1[(ti1 >> 16) & 0xFF] + ^ TI2[(ti0 >> 8) & 0xFF] ^ TI3[ti3 & 0xFF] ^ K[26]; + a3 = TI0[ti3 >>> 24] ^ TI1[(ti2 >> 16) & 0xFF] + ^ TI2[(ti1 >> 8) & 0xFF] ^ TI3[ti0 & 0xFF] ^ K[27]; + + ti0 = TI0[a0 >>> 24] ^ TI1[(a3 >> 16) & 0xFF] + ^ TI2[(a2 >> 8) & 0xFF] ^ TI3[a1 & 0xFF] ^ K[28]; + ti1 = TI0[a1 >>> 24] ^ TI1[(a0 >> 16) & 0xFF] + ^ TI2[(a3 >> 8) & 0xFF] ^ TI3[a2 & 0xFF] ^ K[29]; + ti2 = TI0[a2 >>> 24] ^ TI1[(a1 >> 16) & 0xFF] + ^ TI2[(a0 >> 8) & 0xFF] ^ TI3[a3 & 0xFF] ^ K[30]; + ti3 = TI0[a3 >>> 24] ^ TI1[(a2 >> 16) & 0xFF] + ^ TI2[(a1 >> 8) & 0xFF] ^ TI3[a0 & 0xFF] ^ K[31]; + + a0 = TI0[ti0 >>> 24] ^ TI1[(ti3 >> 16) & 0xFF] + ^ TI2[(ti2 >> 8) & 0xFF] ^ TI3[ti1 & 0xFF] ^ K[32]; + a1 = TI0[ti1 >>> 24] ^ TI1[(ti0 >> 16) & 0xFF] + ^ TI2[(ti3 >> 8) & 0xFF] ^ TI3[ti2 & 0xFF] ^ K[33]; + a2 = TI0[ti2 >>> 24] ^ TI1[(ti1 >> 16) & 0xFF] + ^ TI2[(ti0 >> 8) & 0xFF] ^ TI3[ti3 & 0xFF] ^ K[34]; + a3 = TI0[ti3 >>> 24] ^ TI1[(ti2 >> 16) & 0xFF] + ^ TI2[(ti1 >> 8) & 0xFF] ^ TI3[ti0 & 0xFF] ^ K[35]; + + ti0 = TI0[a0 >>> 24] ^ TI1[(a3 >> 16) & 0xFF] + ^ TI2[(a2 >> 8) & 0xFF] ^ TI3[a1 & 0xFF] ^ K[36]; + ti1 = TI0[a1 >>> 24] ^ TI1[(a0 >> 16) & 0xFF] + ^ TI2[(a3 >> 8) & 0xFF] ^ TI3[a2 & 0xFF] ^ K[37]; + ti2 = TI0[a2 >>> 24] ^ TI1[(a1 >> 16) & 0xFF] + ^ TI2[(a0 >> 8) & 0xFF] ^ TI3[a3 & 0xFF] ^ K[38]; + ti3 = TI0[a3 >>> 24] ^ TI1[(a2 >> 16) & 0xFF] + ^ TI2[(a1 >> 8) & 0xFF] ^ TI3[a0 & 0xFF] ^ K[39]; + + a0 = TI0[ti0 >>> 24] ^ TI1[(ti3 >> 16) & 0xFF] + ^ TI2[(ti2 >> 8) & 0xFF] ^ TI3[ti1 & 0xFF] ^ K[40]; + a1 = TI0[ti1 >>> 24] ^ TI1[(ti0 >> 16) & 0xFF] + ^ TI2[(ti3 >> 8) & 0xFF] ^ TI3[ti2 & 0xFF] ^ K[41]; + a2 = TI0[ti2 >>> 24] ^ TI1[(ti1 >> 16) & 0xFF] + ^ TI2[(ti0 >> 8) & 0xFF] ^ TI3[ti3 & 0xFF] ^ K[42]; + a3 = TI0[ti3 >>> 24] ^ TI1[(ti2 >> 16) & 0xFF] + ^ TI2[(ti1 >> 8) & 0xFF] ^ TI3[ti0 & 0xFF] ^ K[43]; + + if (rounds > AES_128_ROUNDS) { + ti0 = TI0[a0 >>> 24] ^ TI1[(a3 >> 16) & 0xFF] + ^ TI2[(a2 >> 8) & 0xFF] ^ TI3[a1 & 0xFF] ^ K[44]; + ti1 = TI0[a1 >>> 24] ^ TI1[(a0 >> 16) & 0xFF] + ^ TI2[(a3 >> 8) & 0xFF] ^ TI3[a2 & 0xFF] ^ K[45]; + ti2 = TI0[a2 >>> 24] ^ TI1[(a1 >> 16) & 0xFF] + ^ TI2[(a0 >> 8) & 0xFF] ^ TI3[a3 & 0xFF] ^ K[46]; + ti3 = TI0[a3 >>> 24] ^ TI1[(a2 >> 16) & 0xFF] + ^ TI2[(a1 >> 8) & 0xFF] ^ TI3[a0 & 0xFF] ^ K[47]; + + a0 = TI0[ti0 >>> 24] ^ TI1[(ti3 >> 16) & 0xFF] + ^ TI2[(ti2 >> 8) & 0xFF] ^ TI3[ti1 & 0xFF] ^ K[48]; + a1 = TI0[ti1 >>> 24] ^ TI1[(ti0 >> 16) & 0xFF] + ^ TI2[(ti3 >> 8) & 0xFF] ^ TI3[ti2 & 0xFF] ^ K[49]; + a2 = TI0[ti2 >>> 24] ^ TI1[(ti1 >> 16) & 0xFF] + ^ TI2[(ti0 >> 8) & 0xFF] ^ TI3[ti3 & 0xFF] ^ K[50]; + a3 = TI0[ti3 >>> 24] ^ TI1[(ti2 >> 16) & 0xFF] + ^ TI2[(ti1 >> 8) & 0xFF] ^ TI3[ti0 & 0xFF] ^ K[51]; + } + if (rounds > AES_192_ROUNDS) { + ti0 = TI0[a0 >>> 24] ^ TI1[(a3 >> 16) & 0xFF] + ^ TI2[(a2 >> 8) & 0xFF] ^ TI3[a1 & 0xFF] ^ K[52]; + ti1 = TI0[a1 >>> 24] ^ TI1[(a0 >> 16) & 0xFF] + ^ TI2[(a3 >> 8) & 0xFF] ^ TI3[a2 & 0xFF] ^ K[53]; + ti2 = TI0[a2 >>> 24] ^ TI1[(a1 >> 16) & 0xFF] + ^ TI2[(a0 >> 8) & 0xFF] ^ TI3[a3 & 0xFF] ^ K[54]; + ti3 = TI0[a3 >>> 24] ^ TI1[(a2 >> 16) & 0xFF] + ^ TI2[(a1 >> 8) & 0xFF] ^ TI3[a0 & 0xFF] ^ K[55]; + + a0 = TI0[ti0 >>> 24] ^ TI1[(ti3 >> 16) & 0xFF] + ^ TI2[(ti2 >> 8) & 0xFF] ^ TI3[ti1 & 0xFF] ^ K[56]; + a1 = TI0[ti1 >>> 24] ^ TI1[(ti0 >> 16) & 0xFF] + ^ TI2[(ti3 >> 8) & 0xFF] ^ TI3[ti2 & 0xFF] ^ K[57]; + a2 = TI0[ti2 >>> 24] ^ TI1[(ti1 >> 16) & 0xFF] + ^ TI2[(ti0 >> 8) & 0xFF] ^ TI3[ti3 & 0xFF] ^ K[58]; + a3 = TI0[ti3 >>> 24] ^ TI1[(ti2 >> 16) & 0xFF] + ^ TI2[(ti1 >> 8) & 0xFF] ^ TI3[ti0 & 0xFF] ^ K[59]; + } + + ti0 = TI4[a0 >>> 24] & 0xFF000000 ^ TI4[(a3 >> 16) & 0xFF] & 0xFF0000 + ^ TI4[(a2 >> 8) & 0xFF] & 0xFF00 ^ TI4[a1 & 0xFF] & 0xFF ^ K[0]; + ti1 = TI4[a1 >>> 24] & 0xFF000000 ^ TI4[(a0 >> 16) & 0xFF] & 0xFF0000 + ^ TI4[(a3 >> 8) & 0xFF] & 0xFF00 ^ TI4[a2 & 0xFF] & 0xFF ^ K[1]; + ti2 = TI4[a2 >>> 24] & 0xFF000000 ^ TI4[(a1 >> 16) & 0xFF] & 0xFF0000 + ^ TI4[(a0 >> 8) & 0xFF] & 0xFF00 ^ TI4[a3 & 0xFF] & 0xFF ^ K[2]; + ti3 = TI4[a3 >>> 24] & 0xFF000000 ^ TI4[(a2 >> 16) & 0xFF] & 0xFF0000 + ^ TI4[(a1 >> 8) & 0xFF] & 0xFF00 ^ TI4[a0 & 0xFF] & 0xFF ^ K[3]; + + p[po] = (byte) (ti0 >>> 24); + p[po + 1] = (byte) ((ti0 >> 16) & 0xFF); + p[po + 2] = (byte) ((ti0 >> 8) & 0xFF); + p[po + 3] = (byte) (ti0 & 0xFF); + p[po + 4] = (byte) (ti1 >>> 24); + p[po + 5] = (byte) ((ti1 >> 16) & 0xFF); + p[po + 6] = (byte) ((ti1 >> 8) & 0xFF); + p[po + 7] = (byte) (ti1 & 0xFF); + p[po + 8] = (byte) (ti2 >>> 24); + p[po + 9] = (byte) ((ti2 >> 16) & 0xFF); + p[po + 10] = (byte) ((ti2 >> 8) & 0xFF); + p[po + 11] = (byte) (ti2 & 0xFF); + p[po + 12] = (byte) (ti3 >>> 24); + p[po + 13] = (byte) ((ti3 >> 16) & 0xFF); + p[po + 14] = (byte) ((ti3 >> 8) & 0xFF); + p[po + 15] = (byte) (ti3 & 0xFF); + } + + /** + * Method for one block of encryption. + * + * @param plain [in] the plaintext to be encrypted. + * @param pOff [in] the plaintext offset in the array of bytes. + * @param cipher [out] the encrypted ciphertext output. + * @param cOff [in] the ciphertext offset in the array of bytes. + */ + void encryptBlock(byte[] plain, int pOff, byte[] cipher, int cOff) { + implEncryptBlock(plain, pOff, cipher, cOff); + } + + /** + * Method for one block of decryption. + * + * @param cipher [in] the ciphertext to be decrypted. + * @param cOff [in] the ciphertext offset in the array of bytes. + * @param plain [out] the decrypted plaintext output. + * @param pOff [in] the plaintext offset in the array of bytes. + */ + void decryptBlock(byte[] cipher, int cOff, byte[] plain, int pOff) { + implDecryptBlock(cipher, cOff, plain, pOff); + } +} diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java b/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java index 926a56c140b..3f3373860f3 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import java.util.Arrays; * to 16 bytes. * * If any invariant is broken, failures can occur because the - * AESCrypt.encryptBlock method can be intrinsified on the HotSpot VM + * AES_Crypt.encryptBlock method can be intrinsified on the HotSpot VM * (see JDK-8067648 for details). * * The counter mode operations can be intrinsified and parallelized diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index 3d1396121ad..2f4df1eba03 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -102,7 +102,7 @@ abstract class GaloisCounterMode extends CipherSpi { /** * * @param keySize length of key. - * @param embeddedCipher Cipher object, such as AESCrypt. + * @param embeddedCipher Cipher object, such as AES_Crypt. */ GaloisCounterMode(int keySize, SymmetricCipher embeddedCipher) { blockCipher = embeddedCipher; @@ -198,7 +198,7 @@ abstract class GaloisCounterMode extends CipherSpi { protected int engineGetKeySize(Key key) throws InvalidKeyException { byte[] encoded = key.getEncoded(); Arrays.fill(encoded, (byte)0); - if (!AESCrypt.isKeySizeValid(encoded.length)) { + if (!AES_Crypt.isKeySizeValid(encoded.length)) { throw new InvalidKeyException("Invalid key length: " + encoded.length + " bytes"); } @@ -1693,25 +1693,25 @@ abstract class GaloisCounterMode extends CipherSpi { public static final class AESGCM extends GaloisCounterMode { public AESGCM() { - super(-1, new AESCrypt()); + super(-1, new AES_Crypt()); } } public static final class AES128 extends GaloisCounterMode { public AES128() { - super(16, new AESCrypt()); + super(16, new AES_Crypt()); } } public static final class AES192 extends GaloisCounterMode { public AES192() { - super(24, new AESCrypt()); + super(24, new AES_Crypt()); } } public static final class AES256 extends GaloisCounterMode { public AES256() { - super(32, new AESCrypt()); + super(32, new AES_Crypt()); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java index ba2825fa36c..e0c1873213b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,7 +137,7 @@ abstract class KeyWrapCipher extends CipherSpi { } int keyLen = keyBytes.length; if (!key.getAlgorithm().equalsIgnoreCase("AES") || - !AESCrypt.isKeySizeValid(keyLen) || + !AES_Crypt.isKeySizeValid(keyLen) || (fixedKeySize != -1 && fixedKeySize != keyLen)) { throw new InvalidKeyException("Invalid key length: " + keyLen + " bytes"); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java index 6d2c4da3b8b..df37da2347f 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,7 @@ abstract class PBES2Core extends CipherSpi { if (cipherAlgo.equals("AES")) { blkSize = AESConstants.AES_BLOCK_SIZE; - cipher = new CipherCore(new AESCrypt(), blkSize); + cipher = new CipherCore(new AES_Crypt(), blkSize); switch(kdfAlgo) { case "HmacSHA1": diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SymmetricCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/SymmetricCipher.java index 7b428f86aa7..ad93679140c 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SymmetricCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SymmetricCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import java.security.InvalidKeyException; * @author Jan Luehe * * - * @see AESCrypt + * @see AES_Crypt * @see DESCrypt * @see DESedeCrypt * @see BlowfishCrypt diff --git a/src/java.base/share/legal/aes.md b/src/java.base/share/legal/aes.md deleted file mode 100644 index 6d0ee2e2bb4..00000000000 --- a/src/java.base/share/legal/aes.md +++ /dev/null @@ -1,36 +0,0 @@ -## Cryptix AES v3.2.0 - -### Cryptix General License -

    -
    -Cryptix General License
    -
    -Copyright (c) 1995-2005 The Cryptix Foundation Limited.
    -All rights reserved.
    -
    -Redistribution and use in source and binary forms, with or without
    -modification, are permitted provided that the following conditions are
    -met:
    -
    -  1. Redistributions of source code must retain the copyright notice,
    -     this list of conditions and the following disclaimer.
    -
    -  2. Redistributions in binary form must reproduce the above copyright
    -     notice, this list of conditions and the following disclaimer in
    -     the documentation and/or other materials provided with the
    -     distribution.
    -
    -THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND
    -CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
    -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    -IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE
    -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
    -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    -
    -
    diff --git a/test/hotspot/jtreg/compiler/codegen/aes/TestAESMain.java b/test/hotspot/jtreg/compiler/codegen/aes/TestAESMain.java index 36ee43a7732..608b979e8f1 100644 --- a/test/hotspot/jtreg/compiler/codegen/aes/TestAESMain.java +++ b/test/hotspot/jtreg/compiler/codegen/aes/TestAESMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,7 +155,7 @@ public class TestAESMain { public static void main(String[] args) { String mode = System.getProperty("mode", "CBC"); if ((mode.equals("CBC") || mode.equals("ECB")) && - !Compiler.isIntrinsicAvailable(CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION, "com.sun.crypto.provider.AESCrypt", "implEncryptBlock", byte[].class, int.class, byte[].class, int.class)) { + !Compiler.isIntrinsicAvailable(CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION, "com.sun.crypto.provider.AES_Crypt", "implEncryptBlock", byte[].class, int.class, byte[].class, int.class)) { throw new SkippedException("AES intrinsic is not available"); } if (mode.equals("GCM") && diff --git a/test/hotspot/jtreg/compiler/cpuflags/AESIntrinsicsBase.java b/test/hotspot/jtreg/compiler/cpuflags/AESIntrinsicsBase.java index 2ed3fd81e1c..9f36aae4579 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/AESIntrinsicsBase.java +++ b/test/hotspot/jtreg/compiler/cpuflags/AESIntrinsicsBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ public abstract class AESIntrinsicsBase { + ".provider\\.CipherBlockChaining::" + "(implEncrypt|implDecrypt) \\([0-9]+ bytes\\)\\s+\\(intrinsic[,\\)]"; public static final String AES_INTRINSIC = "com\\.sun\\.crypto\\" - + ".provider\\.AESCrypt::(implEncryptBlock|implDecryptBlock) \\([0-9]+ " + + ".provider\\.AES_Crypt::(implEncryptBlock|implDecryptBlock) \\([0-9]+ " + "bytes\\)\\s+\\(intrinsic[,\\)]"; public static final String USE_AES = "UseAES"; public static final String USE_AES_INTRINSICS = "UseAESIntrinsics"; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotJVMCIRuntime.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotJVMCIRuntime.java index e5d1da81309..e62de99f366 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotJVMCIRuntime.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotJVMCIRuntime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,7 +114,7 @@ public class TestHotSpotJVMCIRuntime { VirtualObjectLayoutTest.class, TestHotSpotJVMCIRuntime.class)); try { - classes.add(Class.forName("com.sun.crypto.provider.AESCrypt")); + classes.add(Class.forName("com.sun.crypto.provider.AES_Crypt")); classes.add(Class.forName("com.sun.crypto.provider.CipherBlockChaining")); } catch (ClassNotFoundException e) { // Extension classes not available diff --git a/test/micro/org/openjdk/bench/javax/crypto/AESDecrypt.java b/test/micro/org/openjdk/bench/javax/crypto/AESDecrypt.java new file mode 100644 index 00000000000..0514a6d25f3 --- /dev/null +++ b/test/micro/org/openjdk/bench/javax/crypto/AESDecrypt.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.javax.crypto; + +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@OutputTimeUnit(TimeUnit.SECONDS) +@State(Scope.Thread) +public class AESDecrypt { + + @Param("10000000") + private int count; + + private Cipher cipher; + private byte[] src; + private byte[] ct; + + @Setup + public void setup() throws Exception { + SecretKeySpec keySpec = new SecretKeySpec(new byte[]{-80, -103, -1, 68, -29, -94, 61, -52, 93, -59, -128, 105, 110, 88, 44, 105}, "AES"); + IvParameterSpec iv = new IvParameterSpec(new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); + + cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); + + src = new byte[count]; + new Random(1).nextBytes(src); + + ct = cipher.doFinal(src); + + cipher.init(Cipher.DECRYPT_MODE, keySpec, iv); + } + + @Benchmark + @Fork(jvmArgs = {"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseAES", "-XX:-UseAESIntrinsics"}) + public byte[] testBaseline() throws Exception { + return cipher.doFinal(ct); + } + + @Benchmark + @Fork(jvmArgs = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseAES", "-XX:-UseAESIntrinsics"}) + public byte[] testUseAes() throws Exception { + return cipher.doFinal(ct); + } + + @Benchmark + @Fork(jvmArgs = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseAES", "-XX:+UseAESIntrinsics"}) + public byte[] testUseAesIntrinsics() throws Exception { + return cipher.doFinal(ct); + } + +} From d720a8491b2556373b2686a129c306deefafd671 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 24 Oct 2025 00:16:18 +0000 Subject: [PATCH 047/736] 8343220: Add test cases to AppContentTest jpackage test Reviewed-by: almatvee --- .../jdk/jpackage/internal/util/FileUtils.java | 12 + .../jpackage/test/ConfigurationTarget.java | 21 + .../helpers/jdk/jpackage/test/TKit.java | 10 +- .../tools/jpackage/share/AppContentTest.java | 728 ++++++++++++++---- 4 files changed, 639 insertions(+), 132 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java index 8ac88c13e1d..cb1bcaa51b1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java @@ -30,6 +30,7 @@ import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; @@ -106,6 +107,17 @@ public final class FileUtils { private static record CopyAction(Path src, Path dest) { void apply(CopyOption... options) throws IOException { + if (List.of(options).contains(StandardCopyOption.REPLACE_EXISTING)) { + // They requested copying with replacing the existing content. + if (src == null && Files.isRegularFile(dest)) { + // This copy action creates a directory, but a file at the same path already exists, so delete it. + Files.deleteIfExists(dest); + } else if (src != null && Files.isDirectory(dest)) { + // This copy action copies a file, but a directory at the same path exists already, so delete it. + deleteRecursive(dest); + } + } + if (src == null) { Files.createDirectories(dest); } else { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ConfigurationTarget.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ConfigurationTarget.java index ba3131a7680..0d68d055b92 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ConfigurationTarget.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ConfigurationTarget.java @@ -62,6 +62,27 @@ public record ConfigurationTarget(Optional cmd, Optional verifier) { + cmd.ifPresent(Objects.requireNonNull(verifier)); + test.ifPresent(v -> { + v.addInstallVerifier(verifier::accept); + }); + return this; + } + + public ConfigurationTarget addRunOnceInitializer(Consumer initializer) { + Objects.requireNonNull(initializer); + cmd.ifPresent(_ -> { + initializer.accept(this); + }); + test.ifPresent(v -> { + v.addRunOnceInitializer(() -> { + initializer.accept(this); + }); + }); + return this; + } + public ConfigurationTarget add(AdditionalLauncher addLauncher) { return apply(addLauncher::applyTo, addLauncher::applyTo); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index a19b3697a81..baeeda4e569 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -26,6 +26,7 @@ import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; import static java.util.stream.Collectors.toSet; import static jdk.jpackage.internal.util.function.ThrowingBiFunction.toBiFunction; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import java.io.Closeable; @@ -896,7 +897,14 @@ public final class TKit { public static void assertSymbolicLinkExists(Path path) { assertPathExists(path, true); assertTrue(Files.isSymbolicLink(path), String.format - ("Check [%s] is a symbolic link", path)); + ("Check [%s] is a symbolic link", Objects.requireNonNull(path))); + } + + public static void assertSymbolicLinkTarget(Path symlinkPath, Path expectedTargetPath) { + assertSymbolicLinkExists(symlinkPath); + var targetPath = toFunction(Files::readSymbolicLink).apply(symlinkPath); + assertEquals(expectedTargetPath, targetPath, + String.format("Check the target of the symbolic link [%s]", symlinkPath)); } public static void assertFileExists(Path path) { diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index 2c6498a631b..5b5734df61d 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -21,24 +21,43 @@ * questions. */ -import static jdk.internal.util.OperatingSystem.LINUX; -import static jdk.internal.util.OperatingSystem.MACOS; +import static java.util.Map.entry; import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toMap; +import static jdk.internal.util.OperatingSystem.MACOS; +import static jdk.internal.util.OperatingSystem.WINDOWS; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import jdk.jpackage.internal.util.FileUtils; -import jdk.jpackage.internal.util.function.ThrowingFunction; +import jdk.jpackage.internal.util.IdentityWrapper; +import jdk.jpackage.internal.util.function.ThrowingSupplier; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.ConfigurationTarget; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.TKit; /** @@ -57,68 +76,23 @@ import jdk.jpackage.test.JPackageStringBundle; */ public class AppContentTest { - private static final String TEST_JAVA = "apps/PrintEnv.java"; - private static final String TEST_DUKE = "apps/dukeplug.png"; - private static final String TEST_DUKE_LINK = "dukeplugLink.txt"; - private static final String TEST_DIR = "apps"; - private static final String TEST_BAD = "non-existant"; - - // On OSX `--app-content` paths will be copied into the "Contents" folder - // of the output app image. - // "codesign" imposes restrictions on the directory structure of "Contents" folder. - // In particular, random files should be placed in "Contents/Resources" folder - // otherwise "codesign" will fail to sign. - // Need to prepare arguments for `--app-content` accordingly. - private static final boolean copyInResources = TKit.isOSX(); - - private static final String RESOURCES_DIR = "Resources"; - private static final String LINKS_DIR = "Links"; + @Test + @ParameterSupplier + @ParameterSupplier(value="testSymlink", ifNotOS = WINDOWS) + public void test(TestSpec testSpec) throws Exception { + testSpec.test(new ConfigurationTarget(new PackageTest().configureHelloApp())); + } @Test - // include two files in two options - @Parameter({TEST_JAVA, TEST_DUKE}) - // try to include non-existant content - @Parameter({TEST_JAVA, TEST_BAD}) - // two files in one option and a dir tree in another option. - @Parameter({TEST_JAVA + "," + TEST_DUKE, TEST_DIR}) - // include one file and one link to the file - @Parameter(value = {TEST_JAVA, TEST_DUKE_LINK}, ifOS = {MACOS,LINUX}) - public void test(String... args) throws Exception { - final List testPathArgs = List.of(args); - final int expectedJPackageExitCode; - if (testPathArgs.contains(TEST_BAD)) { - expectedJPackageExitCode = 1; - } else { - expectedJPackageExitCode = 0; - } - - var appContentInitializer = new AppContentInitializer(testPathArgs); - - new PackageTest().configureHelloApp() - .addRunOnceInitializer(appContentInitializer::initAppContent) - .addInitializer(appContentInitializer::applyTo) - .addInstallVerifier(cmd -> { - for (String arg : testPathArgs) { - List paths = Arrays.asList(arg.split(",")); - for (String p : paths) { - Path name = Path.of(p).getFileName(); - if (isSymlinkPath(name)) { - TKit.assertSymbolicLinkExists(getAppContentRoot(cmd) - .resolve(LINKS_DIR).resolve(name)); - } else { - TKit.assertPathExists(getAppContentRoot(cmd) - .resolve(name), true); - } - } - } - }) - .setExpectedExitCode(expectedJPackageExitCode) - .run(); + @ParameterSupplier("test") + @ParameterSupplier(value="testSymlink", ifNotOS = WINDOWS) + public void testAppImage(TestSpec testSpec) throws Exception { + testSpec.test(new ConfigurationTarget(JPackageCommand.helloAppImage())); } @Test(ifOS = MACOS) - @Parameter({TEST_DIR, "warning.non.standard.contents.sub.dir"}) - @Parameter({TEST_DUKE, "warning.app.content.is.not.dir"}) + @Parameter({"apps", "warning.non.standard.contents.sub.dir"}) + @Parameter({"apps/dukeplug.png", "warning.app.content.is.not.dir"}) public void testWarnings(String testPath, String warningId) throws Exception { final var appContentValue = TKit.TEST_SRC_ROOT.resolve(testPath); final var expectedWarning = JPackageStringBundle.MAIN.cannedFormattedString( @@ -126,96 +100,588 @@ public class AppContentTest { JPackageCommand.helloAppImage() .addArguments("--app-content", appContentValue) + .setFakeRuntime() .validateOutput(expectedWarning) .executeIgnoreExitCode(); } + public static Collection test() { + return Stream.of( + build().add(TEST_JAVA).add(TEST_DUKE), + build().add(TEST_JAVA).add(TEST_BAD), + build().startGroup().add(TEST_JAVA).add(TEST_DUKE).endGroup().add(TEST_DIR), + // Same directory specified multiple times. + build().add(TEST_DIR).add(TEST_DIR), + // Same file specified multiple times. + build().add(TEST_JAVA).add(TEST_JAVA), + // Two files with the same name but different content. + build() + .add(createTextFileContent("welcome.txt", "Welcome")) + .add(createTextFileContent("welcome.txt", "Benvenuti")), + // Same name: one is a directory, another is a file. + build().add(createTextFileContent("a/b/c/d", "Foo")).add(createTextFileContent("a", "Bar")), + // Same name: one is a file, another is a directory. + build().add(createTextFileContent("a", "Bar")).add(createTextFileContent("a/b/c/d", "Foo")) + ).map(TestSpec.Builder::create).map(v -> { + return new Object[] {v}; + }).toList(); + } + + public static Collection testSymlink() { + return Stream.of( + build().add(TEST_JAVA) + .add(new SymlinkContentFactory("Links", "duke-link", "duke-target")) + .add(new SymlinkContentFactory("", "a/b/foo-link", "c/bar-target")) + ).map(TestSpec.Builder::create).map(v -> { + return new Object[] {v}; + }).toList(); + } + + public record TestSpec(List> contentFactories) { + public TestSpec { + contentFactories.stream().flatMap(List::stream).forEach(Objects::requireNonNull); + } + + @Override + public String toString() { + return contentFactories.stream().map(group -> { + return group.stream().map(ContentFactory::toString).collect(joining(",")); + }).collect(joining("; ")); + } + + void test(ConfigurationTarget target) { + final int expectedJPackageExitCode; + if (contentFactories.stream().flatMap(List::stream).anyMatch(TEST_BAD::equals)) { + expectedJPackageExitCode = 1; + } else { + expectedJPackageExitCode = 0; + } + + final List> allContent = new ArrayList<>(); + + target.addInitializer(JPackageCommand::setFakeRuntime) + .addRunOnceInitializer(_ -> { + contentFactories.stream().map(group -> { + return group.stream().map(ContentFactory::create).toList(); + }).forEach(allContent::add); + }).addInitializer(cmd -> { + allContent.stream().map(group -> { + return Stream.of("--app-content", group.stream() + .map(Content::paths) + .flatMap(List::stream) + .map(appContentArg -> { + if (COPY_IN_RESOURCES && Optional.ofNullable(appContentArg.getParent()) + .map(Path::getFileName) + .map(RESOURCES_DIR::equals) + .orElse(false)) { + return appContentArg.getParent(); + } else { + return appContentArg; + } + }) + .map(Path::toString) + .collect(joining(","))); + }).flatMap(x -> x).forEachOrdered(cmd::addArgument); + }); + + target.cmd().ifPresent(cmd -> { + if (expectedJPackageExitCode == 0) { + cmd.executeAndAssertImageCreated(); + } else { + cmd.execute(expectedJPackageExitCode); + } + }); + + target.addInstallVerifier(cmd -> { + var appContentRoot = getAppContentRoot(cmd); + + Set disabledVerifiers = new HashSet<>(); + + var verifiers = allContent.stream().flatMap(List::stream).flatMap(content -> { + return StreamSupport.stream(content.verifiers(appContentRoot).spliterator(), false).map(verifier -> { + return new PathVerifierWithOrigin(verifier, content); + }); + }).collect(toMap(PathVerifierWithOrigin::path, x -> x, (first, second) -> { + // The same file in the content directory is sourced from multiple origins. + // jpackage will handle this case such that the following origins overwrite preceding origins. + // Scratch all path verifiers affected by overrides. + first.getNestedVerifiers(appContentRoot, first.path()).forEach(disabledVerifiers::add); + return second; + }, TreeMap::new)).values().stream() + .map(PathVerifierWithOrigin::verifier) + .filter(Predicate.not(disabledVerifiers::contains)) + .filter(verifier -> { + if (!(verifier instanceof DirectoryVerifier dirVerifier)) { + return true; + } else { + try { + // Run the directory verifier if the directory is empty. + // Otherwise, it just pollutes the test log. + return isDirectoryEmpty(verifier.path()); + } catch (NoSuchFileException ex) { + // If an MSI contains an empty directory, it will be installed but not created when the MSI is unpacked. + // In the latter the control flow will reach this point. + if (dirVerifier.isEmpty() + && PackageType.WINDOWS.contains(cmd.packageType()) + && cmd.isPackageUnpacked(String.format( + "Expected empty directory [%s] is missing", verifier.path()))) { + return false; + } + throw new UncheckedIOException(ex); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + }) + .toList(); + + verifiers.forEach(PathVerifier::verify); + }); + + target.test().ifPresent(test -> { + test.setExpectedExitCode(expectedJPackageExitCode).run(); + }); + } + + static final class Builder { + TestSpec create() { + return new TestSpec(groups); + } + + final class GroupBuilder { + GroupBuilder add(ContentFactory cf) { + group.add(Objects.requireNonNull(cf)); + return this; + } + + Builder endGroup() { + if (!group.isEmpty()) { + groups.add(group); + } + return Builder.this; + } + + private final List group = new ArrayList<>(); + } + + Builder add(ContentFactory cf) { + return startGroup().add(cf).endGroup(); + } + + GroupBuilder startGroup() { + return new GroupBuilder(); + } + + private final List> groups = new ArrayList<>(); + } + + private record PathVerifierWithOrigin(PathVerifier verifier, Content origin) { + PathVerifierWithOrigin { + Objects.requireNonNull(verifier); + Objects.requireNonNull(origin); + } + + Path path() { + return verifier.path(); + } + + Stream getNestedVerifiers(Path appContentRoot, Path path) { + if (!path.startsWith(appContentRoot)) { + throw new IllegalArgumentException(); + } + + return StreamSupport.stream(origin.verifiers(appContentRoot).spliterator(), false).filter(v -> { + return v.path().getNameCount() > path.getNameCount() && v.path().startsWith(path); + }); + } + } + } + + private static TestSpec.Builder build() { + return new TestSpec.Builder(); + } + private static Path getAppContentRoot(JPackageCommand cmd) { - Path contentDir = cmd.appLayout().contentDirectory(); - if (copyInResources) { + final Path contentDir = cmd.appLayout().contentDirectory(); + if (COPY_IN_RESOURCES) { return contentDir.resolve(RESOURCES_DIR); } else { return contentDir; } } - private static boolean isSymlinkPath(Path v) { - return v.getFileName().toString().contains("Link"); + private static Path createAppContentRoot() { + if (COPY_IN_RESOURCES) { + return TKit.createTempDirectory("app-content").resolve(RESOURCES_DIR); + } else { + return TKit.createTempDirectory("app-content"); + } } - private static final class AppContentInitializer { - AppContentInitializer(List appContentArgs) { - appContentPathGroups = appContentArgs.stream().map(arg -> { - return Stream.of(arg.split(",")).map(Path::of).toList(); - }).toList(); + private static boolean isDirectoryEmpty(Path path) throws IOException { + if (Files.exists(path) && !Files.isDirectory(path)) { + throw new IllegalArgumentException(); } - void initAppContent() { - jpackageArgs = appContentPathGroups.stream() - .map(AppContentInitializer::initAppContentPaths) - .mapMulti((appContentPaths, consumer) -> { - consumer.accept("--app-content"); - consumer.accept( - appContentPaths.stream().map(Path::toString).collect( - joining(","))); - }).toList(); + try (var files = Files.list(path)) { + return files.findAny().isEmpty(); + } + } + + @FunctionalInterface + private interface ContentFactory { + Content create(); + } + + private interface Content { + List paths(); + Iterable verifiers(Path appContentRoot); + } + + private sealed interface PathVerifier permits + RegularFileVerifier, + DirectoryVerifier, + SymlinkTargetVerifier, + NoPathVerifier { + + Path path(); + void verify(); + } + + private record RegularFileVerifier(Path path, Path srcFile) implements PathVerifier { + RegularFileVerifier { + Objects.requireNonNull(path); + Objects.requireNonNull(srcFile); } - void applyTo(JPackageCommand cmd) { - cmd.addArguments(jpackageArgs); + @Override + public void verify() { + TKit.assertSameFileContent(srcFile, path); + } + } + + private record DirectoryVerifier(Path path, boolean isEmpty, IdentityWrapper origin) implements PathVerifier { + DirectoryVerifier { + Objects.requireNonNull(path); } - private static Path copyAppContentPath(Path appContentPath) throws IOException { - var appContentArg = TKit.createTempDirectory("app-content").resolve(RESOURCES_DIR); - var srcPath = TKit.TEST_SRC_ROOT.resolve(appContentPath); - var dstPath = appContentArg.resolve(srcPath.getFileName()); - FileUtils.copyRecursive(srcPath, dstPath); - return appContentArg; - } - - private static Path createAppContentLink(Path appContentPath) throws IOException { - var appContentArg = TKit.createTempDirectory("app-content"); - Path dstPath; - if (copyInResources) { - appContentArg = appContentArg.resolve(RESOURCES_DIR); - dstPath = appContentArg.resolve(LINKS_DIR) - .resolve(appContentPath.getFileName()); + @Override + public void verify() { + if (isEmpty) { + TKit.assertDirectoryEmpty(path); } else { - appContentArg = appContentArg.resolve(LINKS_DIR); - dstPath = appContentArg.resolve(appContentPath.getFileName()); + TKit.assertDirectoryExists(path); + } + } + } + + private record SymlinkTargetVerifier(Path path, Path targetPath) implements PathVerifier { + SymlinkTargetVerifier { + Objects.requireNonNull(path); + Objects.requireNonNull(targetPath); + } + + @Override + public void verify() { + TKit.assertSymbolicLinkTarget(path, targetPath); + } + } + + private record NoPathVerifier(Path path) implements PathVerifier { + NoPathVerifier { + Objects.requireNonNull(path); + } + + @Override + public void verify() { + TKit.assertPathExists(path, false); + } + } + + private record FileContent(Path path, int level) implements Content { + + FileContent { + Objects.requireNonNull(path); + if ((level < 0) || (path.getNameCount() <= level)) { + throw new IllegalArgumentException(); + } + } + + @Override + public List paths() { + return List.of(appContentOptionValue()); + } + + @Override + public Iterable verifiers(Path appContentRoot) { + List verifiers = new ArrayList<>(); + + var appContentPath = appContentRoot.resolve(pathInAppContentRoot()); + + if (Files.isDirectory(path)) { + try (var walk = Files.walk(path)) { + verifiers.addAll(walk.map(srcFile -> { + var dstFile = appContentPath.resolve(path.relativize(srcFile)); + if (Files.isRegularFile(srcFile)) { + return new RegularFileVerifier(dstFile, srcFile); + } else { + return new DirectoryVerifier(dstFile, + toFunction(AppContentTest::isDirectoryEmpty).apply(srcFile), + new IdentityWrapper<>(this)); + } + }).toList()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } else if (Files.isRegularFile(path)) { + verifiers.add(new RegularFileVerifier(appContentPath, path)); + } else { + verifiers.add(new NoPathVerifier(appContentPath)); } - Files.createDirectories(dstPath.getParent()); - - // Create target file for a link - String tagetName = dstPath.getFileName().toString().replace("Link", ""); - Path targetPath = dstPath.getParent().resolve(tagetName); - Files.write(targetPath, "foo".getBytes()); - // Create link - Files.createSymbolicLink(dstPath, targetPath.getFileName()); - - return appContentArg; - } - - private static List initAppContentPaths(List appContentPaths) { - return appContentPaths.stream().map(appContentPath -> { - if (appContentPath.endsWith(TEST_BAD)) { - return appContentPath; - } else if (isSymlinkPath(appContentPath)) { - return ThrowingFunction.toFunction( - AppContentInitializer::createAppContentLink).apply( - appContentPath); - } else if (copyInResources) { - return ThrowingFunction.toFunction( - AppContentInitializer::copyAppContentPath).apply( - appContentPath); - } else { - return TKit.TEST_SRC_ROOT.resolve(appContentPath); + if (level > 0) { + var cur = appContentPath; + for (int i = 0; i != level; i++) { + cur = cur.getParent(); + verifiers.add(new DirectoryVerifier(cur, false, new IdentityWrapper<>(this))); } - }).toList(); + } + + return verifiers; } - private List jpackageArgs; - private final List> appContentPathGroups; + private Path appContentOptionValue() { + var cur = path; + for (int i = 0; i != level; i++) { + cur = cur.getParent(); + } + return cur; + } + + private Path pathInAppContentRoot() { + return StreamSupport.stream(path.spliterator(), false) + .skip(path.getNameCount() - level - 1) + .reduce(Path::resolve).orElseThrow(); + } } + + /** + * Non-existing content. + */ + private static final class NonExistantPath implements ContentFactory { + @Override + public Content create() { + var nonExistant = TKit.createTempFile("non-existant"); + try { + TKit.deleteIfExists(nonExistant); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + return new FileContent(nonExistant, 0); + } + + @Override + public String toString() { + return "*non-existant*"; + } + } + + /** + * Creates a content from a directory tree. + * + * @param path name of directory where to create a directory tree + */ + private static ContentFactory createDirTreeContent(Path path) { + if (path.isAbsolute()) { + throw new IllegalArgumentException(); + } + + return new FileContentFactory(() -> { + var basedir = TKit.createTempDirectory("content").resolve(path); + + for (var textFile : Map.ofEntries( + entry("woods/moose", "The moose"), + entry("woods/bear", "The bear"), + entry("woods/trees/jay", "The gray jay") + ).entrySet()) { + var src = basedir.resolve(textFile.getKey()); + Files.createDirectories(src.getParent()); + TKit.createTextFile(src, Stream.of(textFile.getValue())); + } + + for (var emptyDir : List.of("sky")) { + Files.createDirectories(basedir.resolve(emptyDir)); + } + + return basedir; + }, path); + } + + private static ContentFactory createDirTreeContent(String path) { + return createDirTreeContent(Path.of(path)); + } + + /** + * Creates a content from a text file. + * + * @param path the path where to copy the text file in app image's content directory + * @param lines the content of the source text file + */ + private static ContentFactory createTextFileContent(Path path, String ... lines) { + if (path.isAbsolute()) { + throw new IllegalArgumentException(); + } + + return new FileContentFactory(() -> { + var srcPath = TKit.createTempDirectory("content").resolve(path); + Files.createDirectories(srcPath.getParent()); + TKit.createTextFile(srcPath, Stream.of(lines)); + return srcPath; + }, path); + } + + private static ContentFactory createTextFileContent(String path, String ... lines) { + return createTextFileContent(Path.of(path), lines); + } + + /** + * Symlink content factory. + * + * @path basedir the directory where to write the content in app image's content + * directory + * @param symlink the path to the symlink relative to {@code basedir} path + * @param symlinked the path to the source file for the symlink + */ + private record SymlinkContentFactory(Path basedir, Path symlink, Path symlinked) implements ContentFactory { + SymlinkContentFactory { + for (final var path : List.of(basedir, symlink, symlinked)) { + if (path.isAbsolute()) { + throw new IllegalArgumentException(); + } + } + } + + SymlinkContentFactory(String basedir, String symlink, String symlinked) { + this(Path.of(basedir), Path.of(symlink), Path.of(symlinked)); + } + + @Override + public Content create() { + final var appContentRoot = createAppContentRoot(); + + final var symlinkPath = appContentRoot.resolve(symlinkPath()); + final var symlinkedPath = appContentRoot.resolve(symlinkedPath()); + try { + Files.createDirectories(symlinkPath.getParent()); + Files.createDirectories(symlinkedPath.getParent()); + // Create the target file for the link. + Files.writeString(symlinkedPath, symlinkedPath().toString()); + // Create the link. + Files.createSymbolicLink(symlinkPath, symlinkTarget()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + + List contentPaths; + if (COPY_IN_RESOURCES) { + contentPaths = List.of(appContentRoot); + } else if (basedir.equals(Path.of(""))) { + contentPaths = Stream.of(symlinkPath(), symlinkedPath()).map(path -> { + return path.getName(0); + }).map(appContentRoot::resolve).toList(); + } else { + contentPaths = List.of(appContentRoot.resolve(basedir)); + } + + return new Content() { + @Override + public List paths() { + return contentPaths; + } + + @Override + public Iterable verifiers(Path appContentRoot) { + return List.of( + new RegularFileVerifier(appContentRoot.resolve(symlinkedPath()), symlinkedPath), + new SymlinkTargetVerifier(appContentRoot.resolve(symlinkPath()), symlinkTarget()) + ); + } + }; + } + + @Override + public String toString() { + return String.format("symlink:[%s]->[%s][%s]", symlinkPath(), symlinkedPath(), symlinkTarget()); + } + + private Path symlinkPath() { + return basedir.resolve(symlink); + } + + private Path symlinkedPath() { + return basedir.resolve(symlinked); + } + + private Path symlinkTarget() { + return Optional.ofNullable(symlinkPath().getParent()).map(dir -> { + return dir.relativize(symlinkedPath()); + }).orElseGet(this::symlinkedPath); + } + } + + private static final class FileContentFactory implements ContentFactory { + + FileContentFactory(ThrowingSupplier factory, Path pathInAppContentRoot) { + this.factory = ThrowingSupplier.toSupplier(factory); + this.pathInAppContentRoot = pathInAppContentRoot; + if (pathInAppContentRoot.isAbsolute()) { + throw new IllegalArgumentException(); + } + } + + @Override + public Content create() { + Path srcPath = factory.get(); + if (!srcPath.endsWith(pathInAppContentRoot)) { + throw new IllegalArgumentException(); + } + + Path dstPath; + if (!COPY_IN_RESOURCES) { + dstPath = srcPath; + } else { + var contentDir = createAppContentRoot(); + dstPath = contentDir.resolve(pathInAppContentRoot); + try { + FileUtils.copyRecursive(srcPath, dstPath); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + return new FileContent(dstPath, pathInAppContentRoot.getNameCount() - 1); + } + + @Override + public String toString() { + return pathInAppContentRoot.toString(); + } + + private final Supplier factory; + private final Path pathInAppContentRoot; + } + + private static final ContentFactory TEST_JAVA = createTextFileContent("apps/PrintEnv.java", "Not what someone would expect"); + private static final ContentFactory TEST_DUKE = createTextFileContent("duke.txt", "Hi Duke!"); + private static final ContentFactory TEST_DIR = createDirTreeContent("apps"); + private static final ContentFactory TEST_BAD = new NonExistantPath(); + + // On OSX `--app-content` paths will be copied into the "Contents" folder + // of the output app image. + // "codesign" imposes restrictions on the directory structure of "Contents" folder. + // In particular, random files should be placed in "Contents/Resources" folder + // otherwise "codesign" will fail to sign. + // Need to prepare arguments for `--app-content` accordingly. + private static final boolean COPY_IN_RESOURCES = TKit.isOSX(); + + private static final Path RESOURCES_DIR = Path.of("Resources"); } From 586235896536cde293402167775d4d60f1426a9e Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 24 Oct 2025 00:40:13 +0000 Subject: [PATCH 048/736] 8370013: Refactor Double.toHexString to eliminate regex and StringBuilder Reviewed-by: rgiulietti, darcy --- .../share/classes/java/lang/Double.java | 120 +++++++++++------- test/jdk/java/lang/Double/ToHexString.java | 21 +++ .../{FloatingDecimal.java => Doubles.java} | 13 +- 3 files changed, 105 insertions(+), 49 deletions(-) rename test/micro/org/openjdk/bench/java/lang/{FloatingDecimal.java => Doubles.java} (89%) diff --git a/src/java.base/share/classes/java/lang/Double.java b/src/java.base/share/classes/java/lang/Double.java index 6cee75cea2b..53b027dd773 100644 --- a/src/java.base/share/classes/java/lang/Double.java +++ b/src/java.base/share/classes/java/lang/Double.java @@ -1,5 +1,6 @@ /* * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +34,7 @@ import java.util.Optional; import jdk.internal.math.FloatingDecimal; import jdk.internal.math.DoubleConsts; import jdk.internal.math.DoubleToDecimal; +import jdk.internal.util.DecimalDigits; import jdk.internal.vm.annotation.IntrinsicCandidate; /** @@ -699,56 +701,80 @@ public final class Double extends Number * 7.19.6.1; however, the output of this method is more * tightly specified. */ - if (!isFinite(d) ) + if (!isFinite(d)) { // For infinity and NaN, use the decimal output. return Double.toString(d); - else { - // Initialized to maximum size of output. - StringBuilder answer = new StringBuilder(24); - - if (Math.copySign(1.0, d) == -1.0) // value is negative, - answer.append("-"); // so append sign info - - answer.append("0x"); - - d = Math.abs(d); - - if(d == 0.0) { - answer.append("0.0p0"); - } else { - boolean subnormal = (d < Double.MIN_NORMAL); - - // Isolate significand bits and OR in a high-order bit - // so that the string representation has a known - // length. - long signifBits = (Double.doubleToLongBits(d) - & DoubleConsts.SIGNIF_BIT_MASK) | - 0x1000000000000000L; - - // Subnormal values have a 0 implicit bit; normal - // values have a 1 implicit bit. - answer.append(subnormal ? "0." : "1."); - - // Isolate the low-order 13 digits of the hex - // representation. If all the digits are zero, - // replace with a single 0; otherwise, remove all - // trailing zeros. - String signif = Long.toHexString(signifBits).substring(3,16); - answer.append(signif.equals("0000000000000") ? // 13 zeros - "0": - signif.replaceFirst("0{1,12}$", "")); - - answer.append('p'); - // If the value is subnormal, use the E_min exponent - // value for double; otherwise, extract and report d's - // exponent (the representation of a subnormal uses - // E_min -1). - answer.append(subnormal ? - Double.MIN_EXPONENT: - Math.getExponent(d)); - } - return answer.toString(); } + + long doubleToLongBits = Double.doubleToLongBits(d); + boolean negative = doubleToLongBits < 0; + + if (d == 0.0) { + return negative ? "-0x0.0p0" : "0x0.0p0"; + } + d = Math.abs(d); + // Check if the value is subnormal (less than the smallest normal value) + boolean subnormal = d < Double.MIN_NORMAL; + + // Isolate significand bits and OR in a high-order bit + // so that the string representation has a known length. + // This ensures we always have 13 hex digits to work with (52 bits / 4 bits per hex digit) + long signifBits = doubleToLongBits & DoubleConsts.SIGNIF_BIT_MASK; + + // Calculate the number of trailing zeros in the significand (in groups of 4 bits) + // This is used to remove trailing zeros from the hex representation + // We limit to 12 because we want to keep at least 1 hex digit (13 total - 12 = 1) + // assert 0 <= trailingZeros && trailingZeros <= 12 + int trailingZeros = Long.numberOfTrailingZeros(signifBits | 1L << 4 * 12) >> 2; + + // Determine the exponent value based on whether the number is subnormal or normal + // Subnormal numbers use the minimum exponent, normal numbers use the actual exponent + int exp = subnormal ? Double.MIN_EXPONENT : Math.getExponent(d); + + // Calculate the total length of the resulting string: + // Sign (optional) + prefix "0x" + implicit bit + "." + hex digits + "p" + exponent + int charlen = (negative ? 1 : 0) // sign character + + 4 // "0x1." or "0x0." + + 13 - trailingZeros // hex digits (13 max, minus trailing zeros) + + 1 // "p" + + DecimalDigits.stringSize(exp) // exponent + ; + + // Create a byte array to hold the result characters + byte[] chars = new byte[charlen]; + int index = 0; + + // Add the sign character if the number is negative + if (negative) { // value is negative + chars[index++] = '-'; + } + + // Add the prefix and the implicit bit ('1' for normal, '0' for subnormal) + // Subnormal values have a 0 implicit bit; normal values have a 1 implicit bit. + chars[index ] = '0'; // Hex prefix + chars[index + 1] = 'x'; // Hex prefix + chars[index + 2] = (byte) (subnormal ? '0' : '1'); // Implicit bit + chars[index + 3] = '.'; // Decimal point + index += 4; + + // Convert significand to hex digits manually to avoid creating temporary strings + // Extract the 13 hex digits (52 bits) from signifBits + // We need to extract bits 48-51, 44-47, ..., 0-3 (13 groups of 4 bits) + for (int sh = 4 * 12, end = 4 * trailingZeros; sh >= end; sh -= 4) { + // Extract 4 bits at a time from left to right + // Shift right by sh positions and mask with 0xF + // Integer.digits maps values 0-15 to '0'-'f' characters + chars[index++] = Integer.digits[((int)(signifBits >> sh)) & 0xF]; + } + + // Add the exponent indicator + chars[index] = 'p'; + + // Append the exponent value to the character array + // This method writes the decimal representation of exp directly into the byte array + DecimalDigits.uncheckedGetCharsLatin1(exp, charlen, chars); + + return String.newStringWithLatin1Bytes(chars); } /** diff --git a/test/jdk/java/lang/Double/ToHexString.java b/test/jdk/java/lang/Double/ToHexString.java index 912835b7aeb..c408f74fa63 100644 --- a/test/jdk/java/lang/Double/ToHexString.java +++ b/test/jdk/java/lang/Double/ToHexString.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,6 +175,26 @@ public class ToHexString { {"+4.9e-324", "0000000000000001"}, {"-4.9e-324", "8000000000000001"}, + // Test cases for trailing zeros in significand + // These test the removal of trailing zeros in the hexadecimal representation + // The comments indicate the number of trailing zeros removed from the significand + // For "0x1.0p1", there are 13 trailing zeros in the significand, but only 12 are removed + // as we always keep at least one hex digit in the significand + {"0x1.0p1", "4000000000000000"}, // 12 trailing zeros removed (13 total, but only 12 removed) + {"0x1.1p1", "4001000000000000"}, // 12 trailing zeros removed (all zeros after '1') + {"0x1.01p1", "4000100000000000"}, // 11 trailing zeros removed + {"0x1.001p1", "4000010000000000"}, // 10 trailing zeros removed + {"0x1.0001p1", "4000001000000000"}, // 9 trailing zeros removed + {"0x1.00001p1", "4000000100000000"}, // 8 trailing zeros removed + {"0x1.000001p1", "4000000010000000"}, // 7 trailing zeros removed + {"0x1.0000001p1", "4000000001000000"}, // 6 trailing zeros removed + {"0x1.00000001p1", "4000000000100000"}, // 5 trailing zeros removed + {"0x1.000000001p1", "4000000000010000"}, // 4 trailing zeros removed + {"0x1.0000000001p1", "4000000000001000"}, // 3 trailing zeros removed + {"0x1.00000000001p1", "4000000000000100"}, // 2 trailing zeros removed + {"0x1.000000000001p1", "4000000000000010"}, // 1 trailing zero removed (minimum) + {"0x1.0000000000001p1", "4000000000000001"}, // 0 trailing zeros removed (no trailing zeros to remove) + // fdlibm k_sin.c {"+5.00000000000000000000e-01", "3FE0000000000000"}, {"-1.66666666666666324348e-01", "BFC5555555555549"}, diff --git a/test/micro/org/openjdk/bench/java/lang/FloatingDecimal.java b/test/micro/org/openjdk/bench/java/lang/Doubles.java similarity index 89% rename from test/micro/org/openjdk/bench/java/lang/FloatingDecimal.java rename to test/micro/org/openjdk/bench/java/lang/Doubles.java index b8d29aabc84..50c295900af 100644 --- a/test/micro/org/openjdk/bench/java/lang/FloatingDecimal.java +++ b/test/micro/org/openjdk/bench/java/lang/Doubles.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +48,7 @@ import java.util.concurrent.TimeUnit; @Warmup(iterations = 10, time = 1) @Measurement(iterations = 5, time = 2) @Fork(3) -public class FloatingDecimal { +public class Doubles { private double[] randomArray, twoDecimalsArray, integerArray; private static final int TESTSIZE = 1000; @@ -65,6 +66,14 @@ public class FloatingDecimal { } } + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void toHexString(Blackhole bh) { + for (double d : randomArray) { + bh.consume(Double.toHexString(d)); + } + } + /** Tests Double.toString on double values generated from Random.nextDouble() */ @Benchmark @OperationsPerInvocation(TESTSIZE) From 87645afa052a87ab2af9602c8fafc2a707c77c19 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 24 Oct 2025 05:43:16 +0000 Subject: [PATCH 049/736] 8370389: JavaFrameAnchor on s390 has unnecessary barriers Reviewed-by: lucy, aph --- src/hotspot/cpu/s390/javaFrameAnchor_s390.hpp | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/hotspot/cpu/s390/javaFrameAnchor_s390.hpp b/src/hotspot/cpu/s390/javaFrameAnchor_s390.hpp index ae8b8766159..307034ca0cd 100644 --- a/src/hotspot/cpu/s390/javaFrameAnchor_s390.hpp +++ b/src/hotspot/cpu/s390/javaFrameAnchor_s390.hpp @@ -35,38 +35,32 @@ // 3 - restoring an old state (javaCalls). inline void clear(void) { + // No hardware barriers are necessary. All members are volatile and the profiler + // is run from a signal handler and only observers the thread its running on. + // Clearing _last_Java_sp must be first. - OrderAccess::release(); + _last_Java_sp = nullptr; - // Fence? - OrderAccess::fence(); _last_Java_pc = nullptr; } inline void set(intptr_t* sp, address pc) { _last_Java_pc = pc; - - OrderAccess::release(); _last_Java_sp = sp; } void copy(JavaFrameAnchor* src) { - // In order to make sure the transition state is valid for "this" + // No hardware barriers are necessary. All members are volatile and the profiler + // is run from a signal handler and only observers the thread its running on. + // we must clear _last_Java_sp before copying the rest of the new data. - // Hack Alert: Temporary bugfix for 4717480/4721647 - // To act like previous version (pd_cache_state) don't null _last_Java_sp - // unless the value is changing. - // if (_last_Java_sp != src->_last_Java_sp) { - OrderAccess::release(); _last_Java_sp = nullptr; - OrderAccess::fence(); } _last_Java_pc = src->_last_Java_pc; // Must be last so profiler will always see valid frame if has_last_frame() is true. - OrderAccess::release(); _last_Java_sp = src->_last_Java_sp; } @@ -80,7 +74,7 @@ intptr_t* last_Java_fp(void) { return nullptr; } intptr_t* last_Java_sp() const { return _last_Java_sp; } - void set_last_Java_sp(intptr_t* sp) { OrderAccess::release(); _last_Java_sp = sp; } + void set_last_Java_sp(intptr_t* sp) { _last_Java_sp = sp; } address last_Java_pc(void) { return _last_Java_pc; } From 26eed3b61e4987a2998f941d7d26790493850612 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 24 Oct 2025 07:25:53 +0000 Subject: [PATCH 050/736] 8068293: [TEST_BUG] Test closed/com/sun/java/swing/plaf/motif/InternalFrame/4150591/bug4150591.java fails with GTKLookAndFeel Reviewed-by: serb, tr --- test/jdk/javax/swing/plaf/motif/bug4150591.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/jdk/javax/swing/plaf/motif/bug4150591.java b/test/jdk/javax/swing/plaf/motif/bug4150591.java index 66c668a441c..f3614908cff 100644 --- a/test/jdk/javax/swing/plaf/motif/bug4150591.java +++ b/test/jdk/javax/swing/plaf/motif/bug4150591.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ import com.sun.java.swing.plaf.motif.MotifInternalFrameTitlePane; import javax.swing.JInternalFrame; +import javax.swing.UIManager; /* * @test @@ -36,7 +37,8 @@ import javax.swing.JInternalFrame; */ public class bug4150591 { - public static void main(String[] args) { + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); MotifInternalFrameTitlePane mtp = new MotifInternalFrameTitlePane(new JInternalFrame()); } } From b31bbfcf2f13fa5b16762f5384d95c2b5d9c5705 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 24 Oct 2025 08:26:24 +0000 Subject: [PATCH 051/736] 8368787: Error reporting: hs_err files should show instructions when referencing code in nmethods Reviewed-by: stuefe, aph, mbaesken, shade --- src/hotspot/share/code/codeBlob.cpp | 1 + src/hotspot/share/code/nmethod.cpp | 40 +++++++++++++++++++++++++++++ src/hotspot/share/code/nmethod.hpp | 1 + 3 files changed, 42 insertions(+) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 18e77520139..e901d560616 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -910,6 +910,7 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const nm->print_nmethod(true); } else { nm->print_on(st); + nm->print_code_snippet(st, addr); } return; } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index a99e753180d..8e6a1797480 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -4308,6 +4308,46 @@ void nmethod::print_value_on_impl(outputStream* st) const { #endif } +void nmethod::print_code_snippet(outputStream* st, address addr) const { + if (entry_point() <= addr && addr < code_end()) { + // Pointing into the nmethod's code. Try to disassemble some instructions around addr. + // Determine conservative start and end points. + address start; + if (frame_complete_offset() != CodeOffsets::frame_never_safe && + addr >= code_begin() + frame_complete_offset()) { + start = code_begin() + frame_complete_offset(); + } else { + start = (addr < verified_entry_point()) ? entry_point() : verified_entry_point(); + } + address start_for_hex_dump = start; // We can choose a different starting point for hex dump, below. + address end = code_end(); + + // Try using relocations to find closer instruction start and end points. + // (Some platforms have variable length instructions and can only + // disassemble correctly at instruction start addresses.) + RelocIterator iter((nmethod*)this, start); + while (iter.next() && iter.addr() < addr) { // find relocation before addr + // Note: There's a relocation which doesn't point to an instruction start: + // ZBarrierRelocationFormatStoreGoodAfterMov with ZGC on x86_64 + // We could detect and skip it, but hex dump is still usable when + // disassembler produces garbage in such a very rare case. + start = iter.addr(); + // We want at least 64 Bytes ahead in hex dump. + if (iter.addr() <= (addr - 64)) start_for_hex_dump = iter.addr(); + } + if (iter.has_current()) { + if (iter.addr() == addr) iter.next(); // find relocation after addr + if (iter.has_current()) end = iter.addr(); + } + + // Always print hex. Disassembler may still have problems when hitting an incorrect instruction start. + os::print_hex_dump(st, start_for_hex_dump, end, 1, /* print_ascii=*/false); + if (!Disassembler::is_abstract()) { + Disassembler::decode(start, end, st); + } + } +} + #ifndef PRODUCT void nmethod::print_calls(outputStream* st) { diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 3763b81f887..bce0181a3ec 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -1008,6 +1008,7 @@ public: void print_on_impl(outputStream* st) const; void print_code(); void print_value_on_impl(outputStream* st) const; + void print_code_snippet(outputStream* st, address addr) const; #if defined(SUPPORT_DATA_STRUCTS) // print output in opt build for disassembler library From b7a4c9ced82717434e43b3f3a0a57083f4005f32 Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Fri, 24 Oct 2025 08:55:17 +0000 Subject: [PATCH 052/736] 8366240: Improve memory ordering in new CPU Time Profiler Reviewed-by: jbachorik, krk, zgu --- .../sampling/jfrCPUTimeThreadSampler.cpp | 38 ++++++++----------- .../sampling/jfrCPUTimeThreadSampler.hpp | 20 ++++++---- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp index 7507b9c994e..031dfb7e8ad 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp @@ -82,14 +82,7 @@ JfrCPUTimeTraceQueue::~JfrCPUTimeTraceQueue() { bool JfrCPUTimeTraceQueue::enqueue(JfrCPUTimeSampleRequest& request) { assert(JavaThread::current()->jfr_thread_local()->is_cpu_time_jfr_enqueue_locked(), "invariant"); assert(&JavaThread::current()->jfr_thread_local()->cpu_time_jfr_queue() == this, "invariant"); - u4 elementIndex; - do { - elementIndex = AtomicAccess::load_acquire(&_head); - if (elementIndex >= _capacity) { - return false; - } - } while (AtomicAccess::cmpxchg(&_head, elementIndex, elementIndex + 1) != elementIndex); - _data[elementIndex] = request; + _data[_head++] = request; return true; } @@ -101,19 +94,19 @@ JfrCPUTimeSampleRequest& JfrCPUTimeTraceQueue::at(u4 index) { static volatile u4 _lost_samples_sum = 0; u4 JfrCPUTimeTraceQueue::size() const { - return AtomicAccess::load_acquire(&_head); + return _head; } void JfrCPUTimeTraceQueue::set_size(u4 size) { - AtomicAccess::release_store(&_head, size); + _head = size; } u4 JfrCPUTimeTraceQueue::capacity() const { - return AtomicAccess::load_acquire(&_capacity); + return _capacity; } void JfrCPUTimeTraceQueue::set_capacity(u4 capacity) { - if (capacity == AtomicAccess::load(&_capacity)) { + if (capacity == _capacity) { return; } _head = 0; @@ -126,15 +119,15 @@ void JfrCPUTimeTraceQueue::set_capacity(u4 capacity) { } else { _data = nullptr; } - AtomicAccess::release_store(&_capacity, capacity); + _capacity = capacity; } bool JfrCPUTimeTraceQueue::is_empty() const { - return AtomicAccess::load_acquire(&_head) == 0; + return _head == 0; } u4 JfrCPUTimeTraceQueue::lost_samples() const { - return AtomicAccess::load(&_lost_samples); + return _lost_samples; } void JfrCPUTimeTraceQueue::increment_lost_samples() { @@ -143,7 +136,7 @@ void JfrCPUTimeTraceQueue::increment_lost_samples() { } void JfrCPUTimeTraceQueue::increment_lost_samples_due_to_queue_full() { - AtomicAccess::inc(&_lost_samples_due_to_queue_full); + _lost_samples_due_to_queue_full++; } u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples() { @@ -151,7 +144,9 @@ u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples() { } u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples_due_to_queue_full() { - return AtomicAccess::xchg(&_lost_samples_due_to_queue_full, (u4)0); + u4 lost = _lost_samples_due_to_queue_full; + _lost_samples_due_to_queue_full = 0; + return lost; } void JfrCPUTimeTraceQueue::init() { @@ -159,7 +154,7 @@ void JfrCPUTimeTraceQueue::init() { } void JfrCPUTimeTraceQueue::clear() { - AtomicAccess::release_store(&_head, (u4)0); + _head = 0; } void JfrCPUTimeTraceQueue::resize_if_needed() { @@ -167,9 +162,8 @@ void JfrCPUTimeTraceQueue::resize_if_needed() { if (lost_samples_due_to_queue_full == 0) { return; } - u4 capacity = AtomicAccess::load(&_capacity); - if (capacity < CPU_TIME_QUEUE_MAX_CAPACITY) { - float ratio = (float)lost_samples_due_to_queue_full / (float)capacity; + if (_capacity < CPU_TIME_QUEUE_MAX_CAPACITY) { + float ratio = (float)lost_samples_due_to_queue_full / (float)_capacity; int factor = 1; if (ratio > 8) { // idea is to quickly scale the queue in the worst case factor = ratio; @@ -181,7 +175,7 @@ void JfrCPUTimeTraceQueue::resize_if_needed() { factor = 2; } if (factor > 1) { - u4 new_capacity = MIN2(CPU_TIME_QUEUE_MAX_CAPACITY, capacity * factor); + u4 new_capacity = MIN2(CPU_TIME_QUEUE_MAX_CAPACITY, _capacity * factor); set_capacity(new_capacity); } } diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp index e7c915fc8be..48fe28d22f0 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp @@ -43,19 +43,24 @@ struct JfrCPUTimeSampleRequest { // Fixed size async-signal-safe SPSC linear queue backed by an array. // Designed to be only used under lock and read linearly +// The lock in question is the tri-state CPU time JFR lock in JfrThreadLocal +// This allows us to skip most of the atomic accesses and memory barriers, +// holding a lock acts as a memory barrier +// Only the _lost_samples property is atomic, as it can be accessed even after +// acquiring the lock failed. +// Important to note is that the queue is also only accessed under lock in signal +// handlers. class JfrCPUTimeTraceQueue { - // the default queue capacity, scaled if the sampling period is smaller than 10ms - // when the thread is started - static const u4 CPU_TIME_QUEUE_CAPACITY = 500; - JfrCPUTimeSampleRequest* _data; - volatile u4 _capacity; + u4 _capacity; // next unfilled index - volatile u4 _head; + u4 _head; + // the only property accessible without a lock volatile u4 _lost_samples; - volatile u4 _lost_samples_due_to_queue_full; + + u4 _lost_samples_due_to_queue_full; static const u4 CPU_TIME_QUEUE_INITIAL_CAPACITY = 20; static const u4 CPU_TIME_QUEUE_MAX_CAPACITY = 2000; @@ -82,6 +87,7 @@ public: u4 lost_samples() const; + // the only method callable without holding a lock void increment_lost_samples(); void increment_lost_samples_due_to_queue_full(); From f73e56e24f0edfaeb99e2106a56725ea033bd6d6 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Fri, 24 Oct 2025 09:14:04 +0000 Subject: [PATCH 053/736] 8361894: sun/security/krb5/config/native/TestDynamicStore.java ensure that the test is run with sudo Reviewed-by: rhalade --- .../krb5/config/native/TestDynamicStore.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/security/krb5/config/native/TestDynamicStore.java b/test/jdk/sun/security/krb5/config/native/TestDynamicStore.java index 7e396013a71..0ee559f33e4 100644 --- a/test/jdk/sun/security/krb5/config/native/TestDynamicStore.java +++ b/test/jdk/sun/security/krb5/config/native/TestDynamicStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,15 @@ * @summary SCDynamicStoreConfig works * @modules java.security.jgss/sun.security.krb5 * @library /test/lib - * @run main/manual/native TestDynamicStore + * @run main/manual/native/timeout=180 TestDynamicStore * @requires (os.family == "mac") */ import jdk.test.lib.Asserts; import sun.security.krb5.Config; +import javax.swing.JOptionPane; + // =================== Attention =================== // This test calls a native method implemented in libTestDynamicStore.m // to modify system-level Kerberos 5 settings stored in the dynamic store. @@ -56,6 +58,17 @@ public class TestDynamicStore { public static void main(String[] args) throws Exception { + // Show a popup to remind to run this test as sudo user + // this will only trigger if sudo (root) user is not detected + if (!"root".equals(System.getProperty("user.name"))) { + + JOptionPane.showMessageDialog(null, """ + This test MUST be run as ROOT.\s + Please close and RESTART the test."""); + + Asserts.assertFalse(true, "This test must be run as ROOT"); + } + System.loadLibrary("TestDynamicStore"); Config cfg = Config.getInstance(); From 470eedb1e9d67058ff8d67a5b0c2250d9f9b3fa5 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Fri, 24 Oct 2025 09:46:00 +0000 Subject: [PATCH 054/736] 8370511: test/jdk/javax/swing/JSlider/bug4382876.java does not release previously pressed keys Reviewed-by: psadhukhan, serb, honkar --- test/jdk/javax/swing/JSlider/bug4382876.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/jdk/javax/swing/JSlider/bug4382876.java b/test/jdk/javax/swing/JSlider/bug4382876.java index b9ec64aab21..b0988de3cab 100644 --- a/test/jdk/javax/swing/JSlider/bug4382876.java +++ b/test/jdk/javax/swing/JSlider/bug4382876.java @@ -48,8 +48,8 @@ public class bug4382876 { private static Robot r; private static JFrame f; private static JSlider slider; - private static boolean upFail; - private static boolean downFail; + private static volatile boolean upFail; + private static volatile boolean downFail; public static void main(String[] args) throws Exception { try { @@ -70,23 +70,30 @@ public class bug4382876 { r.delay(1000); r.keyPress(KeyEvent.VK_PAGE_UP); + r.keyRelease(KeyEvent.VK_PAGE_UP); + SwingUtilities.invokeAndWait(() -> { if (slider.getValue() < -1000) { System.out.println("PAGE_UP VAL: " + slider.getValue()); upFail = true; } }); + if (upFail) { writeFailImage(); throw new RuntimeException("Slider value did NOT change with PAGE_UP"); } + r.keyPress(KeyEvent.VK_PAGE_DOWN); + r.keyRelease(KeyEvent.VK_PAGE_DOWN); + SwingUtilities.invokeAndWait(() -> { if (slider.getValue() > -1000) { System.out.println("PAGE_DOWN VAL: " + slider.getValue()); downFail = true; } }); + if (downFail) { writeFailImage(); throw new RuntimeException("Slider value did NOT change with PAGE_DOWN"); From cc9483b4da1a0f65f8773d0c7f35f2e6a7e1bd4f Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Fri, 24 Oct 2025 11:10:59 +0000 Subject: [PATCH 055/736] 8366182: Some PKCS11Tests are being skipped when they shouldn't Reviewed-by: rhalade --- .../security/pkcs11/Cipher/TestKATForGCM.java | 13 ++- .../pkcs11/KeyStore/SecretKeysBasic.java | 17 ++-- test/jdk/sun/security/pkcs11/PKCS11Test.java | 79 +++++++++---------- .../pkcs11/Secmod/AddTrustedCert.java | 10 +-- .../pkcs11/Signature/TestDSAKeyLength.java | 18 +++-- test/jdk/sun/security/pkcs11/ec/TestECDH.java | 1 + 6 files changed, 73 insertions(+), 65 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java b/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java index 9844e8ecfd2..e5e8284e6f4 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java @@ -321,14 +321,19 @@ public class TestKATForGCM extends PKCS11Test { System.out.println("Test Passed!"); } } catch (Exception e) { - System.out.println("Exception occured using " + p.getName() + " version " + p.getVersionStr()); + System.out.println("Exception occured using " + p.getName() + + " version " + p.getVersionStr()); if (isNSS(p)) { - double ver = getNSSInfo("nss"); + Version ver = getNSSInfo("nss"); String osName = System.getProperty("os.name"); - if (ver > 3.139 && ver < 3.15 && osName.equals("Linux")) { + + if (osName.equals("Linux") && + ver.major() == 3 && ver.minor() < 15 + && (ver.minor() > 13 && ver.patch() >= 9)) { // warn about buggy behaviour on Linux with nss 3.14 - System.out.println("Warning: old NSS " + ver + " might be problematic, consider upgrading it"); + System.out.println("Warning: old NSS " + ver + + " might be problematic, consider upgrading it"); } } throw e; diff --git a/test/jdk/sun/security/pkcs11/KeyStore/SecretKeysBasic.java b/test/jdk/sun/security/pkcs11/KeyStore/SecretKeysBasic.java index 4d876604c01..1ff80fcaf07 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/SecretKeysBasic.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/SecretKeysBasic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,11 +116,14 @@ public class SecretKeysBasic extends PKCS11Test { // A bug in NSS 3.12 (Mozilla bug 471665) causes AES key lengths // to be read incorrectly. Checking for improper 16 byte length // in key string. - if (isNSS(provider) && expected.getAlgorithm().equals("AES") && - (getNSSVersion() >= 3.12 && getNSSVersion() <= 3.122)) { - System.out.println("NSS 3.12 bug returns incorrect AES key "+ - "length breaking key storage. Aborting..."); - return true; + if (isNSS(provider) && expected.getAlgorithm().equals("AES")) { + Version version = getNSSVersion(); + if (version.major() == 3 && version.minor() == 12 + && version.patch() <= 2) { + System.out.println("NSS 3.12 bug returns incorrect AES key " + + "length breaking key storage. Aborting..."); + return true; + } } if (saveBeforeCheck) { @@ -168,7 +171,7 @@ public class SecretKeysBasic extends PKCS11Test { private static void doTest() throws Exception { // Make sure both NSS libraries are the same version. if (isNSS(provider) && - (getLibsoftokn3Version() != getLibnss3Version())) { + (!getLibsoftokn3Version().equals(getLibnss3Version()))) { System.out.println("libsoftokn3 and libnss3 versions do not match. Aborting test..."); return; } diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index 8454f3ac463..98343d9b7e6 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -83,7 +83,7 @@ public abstract class PKCS11Test { private static final String NSS_BUNDLE_VERSION = "3.111"; private static final String NSSLIB = "jpg.tests.jdk.nsslib"; - static double nss_version = -1; + static Version nss_version = null; static ECCState nss_ecc_status = ECCState.Basic; // The NSS library we need to search for in getNSSLibDir() @@ -93,8 +93,8 @@ public abstract class PKCS11Test { // NSS versions of each library. It is simpler to keep nss_version // for quick checking for generic testing than many if-else statements. - static double softoken3_version = -1; - static double nss3_version = -1; + static Version softoken3_version = null; + static Version nss3_version = null; static Provider pkcs11 = newPKCS11Provider(); private static String PKCS11_BASE; private static Map osMap; @@ -269,13 +269,29 @@ public abstract class PKCS11Test { } static boolean isBadNSSVersion(Provider p) { - double nssVersion = getNSSVersion(); - if (isNSS(p) && nssVersion >= 3.11 && nssVersion < 3.12) { - System.out.println("NSS 3.11 has a DER issue that recent " + - "version do not, skipping"); - return true; + Version nssVersion = getNSSVersion(); + if (isNSS(p)) { + // bad version is just between [3.11,3.12) + return nssVersion.major == 3 && 11 == nssVersion.minor; + } else { + return false; } - return false; + } + + public record Version(int major, int minor, int patch) {} + + protected static Version parseVersionString(String version) { + String [] parts = version.split("\\."); + int major = Integer.parseInt(parts[0]); + int minor = 0; + int patch = 0; + if (parts.length >= 2) { + minor = Integer.parseInt(parts[1]); + } + if (parts.length >= 3) { + patch = Integer.parseInt(parts[2]); + } + return new Version(major, minor, patch); } protected static void safeReload(String lib) { @@ -304,26 +320,26 @@ public abstract class PKCS11Test { return p.getName().equalsIgnoreCase("SUNPKCS11-NSS"); } - static double getNSSVersion() { - if (nss_version == -1) + static Version getNSSVersion() { + if (nss_version == null) getNSSInfo(); return nss_version; } static ECCState getNSSECC() { - if (nss_version == -1) + if (nss_version == null) getNSSInfo(); return nss_ecc_status; } - public static double getLibsoftokn3Version() { - if (softoken3_version == -1) + public static Version getLibsoftokn3Version() { + if (softoken3_version == null) return getNSSInfo("softokn3"); return softoken3_version; } - public static double getLibnss3Version() { - if (nss3_version == -1) + public static Version getLibnss3Version() { + if (nss3_version == null) return getNSSInfo("nss3"); return nss3_version; } @@ -338,7 +354,7 @@ public abstract class PKCS11Test { // $Header: NSS // Version: NSS // Here, stands for NSS version. - static double getNSSInfo(String library) { + static Version getNSSInfo(String library) { // look for two types of headers in NSS libraries String nssHeader1 = "$Header: NSS"; String nssHeader2 = "Version: NSS"; @@ -347,15 +363,15 @@ public abstract class PKCS11Test { int i = 0; Path libfile = null; - if (library.compareTo("softokn3") == 0 && softoken3_version > -1) + if (library.compareTo("softokn3") == 0 && softoken3_version != null) return softoken3_version; - if (library.compareTo("nss3") == 0 && nss3_version > -1) + if (library.compareTo("nss3") == 0 && nss3_version != null) return nss3_version; try { libfile = getNSSLibPath(); if (libfile == null) { - return 0.0; + return parseVersionString("0.0"); } try (InputStream is = Files.newInputStream(libfile)) { byte[] data = new byte[1000]; @@ -391,7 +407,7 @@ public abstract class PKCS11Test { if (!found) { System.out.println("lib" + library + " version not found, set to 0.0: " + libfile); - nss_version = 0.0; + nss_version = parseVersionString("0.0"); return nss_version; } @@ -404,26 +420,7 @@ public abstract class PKCS11Test { version.append(c); } - // If a "dot dot" release, strip the extra dots for double parsing - String[] dot = version.toString().split("\\."); - if (dot.length > 2) { - version = new StringBuilder(dot[0] + "." + dot[1]); - for (int j = 2; dot.length > j; j++) { - version.append(dot[j]); - } - } - - // Convert to double for easier version value checking - try { - nss_version = Double.parseDouble(version.toString()); - } catch (NumberFormatException e) { - System.out.println("===== Content start ====="); - System.out.println(s); - System.out.println("===== Content end ====="); - System.out.println("Failed to parse lib" + library + - " version. Set to 0.0"); - e.printStackTrace(); - } + nss_version = parseVersionString(version.toString()); System.out.print("library: " + library + ", version: " + version + ". "); diff --git a/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java b/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java index 880adc954ea..7b4a5075da8 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java +++ b/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,10 +121,10 @@ public class AddTrustedCert extends SecmodTest { } private static boolean improperNSSVersion(Provider p) { - double nssVersion = getNSSVersion(); - if (p.getName().equalsIgnoreCase("SunPKCS11-NSSKeyStore") - && nssVersion >= 3.28 && nssVersion < 3.35) { - return true; + Version nssVersion = getNSSVersion(); + if (p.getName().equalsIgnoreCase("SunPKCS11-NSSKeyStore")) { + return nssVersion.major() == 3 && + (nssVersion.minor() >= 28 && nssVersion.minor() < 35); } return false; diff --git a/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java b/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java index a9b43a647a9..ffd7b9e3ee0 100644 --- a/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java +++ b/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,13 +47,15 @@ public class TestDSAKeyLength extends PKCS11Test { @Override protected boolean skipTest(Provider provider) { - double version = getNSSVersion(); - String[] versionStrs = Double.toString(version).split("\\."); - int major = Integer.parseInt(versionStrs[0]); - int minor = Integer.parseInt(versionStrs[1]); - if (isNSS(provider) && (version == 0.0 || (major >= 3 && minor >= 14))) { - System.out.println("Skip testing NSS " + version); - return true; + if (isNSS(provider)) { + Version version = getNSSVersion(); + if (version == null) { + return true; + } + if (version.major() >= 3 && version.minor() >= 14){ + System.out.println("Skip testing NSS " + version); + return true; + } } return false; diff --git a/test/jdk/sun/security/pkcs11/ec/TestECDH.java b/test/jdk/sun/security/pkcs11/ec/TestECDH.java index b6821b88372..2900656f626 100644 --- a/test/jdk/sun/security/pkcs11/ec/TestECDH.java +++ b/test/jdk/sun/security/pkcs11/ec/TestECDH.java @@ -111,6 +111,7 @@ public class TestECDH extends PKCS11Test { * PKCS11Test.main will remove this provider if needed */ Providers.setAt(p, 1); + System.out.println("Testing provider " + p.getName()); if (false) { KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p); From fd23a61cd48be5ae2c7f76cc88af3da5b4a27e3d Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 24 Oct 2025 16:43:57 +0000 Subject: [PATCH 056/736] 8370503: Use String.newStringWithLatin1Bytes to simplify Integer/Long toString method Reviewed-by: rgiulietti, rriggs --- .../share/classes/java/lang/Integer.java | 44 +++--------------- .../share/classes/java/lang/Long.java | 45 +++---------------- 2 files changed, 12 insertions(+), 77 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 6e49f1983aa..20d1edb6d5f 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -363,15 +363,9 @@ public final class Integer extends Number // assert shift > 0 && shift <=5 : "Illegal shift value"; int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val); int chars = Math.max(((mag + (shift - 1)) / shift), 1); - if (COMPACT_STRINGS) { - byte[] buf = new byte[chars]; - formatUnsignedInt(val, shift, buf, chars); - return new String(buf, LATIN1); - } else { - byte[] buf = new byte[chars * 2]; - formatUnsignedIntUTF16(val, shift, buf, chars); - return new String(buf, UTF16); - } + byte[] buf = new byte[chars]; + formatUnsignedInt(val, shift, buf, chars); + return String.newStringWithLatin1Bytes(buf); } /** @@ -394,26 +388,6 @@ public final class Integer extends Number } while (charPos > 0); } - /** - * Format an {@code int} (treated as unsigned) into a byte buffer (UTF16 version). If - * {@code len} exceeds the formatted ASCII representation of {@code val}, - * {@code buf} will be padded with leading zeroes. - * - * @param val the unsigned int to format - * @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary) - * @param buf the byte buffer to write to - * @param len the number of characters to write - */ - private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int len) { - int charPos = len; - int radix = 1 << shift; - int mask = radix - 1; - do { - StringUTF16.putChar(buf, --charPos, Integer.digits[val & mask]); - val >>>= shift; - } while (charPos > 0); - } - /** * Returns a {@code String} object representing the * specified integer. The argument is converted to signed decimal @@ -427,15 +401,9 @@ public final class Integer extends Number @IntrinsicCandidate public static String toString(int i) { int size = DecimalDigits.stringSize(i); - if (COMPACT_STRINGS) { - byte[] buf = new byte[size]; - DecimalDigits.uncheckedGetCharsLatin1(i, size, buf); - return new String(buf, LATIN1); - } else { - byte[] buf = new byte[size * 2]; - DecimalDigits.uncheckedGetCharsUTF16(i, size, buf); - return new String(buf, UTF16); - } + byte[] buf = new byte[size]; + DecimalDigits.uncheckedGetCharsLatin1(i, size, buf); + return String.newStringWithLatin1Bytes(buf); } /** diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 90249cb1edb..b0477fdab6d 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -391,15 +391,9 @@ public final class Long extends Number // assert shift > 0 && shift <=5 : "Illegal shift value"; int mag = Long.SIZE - Long.numberOfLeadingZeros(val); int chars = Math.max(((mag + (shift - 1)) / shift), 1); - if (COMPACT_STRINGS) { - byte[] buf = new byte[chars]; - formatUnsignedLong0(val, shift, buf, 0, chars); - return new String(buf, LATIN1); - } else { - byte[] buf = new byte[chars * 2]; - formatUnsignedLong0UTF16(val, shift, buf, 0, chars); - return new String(buf, UTF16); - } + byte[] buf = new byte[chars]; + formatUnsignedLong0(val, shift, buf, 0, chars); + return String.newStringWithLatin1Bytes(buf); } /** @@ -423,27 +417,6 @@ public final class Long extends Number } while (charPos > offset); } - /** - * Format a long (treated as unsigned) into a byte buffer (UTF16 version). If - * {@code len} exceeds the formatted ASCII representation of {@code val}, - * {@code buf} will be padded with leading zeroes. - * - * @param val the unsigned long to format - * @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary) - * @param buf the byte buffer to write to - * @param offset the offset in the destination buffer to start at - * @param len the number of characters to write - */ - private static void formatUnsignedLong0UTF16(long val, int shift, byte[] buf, int offset, int len) { - int charPos = offset + len; - int radix = 1 << shift; - int mask = radix - 1; - do { - StringUTF16.putChar(buf, --charPos, Integer.digits[((int) val) & mask]); - val >>>= shift; - } while (charPos > offset); - } - /** * Returns a {@code String} object representing the specified * {@code long}. The argument is converted to signed decimal @@ -456,15 +429,9 @@ public final class Long extends Number */ public static String toString(long i) { int size = DecimalDigits.stringSize(i); - if (COMPACT_STRINGS) { - byte[] buf = new byte[size]; - DecimalDigits.uncheckedGetCharsLatin1(i, size, buf); - return new String(buf, LATIN1); - } else { - byte[] buf = new byte[size * 2]; - DecimalDigits.uncheckedGetCharsUTF16(i, size, buf); - return new String(buf, UTF16); - } + byte[] buf = new byte[size]; + DecimalDigits.uncheckedGetCharsLatin1(i, size, buf); + return String.newStringWithLatin1Bytes(buf); } /** From 13adcd99db4f14caf90de7f59e341380cfa354b0 Mon Sep 17 00:00:00 2001 From: Anass Baya Date: Fri, 24 Oct 2025 17:04:28 +0000 Subject: [PATCH 057/736] 8274082: Wrong test name in jtreg run tag for java/awt/print/PrinterJob/SwingUIText.java Co-authored-by: Lawrence Andrews Reviewed-by: honkar, dnguyen --- .../awt/print/PrinterJob/SwingUIText.java | 216 +++++------------- 1 file changed, 56 insertions(+), 160 deletions(-) diff --git a/test/jdk/java/awt/print/PrinterJob/SwingUIText.java b/test/jdk/java/awt/print/PrinterJob/SwingUIText.java index 5fcd5e39158..6ef5064fc30 100644 --- a/test/jdk/java/awt/print/PrinterJob/SwingUIText.java +++ b/test/jdk/java/awt/print/PrinterJob/SwingUIText.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,44 +21,70 @@ * questions. */ -/** +/* * @test * @bug 6488219 6560738 7158350 8017469 * @key printer * @summary Test that text printed in Swing UI measures and looks OK. - * @run main/manual=yesno PrintTextTest + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @run main/manual SwingUIText */ -import java.awt.*; -import javax.swing.*; -import java.awt.print.*; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterJob; +import javax.swing.JButton; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import jtreg.SkippedException; public class SwingUIText implements Printable { + private static JFrame frame; + private static final String INSTRUCTIONS = """ + This test checks that when a Swing UI is printed, + the text in each component aligns with the component’s length as seen on-screen. + It also ensures the text spacing is reasonably even, though this is subjective. + The comparison should be made with JDK 1.5 GA or JDK 1.6 GA. - static String[] instructions = { - "This tests that when a Swing UI is printed, that the text", - "in each component properly matches the length of the component", - "as seen on-screen, and that the spacing of the text is of", - "reasonable even-ness. This latter part is very subjective and", - "the comparison has to be with JDK1.5 GA, or JDK 1.6 GA", - }; + Steps: + 1. Press the "Print" or "OK" button on the Print dialog. + This will print the content of the "Swing UI Text Printing Test" JFrame. + 2. Compare the printout with the content of the JFrame. + 3. If they match, press Pass; otherwise, press Fail. + """; - static JFrame frame; + public static void main(String args[]) throws Exception { + PrinterJob job = PrinterJob.getPrinterJob(); + if (job.getPrintService() == null) { + throw new SkippedException("Printer not configured or available."); + } - public static void main(String args[]) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - createUI(); - } - }); + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(SwingUIText::createTestUI) + .build(); + + job.setPrintable(new SwingUIText()); + if (job.printDialog()) { + job.print(); + } + + passFailJFrame.awaitAndCheck(); } - public static void createUI() { - - Sysout.createDialogWithInstructions(instructions); - + public static JFrame createTestUI() { + frame = new JFrame(); JPanel panel = new JPanel(); - panel.setLayout(new GridLayout(4,1)); + panel.setLayout(new GridLayout(4, 1)); String text = "marvelous suspicious solving"; displayText(panel, text); @@ -89,24 +115,12 @@ public class SwingUIText implements Printable { frame = new JFrame("Swing UI Text Printing Test"); frame.getContentPane().add(panel); frame.pack(); - frame.setVisible(true); - - PrinterJob job = PrinterJob.getPrinterJob(); - PageFormat pf = job.defaultPage(); - job.setPrintable(new SwingUIText(), pf); - if (job.printDialog()) { - try { job.print(); } - catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } + return frame; } - static void displayText(JPanel p, String text) { JPanel panel = new JPanel(); - panel.setLayout(new GridLayout(2,1)); + panel.setLayout(new GridLayout(2, 1)); JPanel row = new JPanel(); Font font = new Font("Dialog", Font.PLAIN, 12); @@ -114,7 +128,7 @@ public class SwingUIText implements Printable { label.setFont(font); row.add(label); - JButton button = new JButton("Print "+text); + JButton button = new JButton("Print " + text); button.setMnemonic('P'); button.setFont(font); row.add(button); @@ -133,132 +147,14 @@ public class SwingUIText implements Printable { p.add(panel); } - public int print(Graphics g, PageFormat pf, int pageIndex) - throws PrinterException { - + public int print(Graphics g, PageFormat pf, int pageIndex) { if (pageIndex >= 1) { return Printable.NO_SUCH_PAGE; } + g.translate((int)pf.getImageableX(), (int)pf.getImageableY()); frame.printAll(g); - return Printable.PAGE_EXISTS; } } - -class Sysout - { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - - }// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog - { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 10, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("South", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - } - -}// TestDialog class From 2ee34391c152abeb06a6baf69f4420988b8c838e Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Fri, 24 Oct 2025 17:43:41 +0000 Subject: [PATCH 058/736] 8368975: Windows ProcessImpl.java has dead code Reviewed-by: ayang, rriggs --- .../windows/classes/java/lang/ProcessImpl.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/java.base/windows/classes/java/lang/ProcessImpl.java b/src/java.base/windows/classes/java/lang/ProcessImpl.java index 7f7c1e75013..78180cce678 100644 --- a/src/java.base/windows/classes/java/lang/ProcessImpl.java +++ b/src/java.base/windows/classes/java/lang/ProcessImpl.java @@ -199,7 +199,6 @@ final class ProcessImpl extends Process { } private static final int VERIFICATION_CMD_BAT = 0; - private static final int VERIFICATION_WIN32 = 1; private static final int VERIFICATION_WIN32_SAFE = 2; // inside quotes not allowed private static final int VERIFICATION_LEGACY = 3; // See Command shell overview for documentation of special characters. @@ -384,12 +383,6 @@ final class ProcessImpl extends Process { return (upName.endsWith(".EXE") || upName.indexOf('.') < 0); } - // Old version that can be bypassed - private boolean isShellFile(String executablePath) { - String upPath = executablePath.toUpperCase(Locale.ROOT); - return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT")); - } - private String quoteString(String arg) { StringBuilder argbuf = new StringBuilder(arg.length() + 2); return argbuf.append('"').append(arg).append('"').toString(); @@ -472,12 +465,10 @@ final class ProcessImpl extends Process { // Quotation protects from interpretation of the [path] argument as // start of longer path with spaces. Quotation has no influence to // [.exe] extension heuristic. - boolean isShell = allowAmbiguousCommands ? isShellFile(executablePath) - : !isExe(executablePath); + boolean isShell = !isExe(executablePath); cmdstr = createCommandLine( // We need the extended verification procedures - isShell ? VERIFICATION_CMD_BAT - : (allowAmbiguousCommands ? VERIFICATION_WIN32 : VERIFICATION_WIN32_SAFE), + isShell ? VERIFICATION_CMD_BAT : VERIFICATION_WIN32_SAFE, quoteString(executablePath), cmd); } From 97e5ac6e728baeae4341c6235d026ecd99bc600e Mon Sep 17 00:00:00 2001 From: Mikhailo Seledtsov Date: Fri, 24 Oct 2025 18:04:32 +0000 Subject: [PATCH 059/736] 8370514: Problemlist nio/channels/AsyncCloseAndInterrupt until JDK-8368290 is resolved Reviewed-by: bpb --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1f6bea97407..f95b3681723 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -587,6 +587,7 @@ java/net/MulticastSocket/Test.java 7145658,8308807 # jdk_nio java/nio/channels/Channels/SocketChannelStreams.java 8317838 aix-ppc64 +java/nio/channels/AsyncCloseAndInterrupt.java 8368290 macosx-26.0.1 java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8308807,8144003 aix-ppc64,macosx-all java/nio/channels/DatagramChannel/AfterDisconnect.java 8308807 aix-ppc64 From a4eaeb47c9c42d8da4e3814c80247f40236a03a2 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 24 Oct 2025 22:24:28 +0000 Subject: [PATCH 060/736] 6453640: BandedSampleModel.createCompatibleSampleModel() API docs are wrong Reviewed-by: azvegint, serb --- .../java/awt/image/BandedSampleModel.java | 13 +-- .../BSMCreateCompatibleSMTest.java | 100 ++++++++++++++++++ 2 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 test/jdk/java/awt/image/BandedSampleModel/BSMCreateCompatibleSMTest.java diff --git a/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java index bd955e35870..bad9abc6130 100644 --- a/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java @@ -141,12 +141,9 @@ public final class BandedSampleModel extends ComponentSampleModel * @param h the height of the resulting {@code BandedSampleModel} * @return a new {@code BandedSampleModel} with the specified * width and height. - * @throws IllegalArgumentException if {@code w} or - * {@code h} equals either - * {@code Integer.MAX_VALUE} or - * {@code Integer.MIN_VALUE} - * @throws IllegalArgumentException if {@code dataType} is not - * one of the supported data types + * @throws IllegalArgumentException if the product of {@code w} + * and {@code h} is greater than {@code Integer.MAX_VALUE} + * or {@code w} or {@code h} is not greater than 0. */ public SampleModel createCompatibleSampleModel(int w, int h) { int[] bandOffs; @@ -172,8 +169,8 @@ public final class BandedSampleModel extends ComponentSampleModel * of the original BandedSampleModel/DataBuffer combination. * @throws RasterFormatException if the number of bands is greater than * the number of banks in this sample model. - * @throws IllegalArgumentException if {@code dataType} is not - * one of the supported data types + * @throws IllegalArgumentException if the number of bands is not greater than 0 + * @throws ArrayIndexOutOfBoundsException if any of the bank indices is out of bounds */ public SampleModel createSubsetSampleModel(int[] bands) { if (bands.length > bankIndices.length) diff --git a/test/jdk/java/awt/image/BandedSampleModel/BSMCreateCompatibleSMTest.java b/test/jdk/java/awt/image/BandedSampleModel/BSMCreateCompatibleSMTest.java new file mode 100644 index 00000000000..a47659300e8 --- /dev/null +++ b/test/jdk/java/awt/image/BandedSampleModel/BSMCreateCompatibleSMTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6453640 + * @summary Verify BandedSampleModel.createCompatibleSampleModel + * and createSubsetSampleModel behaviour + * @run main BSMCreateCompatibleSMTest + */ + +import java.awt.image.BandedSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.RasterFormatException; + +public class BSMCreateCompatibleSMTest { + + public static void main(String[] args) { + + // These should all be OK + BandedSampleModel bsm = new BandedSampleModel(DataBuffer.TYPE_BYTE, 1, 1, 1); + bsm.createCompatibleSampleModel(20_000, 20_000); + int[] bands = { 0 } ; + bsm.createSubsetSampleModel(bands); + + // These should all throw an exception + try { + bsm.createCompatibleSampleModel(-1, 1); + throw new RuntimeException("No exception for illegal w"); + } catch (IllegalArgumentException e) { + System.out.println(e); + } + + try { + bsm.createCompatibleSampleModel(1, 0); + throw new RuntimeException("No exception for illegal h"); + } catch (IllegalArgumentException e) { + System.out.println(e); + } + + try { + bsm.createCompatibleSampleModel(-1, -1); + throw new RuntimeException("No exception for illegal w+h"); + } catch (IllegalArgumentException e) { + System.out.println(e); + } + + try { + bsm.createCompatibleSampleModel(50_000, 50_000); + throw new RuntimeException("No exception for too large dims"); + } catch (IllegalArgumentException e) { + System.out.println(e); + } + + try { + int[] bands0 = { } ; + bsm.createSubsetSampleModel(bands0); + throw new RuntimeException("No exception for empty bands[]"); + } catch (IllegalArgumentException e) { + System.out.println(e); + } + + try { + int[] bands1 = { 1 } ; + bsm.createSubsetSampleModel(bands1); + throw new RuntimeException("No exception for out of bounds band"); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e); + } + + try { + int[] bands2 = { 0, 0 } ; + bsm.createSubsetSampleModel(bands2); + throw new RuntimeException("No exception for too many bands"); + } catch (RasterFormatException e) { + System.out.println(e); + } + } + +} From 35fdda0889bd6a83027089672b643ef7ffc8a40c Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Fri, 24 Oct 2025 23:03:50 +0000 Subject: [PATCH 061/736] 7105350: HttpExchange's attributes are the same as HttpContext's attributes Reviewed-by: michaelm, jpai, dfuchs --- .../share/classes/module-info.java | 10 +++++++ .../sun/net/httpserver/ExchangeImpl.java | 30 ++++++++----------- .../net/httpserver/ExchangeAttributeTest.java | 20 ++++++++++--- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/jdk.httpserver/share/classes/module-info.java b/src/jdk.httpserver/share/classes/module-info.java index 15e9e2cc36d..ac147582b14 100644 --- a/src/jdk.httpserver/share/classes/module-info.java +++ b/src/jdk.httpserver/share/classes/module-info.java @@ -23,6 +23,8 @@ * questions. */ +import com.sun.net.httpserver.*; + /** * Defines the JDK-specific HTTP server API, and provides the jwebserver tool * for running a minimal HTTP server. @@ -109,6 +111,14 @@ * and implementation of the server does not intend to be a full-featured, high performance * HTTP server. * + * @implNote + * Prior to JDK 26, in the JDK default implementation, the {@link HttpExchange} attribute map was + * shared with the enclosing {@link HttpContext}. + * Since JDK 26, by default, exchange attributes are per-exchange and the context attributes must + * be accessed by calling {@link HttpExchange#getHttpContext() getHttpContext()}{@link + * HttpContext#getAttributes() .getAttributes()}.
    + * A new system property, {@systemProperty jdk.httpserver.attributes} (default value: {@code ""}) + * allows to revert this new behavior. Set this property to "context" to restore the pre JDK 26 behavior. * @toolGuide jwebserver * * @uses com.sun.net.httpserver.spi.HttpServerProvider diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java index 1119d1e386b..0899952b495 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.io.*; import java.net.*; import javax.net.ssl.*; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.text.*; @@ -59,6 +60,9 @@ class ExchangeImpl { /* for formatting the Date: header */ private static final DateTimeFormatter FORMATTER; + private static final boolean perExchangeAttributes = + !System.getProperty("jdk.httpserver.attributes", "") + .equals("context"); static { String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz"; FORMATTER = DateTimeFormatter.ofPattern(pattern, Locale.US) @@ -76,7 +80,7 @@ class ExchangeImpl { PlaceholderOutputStream uos_orig; boolean sentHeaders; /* true after response headers sent */ - Map attributes; + final Map attributes; int rcode = -1; HttpPrincipal principal; ServerImpl server; @@ -91,6 +95,9 @@ class ExchangeImpl { this.uri = u; this.connection = connection; this.reqContentLen = len; + this.attributes = perExchangeAttributes + ? new ConcurrentHashMap<>() + : getHttpContext().getAttributes(); /* ros only used for headers, body written directly to stream */ this.ros = req.outputStream(); this.ris = req.inputStream(); @@ -361,26 +368,15 @@ class ExchangeImpl { } public Object getAttribute (String name) { - if (name == null) { - throw new NullPointerException ("null name parameter"); - } - if (attributes == null) { - attributes = getHttpContext().getAttributes(); - } - return attributes.get (name); + return attributes.get(Objects.requireNonNull(name, "null name parameter")); } public void setAttribute (String name, Object value) { - if (name == null) { - throw new NullPointerException ("null name parameter"); - } - if (attributes == null) { - attributes = getHttpContext().getAttributes(); - } + var key = Objects.requireNonNull(name, "null name parameter"); if (value != null) { - attributes.put (name, value); + attributes.put(key, value); } else { - attributes.remove (name); + attributes.remove(key); } } diff --git a/test/jdk/com/sun/net/httpserver/ExchangeAttributeTest.java b/test/jdk/com/sun/net/httpserver/ExchangeAttributeTest.java index 2ce3dfd016d..e7bea2814db 100644 --- a/test/jdk/com/sun/net/httpserver/ExchangeAttributeTest.java +++ b/test/jdk/com/sun/net/httpserver/ExchangeAttributeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ * @summary Tests for HttpExchange set/getAttribute * @library /test/lib * @run junit/othervm ExchangeAttributeTest + * @run junit/othervm -Djdk.httpserver.attributes=context ExchangeAttributeTest + * @run junit/othervm -Djdk.httpserver.attributes=random-string ExchangeAttributeTest + * @run junit/othervm -Djdk.httpserver.attributes ExchangeAttributeTest */ import com.sun.net.httpserver.HttpExchange; @@ -71,7 +74,7 @@ public class ExchangeAttributeTest { public void testExchangeAttributes() throws Exception { var handler = new AttribHandler(); var server = HttpServer.create(new InetSocketAddress(LOOPBACK_ADDR,0), 10); - server.createContext("/", handler); + server.createContext("/", handler).getAttributes().put("attr", "context-val"); server.start(); try { var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); @@ -101,8 +104,17 @@ public class ExchangeAttributeTest { @java.lang.Override public void handle(HttpExchange exchange) throws IOException { try { - exchange.setAttribute("attr", "val"); - assertEquals("val", exchange.getAttribute("attr")); + if ("context".equals(System.getProperty("jdk.httpserver.attributes"))) { + exchange.setAttribute("attr", "val"); + assertEquals("val", exchange.getAttribute("attr")); + assertEquals("val", exchange.getHttpContext().getAttributes().get("attr")); + } else { + assertNull(exchange.getAttribute("attr")); + assertEquals("context-val", exchange.getHttpContext().getAttributes().get("attr")); + exchange.setAttribute("attr", "val"); + assertEquals("val", exchange.getAttribute("attr")); + assertEquals("context-val", exchange.getHttpContext().getAttributes().get("attr")); + } exchange.setAttribute("attr", null); assertNull(exchange.getAttribute("attr")); exchange.sendResponseHeaders(200, -1); From 32697bf652429fa7247047465e365835dfa24b39 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Sat, 25 Oct 2025 01:54:03 +0000 Subject: [PATCH 062/736] 8370501: vmTestbase/vm/gc/compact/Humongous_NonbranchyTree5M/TestDescription.java intermittent timed out Reviewed-by: tschatzl --- .../compact/Humongous_NonbranchyTree5M/TestDescription.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree5M/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree5M/TestDescription.java index 1d5a6f0cf11..a539fb7cea2 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree5M/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree5M/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp nonbranchyTree(high) From c3449de23f4fa74590494b8677f6832d47f12dea Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Sat, 25 Oct 2025 15:27:03 +0000 Subject: [PATCH 063/736] 8360395: sun/security/tools/keytool/i18n.java user country is current user location instead of the language Reviewed-by: rhalade --- test/jdk/sun/security/tools/keytool/i18n.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/sun/security/tools/keytool/i18n.java b/test/jdk/sun/security/tools/keytool/i18n.java index ab9da8b1d3e..030735e966c 100644 --- a/test/jdk/sun/security/tools/keytool/i18n.java +++ b/test/jdk/sun/security/tools/keytool/i18n.java @@ -28,7 +28,7 @@ * @author charlie lai * @modules java.base/sun.security.tools.keytool * @library /test/lib - * @run main/manual/othervm -Duser.language=en i18n + * @run main/manual/othervm -Duser.language=en -Duser.country=USA i18n */ /* @@ -38,7 +38,7 @@ * @author charlie lai * @modules java.base/sun.security.tools.keytool * @library /test/lib - * @run main/manual/othervm -Duser.language=de i18n + * @run main/manual/othervm -Duser.language=de -Duser.country=DE i18n */ /* @@ -48,7 +48,7 @@ * @author charlie lai * @modules java.base/sun.security.tools.keytool * @library /test/lib - * @run main/manual/othervm -Duser.language=ja i18n + * @run main/manual/othervm -Duser.language=ja -Duser.country=JP i18n */ /* From e7c7892b9f0fcee37495cce312fdd67dc800f9c9 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sun, 26 Oct 2025 06:04:02 +0000 Subject: [PATCH 064/736] 8370197: Add missing @Override annotations in com.sun.beans package Reviewed-by: prr --- .../classes/com/sun/beans/WildcardTypeImpl.java | 4 +++- .../sun/beans/decoder/NullElementHandler.java | 4 +++- .../com/sun/beans/decoder/ValueObjectImpl.java | 4 +++- .../com/sun/beans/editors/BooleanEditor.java | 6 +++++- .../com/sun/beans/editors/ByteEditor.java | 4 +++- .../com/sun/beans/editors/ColorEditor.java | 17 ++++++++++++++++- .../com/sun/beans/editors/DoubleEditor.java | 3 ++- .../com/sun/beans/editors/EnumEditor.java | 14 +++++++++++++- .../com/sun/beans/editors/FloatEditor.java | 4 +++- .../com/sun/beans/editors/FontEditor.java | 16 +++++++++++++++- .../com/sun/beans/editors/IntegerEditor.java | 3 ++- .../com/sun/beans/editors/LongEditor.java | 4 +++- .../com/sun/beans/editors/NumberEditor.java | 3 ++- .../com/sun/beans/editors/ShortEditor.java | 4 +++- .../com/sun/beans/editors/StringEditor.java | 4 +++- .../com/sun/beans/infos/ComponentBeanInfo.java | 3 ++- .../share/classes/com/sun/beans/util/Cache.java | 17 ++++++++++++++++- 17 files changed, 97 insertions(+), 17 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/beans/WildcardTypeImpl.java b/src/java.desktop/share/classes/com/sun/beans/WildcardTypeImpl.java index 28e316c90ec..ebbc8d2cb26 100644 --- a/src/java.desktop/share/classes/com/sun/beans/WildcardTypeImpl.java +++ b/src/java.desktop/share/classes/com/sun/beans/WildcardTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,6 +73,7 @@ final class WildcardTypeImpl implements WildcardType { * @return an array of types representing * the upper bound(s) of this type variable */ + @Override public Type[] getUpperBounds() { return this.upperBounds.clone(); } @@ -87,6 +88,7 @@ final class WildcardTypeImpl implements WildcardType { * @return an array of types representing * the lower bound(s) of this type variable */ + @Override public Type[] getLowerBounds() { return this.lowerBounds.clone(); } diff --git a/src/java.desktop/share/classes/com/sun/beans/decoder/NullElementHandler.java b/src/java.desktop/share/classes/com/sun/beans/decoder/NullElementHandler.java index f865535e4fb..d5ac5368f9a 100644 --- a/src/java.desktop/share/classes/com/sun/beans/decoder/NullElementHandler.java +++ b/src/java.desktop/share/classes/com/sun/beans/decoder/NullElementHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,7 @@ class NullElementHandler extends ElementHandler implements ValueObject { * * @return {@code null} by default */ + @Override public Object getValue() { return null; } @@ -70,6 +71,7 @@ class NullElementHandler extends ElementHandler implements ValueObject { * * @return {@code false} always */ + @Override public final boolean isVoid() { return false; } diff --git a/src/java.desktop/share/classes/com/sun/beans/decoder/ValueObjectImpl.java b/src/java.desktop/share/classes/com/sun/beans/decoder/ValueObjectImpl.java index 6fa46c93fa8..54c73381191 100644 --- a/src/java.desktop/share/classes/com/sun/beans/decoder/ValueObjectImpl.java +++ b/src/java.desktop/share/classes/com/sun/beans/decoder/ValueObjectImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,6 +72,7 @@ final class ValueObjectImpl implements ValueObject { * * @return the result of method execution */ + @Override public Object getValue() { return this.value; } @@ -82,6 +83,7 @@ final class ValueObjectImpl implements ValueObject { * @return {@code true} if value should be ignored, * {@code false} otherwise */ + @Override public boolean isVoid() { return this.isVoid; } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/BooleanEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/BooleanEditor.java index 69aca3238c9..79900b5deb1 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/BooleanEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/BooleanEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.beans.*; public class BooleanEditor extends PropertyEditorSupport { + @Override public String getJavaInitializationString() { Object value = getValue(); return (value != null) @@ -41,6 +42,7 @@ public class BooleanEditor extends PropertyEditorSupport { : "null"; } + @Override public String getAsText() { Object value = getValue(); return (value instanceof Boolean) @@ -48,6 +50,7 @@ public class BooleanEditor extends PropertyEditorSupport { : null; } + @Override public void setAsText(String text) throws java.lang.IllegalArgumentException { if (text == null) { setValue(null); @@ -60,6 +63,7 @@ public class BooleanEditor extends PropertyEditorSupport { } } + @Override public String[] getTags() { return new String[] {getValidName(true), getValidName(false)}; } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/ByteEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/ByteEditor.java index 2f4f342774f..fe927fda74d 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/ByteEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/ByteEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.beans.*; public class ByteEditor extends NumberEditor { + @Override public String getJavaInitializationString() { Object value = getValue(); return (value != null) @@ -41,6 +42,7 @@ public class ByteEditor extends NumberEditor { : "null"; } + @Override public void setAsText(String text) throws IllegalArgumentException { setValue((text == null) ? null : Byte.decode(text)); } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/ColorEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/ColorEditor.java index 3c3207ccd15..a5cf00923dd 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/ColorEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/ColorEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,16 +79,19 @@ public class ColorEditor extends Panel implements PropertyEditor { resize(ourWidth,40); } + @Override public void setValue(Object o) { Color c = (Color)o; changeColor(c); } + @Override @SuppressWarnings("deprecation") public Dimension preferredSize() { return new Dimension(ourWidth, 40); } + @Override @SuppressWarnings("deprecation") public boolean keyUp(Event e, int key) { if (e.target == text) { @@ -101,6 +104,7 @@ public class ColorEditor extends Panel implements PropertyEditor { return (false); } + @Override public void setAsText(String s) throws java.lang.IllegalArgumentException { if (s == null) { changeColor(null); @@ -124,6 +128,7 @@ public class ColorEditor extends Panel implements PropertyEditor { } + @Override @SuppressWarnings("deprecation") public boolean action(Event e, Object arg) { if (e.target == chooser) { @@ -132,6 +137,7 @@ public class ColorEditor extends Panel implements PropertyEditor { return false; } + @Override public String getJavaInitializationString() { return (this.color != null) ? "new java.awt.Color(" + this.color.getRGB() + ",true)" @@ -165,14 +171,17 @@ public class ColorEditor extends Panel implements PropertyEditor { support.firePropertyChange("", null, null); } + @Override public Object getValue() { return color; } + @Override public boolean isPaintable() { return true; } + @Override public void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box) { Color oldColor = gfx.getColor(); gfx.setColor(Color.black); @@ -182,28 +191,34 @@ public class ColorEditor extends Panel implements PropertyEditor { gfx.setColor(oldColor); } + @Override public String getAsText() { return (this.color != null) ? this.color.getRed() + "," + this.color.getGreen() + "," + this.color.getBlue() : null; } + @Override public String[] getTags() { return null; } + @Override public java.awt.Component getCustomEditor() { return this; } + @Override public boolean supportsCustomEditor() { return true; } + @Override public void addPropertyChangeListener(PropertyChangeListener l) { support.addPropertyChangeListener(l); } + @Override public void removePropertyChangeListener(PropertyChangeListener l) { support.removePropertyChangeListener(l); } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/DoubleEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/DoubleEditor.java index 55d5a0528a4..3803cca7d7c 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/DoubleEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/DoubleEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.beans.*; public class DoubleEditor extends NumberEditor { + @Override public void setAsText(String text) throws IllegalArgumentException { setValue((text == null) ? null : Double.valueOf(text)); } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/EnumEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/EnumEditor.java index b7f5ada0d1f..b5316a04d65 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/EnumEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/EnumEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,10 +63,12 @@ public final class EnumEditor implements PropertyEditor { } } + @Override public Object getValue() { return this.value; } + @Override public void setValue( Object value ) { if ( ( value != null ) && !this.type.isInstance( value ) ) { throw new IllegalArgumentException( "Unsupported value: " + value ); @@ -92,12 +94,14 @@ public final class EnumEditor implements PropertyEditor { } } + @Override public String getAsText() { return ( this.value != null ) ? ( ( Enum )this.value ).name() : null; } + @Override public void setAsText( String text ) { @SuppressWarnings("unchecked") Object tmp = ( text != null ) @@ -106,10 +110,12 @@ public final class EnumEditor implements PropertyEditor { setValue(tmp); } + @Override public String[] getTags() { return this.tags.clone(); } + @Override public String getJavaInitializationString() { String name = getAsText(); return ( name != null ) @@ -117,27 +123,33 @@ public final class EnumEditor implements PropertyEditor { : "null"; } + @Override public boolean isPaintable() { return false; } + @Override public void paintValue( Graphics gfx, Rectangle box ) { } + @Override public boolean supportsCustomEditor() { return false; } + @Override public Component getCustomEditor() { return null; } + @Override public void addPropertyChangeListener( PropertyChangeListener listener ) { synchronized ( this.listeners ) { this.listeners.add( listener ); } } + @Override public void removePropertyChangeListener( PropertyChangeListener listener ) { synchronized ( this.listeners ) { this.listeners.remove( listener ); diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/FloatEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/FloatEditor.java index 4723c489cc0..5820c00d82e 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/FloatEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/FloatEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.beans.*; public class FloatEditor extends NumberEditor { + @Override public String getJavaInitializationString() { Object value = getValue(); return (value != null) @@ -41,6 +42,7 @@ public class FloatEditor extends NumberEditor { : "null"; } + @Override public void setAsText(String text) throws IllegalArgumentException { setValue((text == null) ? null : Float.valueOf(text)); } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/FontEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/FontEditor.java index cf2fdd26307..26d4ab2b182 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/FontEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/FontEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,11 +78,13 @@ public class FontEditor extends Panel implements java.beans.PropertyEditor { } + @Override @SuppressWarnings("deprecation") public Dimension preferredSize() { return new Dimension(300, 40); } + @Override public void setValue(Object o) { font = (Font) o; if (this.font == null) @@ -130,10 +132,12 @@ public class FontEditor extends Panel implements java.beans.PropertyEditor { support.firePropertyChange("", null, null); } + @Override public Object getValue() { return (font); } + @Override public String getJavaInitializationString() { if (this.font == null) return "null"; @@ -142,6 +146,7 @@ public class FontEditor extends Panel implements java.beans.PropertyEditor { font.getStyle() + ", " + font.getSize() + ")"; } + @Override @SuppressWarnings("deprecation") public boolean action(Event e, Object arg) { String family = familyChoser.getSelectedItem(); @@ -158,10 +163,12 @@ public class FontEditor extends Panel implements java.beans.PropertyEditor { } + @Override public boolean isPaintable() { return true; } + @Override public void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box) { // Silent noop. Font oldFont = gfx.getFont(); @@ -172,6 +179,7 @@ public class FontEditor extends Panel implements java.beans.PropertyEditor { gfx.setFont(oldFont); } + @Override public String getAsText() { if (this.font == null) { return null; @@ -195,26 +203,32 @@ public class FontEditor extends Panel implements java.beans.PropertyEditor { return sb.toString(); } + @Override public void setAsText(String text) throws IllegalArgumentException { setValue((text == null) ? null : Font.decode(text)); } + @Override public String[] getTags() { return null; } + @Override public java.awt.Component getCustomEditor() { return this; } + @Override public boolean supportsCustomEditor() { return true; } + @Override public void addPropertyChangeListener(PropertyChangeListener l) { support.addPropertyChangeListener(l); } + @Override public void removePropertyChangeListener(PropertyChangeListener l) { support.removePropertyChangeListener(l); } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/IntegerEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/IntegerEditor.java index 066b7143ac6..65b4d1dcf19 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/IntegerEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/IntegerEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.beans.*; public class IntegerEditor extends NumberEditor { + @Override public void setAsText(String text) throws IllegalArgumentException { setValue((text == null) ? null : Integer.decode(text)); } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/LongEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/LongEditor.java index 3a8efbba53c..ed4d12ac505 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/LongEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/LongEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.beans.*; public class LongEditor extends NumberEditor { + @Override public String getJavaInitializationString() { Object value = getValue(); return (value != null) @@ -41,6 +42,7 @@ public class LongEditor extends NumberEditor { : "null"; } + @Override public void setAsText(String text) throws IllegalArgumentException { setValue((text == null) ? null : Long.decode(text)); } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/NumberEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/NumberEditor.java index 9097546d2e0..3c0c5bb6c9f 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/NumberEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/NumberEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.beans.*; public abstract class NumberEditor extends PropertyEditorSupport { + @Override public String getJavaInitializationString() { Object value = getValue(); return (value != null) diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/ShortEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/ShortEditor.java index cf82eef215d..6be5b14b90f 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/ShortEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/ShortEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.beans.*; public class ShortEditor extends NumberEditor { + @Override public String getJavaInitializationString() { Object value = getValue(); return (value != null) @@ -42,6 +43,7 @@ public class ShortEditor extends NumberEditor { : "null"; } + @Override public void setAsText(String text) throws IllegalArgumentException { setValue((text == null) ? null : Short.decode(text)); } diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/StringEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/StringEditor.java index 2f1cde46ea0..b064ccbddbb 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/StringEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/StringEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.beans.*; public class StringEditor extends PropertyEditorSupport { + @Override public String getJavaInitializationString() { Object value = getValue(); if (value == null) @@ -67,6 +68,7 @@ public class StringEditor extends PropertyEditorSupport { return sb.toString(); } + @Override public void setAsText(String text) { setValue(text); } diff --git a/src/java.desktop/share/classes/com/sun/beans/infos/ComponentBeanInfo.java b/src/java.desktop/share/classes/com/sun/beans/infos/ComponentBeanInfo.java index 1514b005074..39d7cbb2146 100644 --- a/src/java.desktop/share/classes/com/sun/beans/infos/ComponentBeanInfo.java +++ b/src/java.desktop/share/classes/com/sun/beans/infos/ComponentBeanInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.beans.*; public class ComponentBeanInfo extends SimpleBeanInfo { private static final Class beanClass = java.awt.Component.class; + @Override public PropertyDescriptor[] getPropertyDescriptors() { try { PropertyDescriptor diff --git a/src/java.desktop/share/classes/com/sun/beans/util/Cache.java b/src/java.desktop/share/classes/com/sun/beans/util/Cache.java index 2cb21791416..58151e3a56f 100644 --- a/src/java.desktop/share/classes/com/sun/beans/util/Cache.java +++ b/src/java.desktop/share/classes/com/sun/beans/util/Cache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -405,11 +405,13 @@ public abstract class Cache { */ public static enum Kind { STRONG { + @Override Ref create(Object owner, T value, ReferenceQueue queue) { return new Strong<>(owner, value); } }, SOFT { + @Override Ref create(Object owner, T referent, ReferenceQueue queue) { return (referent == null) ? new Strong<>(owner, referent) @@ -417,6 +419,7 @@ public abstract class Cache { } }, WEAK { + @Override Ref create(Object owner, T referent, ReferenceQueue queue) { return (referent == null) ? new Strong<>(owner, referent) @@ -463,6 +466,7 @@ public abstract class Cache { * * @return the owner of the reference or {@code null} if the owner is unknown */ + @Override public Object getOwner() { return this.owner; } @@ -472,6 +476,7 @@ public abstract class Cache { * * @return the referred object */ + @Override public T getReferent() { return this.referent; } @@ -481,6 +486,7 @@ public abstract class Cache { * * @return {@code true} if the referred object was collected */ + @Override public boolean isStale() { return false; } @@ -488,6 +494,7 @@ public abstract class Cache { /** * Marks this reference as removed from the cache. */ + @Override public void removeOwner() { this.owner = null; } @@ -522,6 +529,7 @@ public abstract class Cache { * * @return the owner of the reference or {@code null} if the owner is unknown */ + @Override public Object getOwner() { return this.owner; } @@ -531,6 +539,7 @@ public abstract class Cache { * * @return the referred object or {@code null} if it was collected */ + @Override public T getReferent() { return get(); } @@ -540,6 +549,7 @@ public abstract class Cache { * * @return {@code true} if the referred object was collected */ + @Override public boolean isStale() { return null == get(); } @@ -547,6 +557,7 @@ public abstract class Cache { /** * Marks this reference as removed from the cache. */ + @Override public void removeOwner() { this.owner = null; } @@ -581,6 +592,7 @@ public abstract class Cache { * * @return the owner of the reference or {@code null} if the owner is unknown */ + @Override public Object getOwner() { return this.owner; } @@ -590,6 +602,7 @@ public abstract class Cache { * * @return the referred object or {@code null} if it was collected */ + @Override public T getReferent() { return get(); } @@ -599,6 +612,7 @@ public abstract class Cache { * * @return {@code true} if the referred object was collected */ + @Override public boolean isStale() { return null == get(); } @@ -606,6 +620,7 @@ public abstract class Cache { /** * Marks this reference as removed from the cache. */ + @Override public void removeOwner() { this.owner = null; } From bfc1db7ed6bf9563c0441b24abe6943607b532e7 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 27 Oct 2025 05:17:43 +0000 Subject: [PATCH 065/736] 8370560: Remove non-public API reference from public API javadoc Reviewed-by: prr --- src/java.desktop/share/classes/java/awt/Component.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/java/awt/Component.java b/src/java.desktop/share/classes/java/awt/Component.java index e78cab2a14c..e48255aaf00 100644 --- a/src/java.desktop/share/classes/java/awt/Component.java +++ b/src/java.desktop/share/classes/java/awt/Component.java @@ -6287,7 +6287,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * and paint (and update) events. * For mouse move events the last event is always returned, causing * intermediate moves to be discarded. For paint events, the new - * event is coalesced into a complex {@code RepaintArea} in the peer. + * event is coalesced into a complex repaint area in the peer. * The new {@code AWTEvent} is always returned. * * @param existingEvent the event already on the {@code EventQueue} From 3d2ce8045f9ea52c6559638f9cc7e0a0544b4540 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 27 Oct 2025 06:53:08 +0000 Subject: [PATCH 066/736] 8212084: G1: Implement UseGCOverheadLimit Reviewed-by: ayang, iwalulya, fandreuzzi --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 110 ++++++++++++++---- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 11 ++ .../share/gc/parallel/parallelArguments.cpp | 5 - .../gc/parallel/parallelScavengeHeap.cpp | 9 +- .../gc/parallel/parallelScavengeHeap.hpp | 2 +- src/hotspot/share/gc/shared/gc_globals.hpp | 2 +- .../jtreg/gc/TestUseGCOverheadLimit.java | 98 ++++++++++++++++ 7 files changed, 204 insertions(+), 33 deletions(-) create mode 100644 test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index d3e02df3e09..d37ae512023 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -467,8 +467,20 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(uint node_index, size_t word_ log_trace(gc, alloc)("%s: Unsuccessfully scheduled collection allocating %zu words", Thread::current()->name(), word_size); + if (is_shutting_down()) { + stall_for_vm_shutdown(); + return nullptr; + } + + // Has the gc overhead limit been reached in the meantime? If so, this mutator + // should receive null even when unsuccessfully scheduling a collection as well + // for global consistency. + if (gc_overhead_limit_exceeded()) { + return nullptr; + } + // We can reach here if we were unsuccessful in scheduling a collection (because - // another thread beat us to it). In this case immeditealy retry the allocation + // another thread beat us to it). In this case immediately retry the allocation // attempt because another thread successfully performed a collection and possibly // reclaimed enough space. The first attempt (without holding the Heap_lock) is // here and the follow-on attempt will be at the start of the next loop @@ -485,11 +497,6 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(uint node_index, size_t word_ log_warning(gc, alloc)("%s: Retried allocation %u times for %zu words", Thread::current()->name(), try_count, word_size); } - - if (is_shutting_down()) { - stall_for_vm_shutdown(); - return nullptr; - } } ShouldNotReachHere(); @@ -714,6 +721,18 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) { log_trace(gc, alloc)("%s: Unsuccessfully scheduled collection allocating %zu", Thread::current()->name(), word_size); + if (is_shutting_down()) { + stall_for_vm_shutdown(); + return nullptr; + } + + // Has the gc overhead limit been reached in the meantime? If so, this mutator + // should receive null even when unsuccessfully scheduling a collection as well + // for global consistency. + if (gc_overhead_limit_exceeded()) { + return nullptr; + } + // We can reach here if we were unsuccessful in scheduling a collection (because // another thread beat us to it). // Humongous object allocation always needs a lock, so we wait for the retry @@ -725,11 +744,6 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) { log_warning(gc, alloc)("%s: Retried allocation %u times for %zu words", Thread::current()->name(), try_count, word_size); } - - if (is_shutting_down()) { - stall_for_vm_shutdown(); - return nullptr; - } } ShouldNotReachHere(); @@ -955,25 +969,62 @@ void G1CollectedHeap::resize_heap_after_young_collection(size_t allocation_word_ phase_times()->record_resize_heap_time((Ticks::now() - start).seconds() * 1000.0); } +void G1CollectedHeap::update_gc_overhead_counter() { + assert(SafepointSynchronize::is_at_safepoint(), "precondition"); + + if (!UseGCOverheadLimit) { + return; + } + + bool gc_time_over_limit = (_policy->analytics()->long_term_gc_time_ratio() * 100) >= GCTimeLimit; + double free_space_percent = percent_of(num_available_regions() * G1HeapRegion::GrainBytes, max_capacity()); + bool free_space_below_limit = free_space_percent < GCHeapFreeLimit; + + log_debug(gc)("GC Overhead Limit: GC Time %f Free Space %f Counter %zu", + (_policy->analytics()->long_term_gc_time_ratio() * 100), + free_space_percent, + _gc_overhead_counter); + + if (gc_time_over_limit && free_space_below_limit) { + _gc_overhead_counter++; + } else { + _gc_overhead_counter = 0; + } +} + +bool G1CollectedHeap::gc_overhead_limit_exceeded() { + return _gc_overhead_counter >= GCOverheadLimitThreshold; +} + HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, bool do_gc, bool maximal_compaction, bool expect_null_mutator_alloc_region) { - // Let's attempt the allocation first. - HeapWord* result = - attempt_allocation_at_safepoint(word_size, - expect_null_mutator_alloc_region); - if (result != nullptr) { - return result; - } + // Skip allocation if GC overhead limit has been exceeded to let the mutator run + // into an OOME. It can either exit "gracefully" or try to free up memory asap. + // For the latter situation, keep running GCs. If the mutator frees up enough + // memory quickly enough, the overhead(s) will go below the threshold(s) again + // and the VM may continue running. + // If we did not continue garbage collections, the (gc overhead) limit may decrease + // enough by itself to not count as exceeding the limit any more, in the worst + // case bouncing back-and-forth all the time. + if (!gc_overhead_limit_exceeded()) { + // Let's attempt the allocation first. + HeapWord* result = + attempt_allocation_at_safepoint(word_size, + expect_null_mutator_alloc_region); + if (result != nullptr) { + return result; + } - // In a G1 heap, we're supposed to keep allocation from failing by - // incremental pauses. Therefore, at least for now, we'll favor - // expansion over collection. (This might change in the future if we can - // do something smarter than full collection to satisfy a failed alloc.) - result = expand_and_allocate(word_size); - if (result != nullptr) { - return result; + // In a G1 heap, we're supposed to keep allocation from failing by + // incremental pauses. Therefore, at least for now, we'll favor + // expansion over collection. (This might change in the future if we can + // do something smarter than full collection to satisfy a failed alloc.) + result = expand_and_allocate(word_size); + if (result != nullptr) { + return result; + } } if (do_gc) { @@ -997,6 +1048,10 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size) { assert_at_safepoint_on_vm_thread(); + // Update GC overhead limits after the initial garbage collection leading to this + // allocation attempt. + update_gc_overhead_counter(); + // Attempts to allocate followed by Full GC. HeapWord* result = satisfy_failed_allocation_helper(word_size, @@ -1028,6 +1083,10 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size) { return result; } + if (gc_overhead_limit_exceeded()) { + log_info(gc)("GC Overhead Limit exceeded too often (%zu).", GCOverheadLimitThreshold); + } + // What else? We might try synchronous finalization later. If the total // space available is large enough for the allocation, then a more // complete compaction phase than we've tried so far might be @@ -1209,6 +1268,7 @@ public: G1CollectedHeap::G1CollectedHeap() : CollectedHeap(), + _gc_overhead_counter(0), _service_thread(nullptr), _periodic_gc_task(nullptr), _free_arena_memory_task(nullptr), diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 0d354525d89..c5b7da613d0 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -169,6 +169,17 @@ class G1CollectedHeap : public CollectedHeap { friend class G1CheckRegionAttrTableClosure; private: + // GC Overhead Limit functionality related members. + // + // The goal is to return null for allocations prematurely (before really going + // OOME) in case both GC CPU usage (>= GCTimeLimit) and not much available free + // memory (<= GCHeapFreeLimit) so that applications can exit gracefully or try + // to keep running by easing off memory. + uintx _gc_overhead_counter; // The number of consecutive garbage collections we were over the limits. + + void update_gc_overhead_counter(); + bool gc_overhead_limit_exceeded(); + G1ServiceThread* _service_thread; G1ServiceTask* _periodic_gc_task; G1MonotonicArenaFreeMemoryTask* _free_arena_memory_task; diff --git a/src/hotspot/share/gc/parallel/parallelArguments.cpp b/src/hotspot/share/gc/parallel/parallelArguments.cpp index 2d267951f79..629690a6258 100644 --- a/src/hotspot/share/gc/parallel/parallelArguments.cpp +++ b/src/hotspot/share/gc/parallel/parallelArguments.cpp @@ -66,11 +66,6 @@ void ParallelArguments::initialize() { } } - // True in product build, since tests using debug build often stress GC - if (FLAG_IS_DEFAULT(UseGCOverheadLimit)) { - FLAG_SET_DEFAULT(UseGCOverheadLimit, trueInProduct); - } - if (InitialSurvivorRatio < MinSurvivorRatio) { if (FLAG_IS_CMDLINE(InitialSurvivorRatio)) { if (FLAG_IS_CMDLINE(MinSurvivorRatio)) { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index eef9dfbc97c..f1baa4c4ff7 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -374,6 +374,13 @@ bool ParallelScavengeHeap::check_gc_overhead_limit() { bool little_mutator_time = _size_policy->mutator_time_percent() * 100 < (100 - GCTimeLimit); bool little_free_space = check_gc_heap_free_limit(_young_gen->free_in_bytes(), _young_gen->capacity_in_bytes()) && check_gc_heap_free_limit( _old_gen->free_in_bytes(), _old_gen->capacity_in_bytes()); + + log_debug(gc)("GC Overhead Limit: GC Time %f Free Space Young %f Old %f Counter %zu", + (100 - _size_policy->mutator_time_percent()), + percent_of(_young_gen->free_in_bytes(), _young_gen->capacity_in_bytes()), + percent_of(_old_gen->free_in_bytes(), _young_gen->capacity_in_bytes()), + _gc_overhead_counter); + if (little_mutator_time && little_free_space) { _gc_overhead_counter++; if (_gc_overhead_counter >= GCOverheadLimitThreshold) { @@ -426,7 +433,7 @@ HeapWord* ParallelScavengeHeap::satisfy_failed_allocation(size_t size, bool is_t } if (check_gc_overhead_limit()) { - log_info(gc)("GCOverheadLimitThreshold %zu reached.", GCOverheadLimitThreshold); + log_info(gc)("GC Overhead Limit exceeded too often (%zu).", GCOverheadLimitThreshold); return nullptr; } diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index 84732a86880..962a3c4b15b 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -88,7 +88,7 @@ class ParallelScavengeHeap : public CollectedHeap { WorkerThreads _workers; - uint _gc_overhead_counter; + uintx _gc_overhead_counter; bool _is_heap_almost_full; diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 956bffde156..6f754dbc39d 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -357,7 +357,7 @@ "Initial ratio of young generation/survivor space size") \ range(3, max_uintx) \ \ - product(bool, UseGCOverheadLimit, true, \ + product(bool, UseGCOverheadLimit, falseInDebug, \ "Use policy to limit of proportion of time spent in GC " \ "before an OutOfMemory error is thrown") \ \ diff --git a/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java b/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java new file mode 100644 index 00000000000..bc4c6bd6278 --- /dev/null +++ b/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package gc; + +/* + * @test id=Parallel + * @requires vm.gc.Parallel + * @requires !vm.debug + * @summary Verifies that the UseGCOverheadLimit functionality works in Parallel GC. + * @library /test/lib + * @run driver gc.TestUseGCOverheadLimit Parallel + */ + +/* + * @test id=G1 + * @requires vm.gc.G1 + * @requires !vm.debug + * @summary Verifies that the UseGCOverheadLimit functionality works in G1 GC. + * @library /test/lib + * @run driver gc.TestUseGCOverheadLimit G1 + */ + +import java.util.Arrays; +import java.util.stream.Stream; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class TestUseGCOverheadLimit { + public static void main(String args[]) throws Exception { + String[] parallelArgs = { + "-XX:+UseParallelGC", + "-XX:NewSize=122m", + "-XX:SurvivorRatio=99", + "-XX:GCHeapFreeLimit=10" + }; + String[] g1Args = { + "-XX:+UseG1GC", + "-XX:GCHeapFreeLimit=5" + }; + + String[] selectedArgs = args[0].equals("G1") ? g1Args : parallelArgs; + + final String[] commonArgs = { + "-XX:-UseCompactObjectHeaders", // Object sizes are calculated such that the heap is tight. + "-XX:ParallelGCThreads=1", // Make GCs take longer. + "-XX:+UseGCOverheadLimit", + "-Xlog:gc=debug", + "-XX:GCTimeLimit=90", // Ease the CPU requirement a little. + "-Xmx128m", + Allocating.class.getName() + }; + + String[] vmArgs = Stream.concat(Arrays.stream(selectedArgs), Arrays.stream(commonArgs)).toArray(String[]::new); + OutputAnalyzer output = ProcessTools.executeLimitedTestJava(vmArgs); + output.shouldNotHaveExitValue(0); + + System.out.println(output.getStdout()); + + output.stdoutShouldContain("GC Overhead Limit exceeded too often (5)."); + } + + static class Allocating { + public static void main(String[] args) { + Object[] cache = new Object[1024 * 1024 * 2]; + + // Allocate random objects, keeping around data, causing garbage + // collections. + for (int i = 0; i < 1024* 1024 * 30; i++) { + Object[] obj = new Object[10]; + cache[i % cache.length] = obj; + } + + System.out.println(cache); + } + } +} From f5ef01d4bfcf960b6a46844818138ee798532d45 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Mon, 27 Oct 2025 07:38:28 +0000 Subject: [PATCH 067/736] 8370368: Apply java.io.Serial annotations in java.security.jgss Reviewed-by: mullan --- .../classes/sun/security/jgss/krb5/Krb5Context.java | 6 ++++-- .../sun/security/jgss/krb5/Krb5InitCredential.java | 2 +- .../share/classes/sun/security/krb5/Asn1Exception.java | 3 +++ .../classes/sun/security/krb5/KrbCryptoException.java | 3 +++ .../share/classes/sun/security/krb5/KrbException.java | 4 +++- .../share/classes/sun/security/krb5/RealmException.java | 5 ++++- .../classes/sun/security/krb5/internal/KRBError.java | 9 ++++++--- .../sun/security/krb5/internal/KdcErrException.java | 5 ++++- .../sun/security/krb5/internal/KrbApErrException.java | 5 ++++- .../sun/security/krb5/internal/KrbErrException.java | 3 +++ .../classes/sun/security/krb5/internal/tools/Ktab.java | 5 +++-- 11 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java index 7df3d8d2de0..b118c9ee215 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.io.InvalidObjectException; import java.io.IOException; import java.io.ObjectInputStream; import java.io.OutputStream; +import java.io.Serial; import java.security.*; import javax.security.auth.Subject; import javax.security.auth.kerberos.KerberosCredMessage; @@ -1332,6 +1333,7 @@ class Krb5Context implements GSSContextSpi { * The session key returned by inquireSecContext(KRB5_INQ_SSPI_SESSION_KEY) */ static class KerberosSessionKey implements Key { + @Serial private static final long serialVersionUID = 699307378954123869L; @SuppressWarnings("serial") // Not statically typed as Serializable @@ -1369,7 +1371,7 @@ class Krb5Context implements GSSContextSpi { * @throws IOException if an I/O error occurs * @throws ClassNotFoundException if a serialized class cannot be loaded */ - @java.io.Serial + @Serial private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { throw new InvalidObjectException diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java index 29176ba3c2b..7aaa8975185 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java @@ -402,7 +402,7 @@ public class Krb5InitCredential * @throws IOException if an I/O error occurs * @throws ClassNotFoundException if a serialized class cannot be loaded */ - @java.io.Serial + @Serial private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { throw new InvalidObjectException("Krb5InitCredential not deserializable"); diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/Asn1Exception.java b/src/java.security.jgss/share/classes/sun/security/krb5/Asn1Exception.java index 7899a571589..8fe5591ffbc 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/Asn1Exception.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Asn1Exception.java @@ -30,8 +30,11 @@ package sun.security.krb5; +import java.io.Serial; + public class Asn1Exception extends KrbException { + @Serial private static final long serialVersionUID = 8291288984575084132L; public Asn1Exception(int i) { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbCryptoException.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbCryptoException.java index eda5fcec397..24cda1849ff 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbCryptoException.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbCryptoException.java @@ -30,6 +30,8 @@ package sun.security.krb5; +import java.io.Serial; + /** * KrbCryptoException is a wrapper exception for exceptions thrown by JCE. * @@ -37,6 +39,7 @@ package sun.security.krb5; */ public class KrbCryptoException extends KrbException { + @Serial private static final long serialVersionUID = -1657367919979982250L; public KrbCryptoException(String s) { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbException.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbException.java index 3fae5c7c2c5..434a0b401dd 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbException.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ package sun.security.krb5; +import java.io.Serial; import java.util.Objects; import sun.security.krb5.internal.Krb5; @@ -38,6 +39,7 @@ import sun.security.krb5.internal.KRBError; public class KrbException extends Exception { + @Serial private static final long serialVersionUID = -4993302876451928596L; private int returnCode; diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/RealmException.java b/src/java.security.jgss/share/classes/sun/security/krb5/RealmException.java index 124d1b63ed4..461da49c757 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/RealmException.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/RealmException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,11 @@ package sun.security.krb5; +import java.io.Serial; + public class RealmException extends KrbException { + @Serial private static final long serialVersionUID = -9100385213693792864L; public RealmException(int i) { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java index db6192ce9ee..46c733824c5 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import sun.security.krb5.RealmException; import sun.security.util.*; import java.io.IOException; import java.io.ObjectInputStream; +import java.io.Serial; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; @@ -85,7 +86,8 @@ import static sun.security.krb5.internal.Krb5.DEBUG; */ public class KRBError implements java.io.Serializable { - static final long serialVersionUID = 3643809337475284503L; + @Serial + private static final long serialVersionUID = 3643809337475284503L; private transient int pvno; private transient int msgType; @@ -112,7 +114,7 @@ public class KRBError implements java.io.Serializable { * @throws IOException if an I/O error occurs * @throws ClassNotFoundException if a serialized class cannot be loaded */ - @java.io.Serial + @Serial private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { try { @@ -123,6 +125,7 @@ public class KRBError implements java.io.Serializable { } } + @Serial private void writeObject(ObjectOutputStream os) throws IOException { try { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KdcErrException.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KdcErrException.java index c55670f4b23..744ba9ba2ac 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KdcErrException.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KdcErrException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,11 @@ package sun.security.krb5.internal; +import java.io.Serial; + public class KdcErrException extends sun.security.krb5.KrbException { + @Serial private static final long serialVersionUID = -8788186031117310306L; public KdcErrException(int i) { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbApErrException.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbApErrException.java index 04048cb73bb..4fd0aec5fa8 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbApErrException.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbApErrException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,11 @@ package sun.security.krb5.internal; +import java.io.Serial; + public class KrbApErrException extends sun.security.krb5.KrbException { + @Serial private static final long serialVersionUID = 7545264413323118315L; public KrbApErrException(int i) { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbErrException.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbErrException.java index 62e84959ca9..8e5a49dd802 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbErrException.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbErrException.java @@ -30,8 +30,11 @@ package sun.security.krb5.internal; +import java.io.Serial; + public class KrbErrException extends sun.security.krb5.KrbException { + @Serial private static final long serialVersionUID = 2186533836785448317L; public KrbErrException(int i) { diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java index ffe2e3196c1..bf1ceed8d22 100644 --- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java +++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java @@ -36,6 +36,7 @@ import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.Reader; +import java.io.Serial; import java.nio.charset.Charset; import java.text.DateFormat; import java.util.Arrays; @@ -82,8 +83,8 @@ public class Ktab { } private static class ExitException extends RuntimeException { - @java.io.Serial - static final long serialVersionUID = 0L; + @Serial + private static final long serialVersionUID = 0L; private final int errorCode; public ExitException(int errorCode) { this.errorCode = errorCode; From e9479b517ad8b6eac7244057644f90e710bd74b7 Mon Sep 17 00:00:00 2001 From: Raffaello Giulietti Date: Mon, 27 Oct 2025 08:15:00 +0000 Subject: [PATCH 068/736] 8370628: Rename BigInteger::nthRoot to rootn, and similarly for nthRootAndRemainder Reviewed-by: darcy --- .../share/classes/java/math/BigInteger.java | 14 +-- .../classes/java/math/MutableBigInteger.java | 16 ++-- .../java/math/BigInteger/BigIntegerTest.java | 88 +++++++++---------- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 6253adffb2b..ed26f5c1211 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -2768,9 +2768,9 @@ public class BigInteger extends Number implements Comparable { * @throws ArithmeticException if {@code n} is even and {@code this} is negative. * @see #sqrt() * @since 26 - * @apiNote Note that calling {@code nthRoot(2)} is equivalent to calling {@code sqrt()}. + * @apiNote Note that calling {@code rootn(2)} is equivalent to calling {@code sqrt()}. */ - public BigInteger nthRoot(int n) { + public BigInteger rootn(int n) { if (n == 1) return this; @@ -2778,7 +2778,7 @@ public class BigInteger extends Number implements Comparable { return sqrt(); checkRootDegree(n); - return new MutableBigInteger(this.mag).nthRootRem(n)[0].toBigInteger(signum); + return new MutableBigInteger(this.mag).rootnRem(n)[0].toBigInteger(signum); } /** @@ -2793,12 +2793,12 @@ public class BigInteger extends Number implements Comparable { * @throws ArithmeticException if {@code n} is even and {@code this} is negative. * @see #sqrt() * @see #sqrtAndRemainder() - * @see #nthRoot(int) + * @see #rootn(int) * @since 26 - * @apiNote Note that calling {@code nthRootAndRemainder(2)} is equivalent to calling + * @apiNote Note that calling {@code rootnAndRemainder(2)} is equivalent to calling * {@code sqrtAndRemainder()}. */ - public BigInteger[] nthRootAndRemainder(int n) { + public BigInteger[] rootnAndRemainder(int n) { if (n == 1) return new BigInteger[] { this, ZERO }; @@ -2806,7 +2806,7 @@ public class BigInteger extends Number implements Comparable { return sqrtAndRemainder(); checkRootDegree(n); - MutableBigInteger[] rootRem = new MutableBigInteger(this.mag).nthRootRem(n); + MutableBigInteger[] rootRem = new MutableBigInteger(this.mag).rootnRem(n); return new BigInteger[] { rootRem[0].toBigInteger(signum), rootRem[1].toBigInteger(signum) diff --git a/src/java.base/share/classes/java/math/MutableBigInteger.java b/src/java.base/share/classes/java/math/MutableBigInteger.java index dd1da29ddd2..1ede4cf32f8 100644 --- a/src/java.base/share/classes/java/math/MutableBigInteger.java +++ b/src/java.base/share/classes/java/math/MutableBigInteger.java @@ -1906,7 +1906,7 @@ class MutableBigInteger { * @param n the root degree * @return the integer {@code n}th root of {@code this} and the remainder */ - MutableBigInteger[] nthRootRem(int n) { + MutableBigInteger[] rootnRem(int n) { // Special cases. if (this.isZero() || this.isOne()) return new MutableBigInteger[] { this, new MutableBigInteger() }; @@ -1923,7 +1923,7 @@ class MutableBigInteger { if (bitLength <= Long.SIZE) { // Initial estimate is the root of the unsigned long value. final long x = this.toLong(); - long sLong = (long) nthRootApprox(Math.nextUp(x >= 0 ? x : x + 0x1p64), n) + 1L; + long sLong = (long) rootnApprox(Math.nextUp(x >= 0 ? x : x + 0x1p64), n) + 1L; /* The integer-valued recurrence formula in the algorithm of Brent&Zimmermann * simply discards the fraction part of the real-valued Newton recurrence * on the function f discussed in the referenced work. @@ -1996,7 +1996,7 @@ class MutableBigInteger { // Use the root of the shifted value as an estimate. // rad ≤ 2^ME, so Math.nextUp(rad) < Double.MAX_VALUE rad = Math.nextUp(rad); - approx = nthRootApprox(rad, n); + approx = rootnApprox(rad, n); } else { // fp arithmetic gives too few correct bits // Set the root shift to the root's bit length minus 1 // The initial estimate will be 2^rootLen == 2 << (rootLen - 1) @@ -2050,7 +2050,7 @@ class MutableBigInteger { MutableBigInteger x = new MutableBigInteger(this); x.rightShift(rootSh * n); - newtonRecurrenceNthRoot(x, s, n, s.toBigInteger().pow(n - 1)); + newtonRecurrenceRootn(x, s, n, s.toBigInteger().pow(n - 1)); s.add(ONE); // round up to ensure s is an upper bound of the root } @@ -2060,7 +2060,7 @@ class MutableBigInteger { } // Do the 1st iteration outside the loop to ensure an overestimate - newtonRecurrenceNthRoot(this, s, n, s.toBigInteger().pow(n - 1)); + newtonRecurrenceRootn(this, s, n, s.toBigInteger().pow(n - 1)); // Refine the estimate. do { BigInteger sBig = s.toBigInteger(); @@ -2069,18 +2069,18 @@ class MutableBigInteger { if (rem.subtract(this) <= 0) return new MutableBigInteger[] { s, rem }; - newtonRecurrenceNthRoot(this, s, n, sToN1); + newtonRecurrenceRootn(this, s, n, sToN1); } while (true); } - private static double nthRootApprox(double x, int n) { + private static double rootnApprox(double x, int n) { return Math.nextUp(n == 3 ? Math.cbrt(x) : Math.pow(x, Math.nextUp(1.0 / n))); } /** * Computes {@code ((n-1)*s + x/sToN1)/n} and places the result in {@code s}. */ - private static void newtonRecurrenceNthRoot( + private static void newtonRecurrenceRootn( MutableBigInteger x, MutableBigInteger s, int n, BigInteger sToN1) { MutableBigInteger dividend = new MutableBigInteger(); s.mul(n - 1, dividend); diff --git a/test/jdk/java/math/BigInteger/BigIntegerTest.java b/test/jdk/java/math/BigInteger/BigIntegerTest.java index 0e847f5ff6c..84aa8d15676 100644 --- a/test/jdk/java/math/BigInteger/BigIntegerTest.java +++ b/test/jdk/java/math/BigInteger/BigIntegerTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 - * 8074460 8078672 8032027 8229845 8077587 8367365 + * 8074460 8078672 8032027 8229845 8077587 8367365 8370628 * @summary tests methods in BigInteger (use -Dseed=X to set PRNG seed) * @key randomness * @library /test/lib @@ -232,7 +232,7 @@ public class BigIntegerTest { failCount1++; failCount1 += checkResult(x.signum() < 0 && power % 2 == 0 ? x.negate() : x, - y.nthRoot(power), "BigInteger.pow() inconsistent with BigInteger.nthRoot()"); + y.rootn(power), "BigInteger.pow() inconsistent with BigInteger.rootn()"); } report("pow for " + order + " bits", failCount1); } @@ -414,7 +414,7 @@ public class BigIntegerTest { BigInteger.valueOf(x)).collect(Collectors.summingInt(g))); } - private static void nthRootSmall() { + private static void rootnSmall() { int failCount = 0; // A non-positive degree should cause an exception. @@ -422,10 +422,10 @@ public class BigIntegerTest { BigInteger x = BigInteger.ONE; BigInteger s; try { - s = x.nthRoot(n); - // If nthRoot() does not throw an exception that is a failure. + s = x.rootn(n); + // If rootn() does not throw an exception that is a failure. failCount++; - printErr("nthRoot() of non-positive degree did not throw an exception"); + printErr("rootn() of non-positive degree did not throw an exception"); } catch (ArithmeticException expected) { // Not a failure } @@ -434,41 +434,41 @@ public class BigIntegerTest { n = 4; x = BigInteger.valueOf(-1); try { - s = x.nthRoot(n); - // If nthRoot() does not throw an exception that is a failure. + s = x.rootn(n); + // If rootn() does not throw an exception that is a failure. failCount++; - printErr("nthRoot() of negative number and even degree did not throw an exception"); + printErr("rootn() of negative number and even degree did not throw an exception"); } catch (ArithmeticException expected) { // Not a failure } - // A negative value with odd degree should return -nthRoot(-x, n) + // A negative value with odd degree should return -rootn(-x, n) n = 3; x = BigInteger.valueOf(-8); - failCount += checkResult(x.negate().nthRoot(n).negate(), x.nthRoot(n), - "nthRoot(" + x + ", " + n + ") != -nthRoot(" + x.negate() + ", " + n + ")"); + failCount += checkResult(x.negate().rootn(n).negate(), x.rootn(n), + "rootn(" + x + ", " + n + ") != -rootn(" + x.negate() + ", " + n + ")"); // A zero value should return BigInteger.ZERO. - failCount += checkResult(BigInteger.ZERO, BigInteger.ZERO.nthRoot(n), - "nthRoot(0, " + n + ") != 0"); + failCount += checkResult(BigInteger.ZERO, BigInteger.ZERO.rootn(n), + "rootn(0, " + n + ") != 0"); // A one degree should return x. x = BigInteger.TWO; - failCount += checkResult(x, x.nthRoot(1), "nthRoot(" + x + ", 1) != " + x); + failCount += checkResult(x, x.rootn(1), "rootn(" + x + ", 1) != " + x); n = 8; // 1 <= value < 2^n should return BigInteger.ONE. int end = 1 << n; for (int i = 1; i < end; i++) { failCount += checkResult(BigInteger.ONE, - BigInteger.valueOf(i).nthRoot(n), "nthRoot(" + i + ", " + n + ") != 1"); + BigInteger.valueOf(i).rootn(n), "rootn(" + i + ", " + n + ") != 1"); } - report("nthRootSmall", failCount); + report("rootnSmall", failCount); } - public static void nthRoot() { - nthRootSmall(); + public static void rootn() { + rootnSmall(); ToIntFunction f = (x) -> { int n = random.nextInt(x.bitLength()) + 2; @@ -476,28 +476,28 @@ public class BigIntegerTest { // nth root of x^n -> x BigInteger xN = x.pow(n); - failCount += checkResult(x, xN.nthRoot(n), "nthRoot() x^n -> x"); + failCount += checkResult(x, xN.rootn(n), "rootn() x^n -> x"); // nth root of x^n + 1 -> x BigInteger xNup = xN.add(BigInteger.ONE); - failCount += checkResult(x, xNup.nthRoot(n), "nthRoot() x^n + 1 -> x"); + failCount += checkResult(x, xNup.rootn(n), "rootn() x^n + 1 -> x"); // nth root of (x + 1)^n - 1 -> x BigInteger up = x.add(BigInteger.ONE).pow(n).subtract(BigInteger.ONE); - failCount += checkResult(x, up.nthRoot(n), "nthRoot() (x + 1)^n - 1 -> x"); + failCount += checkResult(x, up.rootn(n), "rootn() (x + 1)^n - 1 -> x"); - // nthRoot(x, n)^n <= x - BigInteger r = x.nthRoot(n); + // rootn(x, n)^n <= x + BigInteger r = x.rootn(n); if (r.pow(n).compareTo(x) > 0) { failCount++; - printErr("nthRoot(x, n)^n > x for x = " + x + ", n = " + n); + printErr("rootn(x, n)^n > x for x = " + x + ", n = " + n); } - // (nthRoot(x, n) + 1)^n > x + // (rootn(x, n) + 1)^n > x if (r.add(BigInteger.ONE).pow(n).compareTo(x) <= 0) { failCount++; - printErr("(nthRoot(x, n) + 1)^n <= x for x = " + x + ", n = " + n); + printErr("(rootn(x, n) + 1)^n <= x for x = " + x + ", n = " + n); } return failCount; @@ -513,52 +513,52 @@ public class BigIntegerTest { } sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger()); sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger().add(BigInteger.ONE)); - report("nthRoot for 2^N, 2^N - 1 and 2^N + 1, 1 <= N <= " + maxExponent, + report("rootn for 2^N, 2^N - 1 and 2^N + 1, 1 <= N <= " + maxExponent, sb.build().collect(Collectors.summingInt(f))); IntStream ints = random.ints(SIZE, 2, Integer.MAX_VALUE); - report("nthRoot for int", ints.mapToObj(x -> + report("rootn for int", ints.mapToObj(x -> BigInteger.valueOf(x)).collect(Collectors.summingInt(f))); LongStream longs = random.longs(SIZE, Integer.MAX_VALUE + 1L, Long.MAX_VALUE); - report("nthRoot for long", longs.mapToObj(x -> + report("rootn for long", longs.mapToObj(x -> BigInteger.valueOf(x)).collect(Collectors.summingInt(f))); DoubleStream doubles = random.doubles(SIZE, 0x1p63, Math.scalb(1.0, maxExponent)); - report("nthRoot for double", doubles.mapToObj(x -> + report("rootn for double", doubles.mapToObj(x -> BigDecimal.valueOf(x).toBigInteger()).collect(Collectors.summingInt(f))); } - public static void nthRootAndRemainder() { + public static void rootnAndRemainder() { ToIntFunction g = (x) -> { int failCount = 0; int n = random.nextInt(x.bitLength()) + 2; BigInteger xN = x.pow(n); // nth root of x^n -> x - BigInteger[] actual = xN.nthRootAndRemainder(n); - failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]"); - failCount += checkResult(BigInteger.ZERO, actual[1], "nthRootAndRemainder()[1]"); + BigInteger[] actual = xN.rootnAndRemainder(n); + failCount += checkResult(x, actual[0], "rootnAndRemainder()[0]"); + failCount += checkResult(BigInteger.ZERO, actual[1], "rootnAndRemainder()[1]"); // nth root of x^n + 1 -> x BigInteger xNup = xN.add(BigInteger.ONE); - actual = xNup.nthRootAndRemainder(n); - failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]"); - failCount += checkResult(BigInteger.ONE, actual[1], "nthRootAndRemainder()[1]"); + actual = xNup.rootnAndRemainder(n); + failCount += checkResult(x, actual[0], "rootnAndRemainder()[0]"); + failCount += checkResult(BigInteger.ONE, actual[1], "rootnAndRemainder()[1]"); // nth root of (x + 1)^n - 1 -> x BigInteger up = x.add(BigInteger.ONE).pow(n).subtract(BigInteger.ONE); - actual = up.nthRootAndRemainder(n); - failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]"); + actual = up.rootnAndRemainder(n); + failCount += checkResult(x, actual[0], "rootnAndRemainder()[0]"); BigInteger r = up.subtract(xN); - failCount += checkResult(r, actual[1], "nthRootAndRemainder()[1]"); + failCount += checkResult(r, actual[1], "rootnAndRemainder()[1]"); return failCount; }; IntStream bits = random.ints(SIZE, 3, Short.MAX_VALUE); - report("nthRootAndRemainder", bits.mapToObj(x -> + report("rootnAndRemainder", bits.mapToObj(x -> BigInteger.valueOf(x)).collect(Collectors.summingInt(g))); } @@ -1472,8 +1472,8 @@ public class BigIntegerTest { squareRoot(); squareRootAndRemainder(); - nthRoot(); - nthRootAndRemainder(); + rootn(); + rootnAndRemainder(); } if (failure) From 91e1dcb1083cc8c451d2d169d7f2fdb51c1a158e Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 27 Oct 2025 10:07:55 +0000 Subject: [PATCH 069/736] 8366781: Parallel: Include OS free memory in GC selection heuristics Reviewed-by: gli, iwalulya --- src/hotspot/share/gc/parallel/psScavenge.cpp | 47 +++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index f633f40ef7f..e738a13d464 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -521,31 +521,56 @@ void PSScavenge::clean_up_failed_promotion() { } bool PSScavenge::should_attempt_scavenge() { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + const bool ShouldRunYoungGC = true; + const bool ShouldRunFullGC = false; + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); if (!young_gen->to_space()->is_empty()) { - log_debug(gc, ergo)("To-space is not empty; should run full-gc instead."); - return false; + log_debug(gc, ergo)("To-space is not empty; run full-gc instead."); + return ShouldRunFullGC; } - // Test to see if the scavenge will likely fail. + // Check if the predicted promoted bytes will overflow free space in old-gen. PSAdaptiveSizePolicy* policy = heap->size_policy(); size_t avg_promoted = (size_t) policy->padded_average_promoted_in_bytes(); size_t promotion_estimate = MIN2(avg_promoted, young_gen->used_in_bytes()); // Total free size after possible old gen expansion - size_t free_in_old_gen = old_gen->max_gen_size() - old_gen->used_in_bytes(); - bool result = promotion_estimate < free_in_old_gen; + size_t free_in_old_gen_with_expansion = old_gen->max_gen_size() - old_gen->used_in_bytes(); - log_trace(gc, ergo)("%s scavenge: average_promoted %zu padded_average_promoted %zu free in old gen %zu", - result ? "Do" : "Skip", (size_t) policy->average_promoted_in_bytes(), - (size_t) policy->padded_average_promoted_in_bytes(), - free_in_old_gen); + log_trace(gc, ergo)("average_promoted %zu; padded_average_promoted %zu", + (size_t) policy->average_promoted_in_bytes(), + (size_t) policy->padded_average_promoted_in_bytes()); - return result; + if (promotion_estimate >= free_in_old_gen_with_expansion) { + log_debug(gc, ergo)("Run full-gc; predicted promotion size >= max free space in old-gen: %zu >= %zu", + promotion_estimate, free_in_old_gen_with_expansion); + return ShouldRunFullGC; + } + + if (UseAdaptiveSizePolicy) { + // Also checking OS has enough free memory to commit and expand old-gen. + // Otherwise, the recorded gc-pause-time might be inflated to include time + // of OS preparing free memory, resulting in inaccurate young-gen resizing. + assert(old_gen->committed().byte_size() >= old_gen->used_in_bytes(), "inv"); + // Use uint64_t instead of size_t for 32bit compatibility. + uint64_t free_mem_in_os; + if (os::free_memory(free_mem_in_os)) { + size_t actual_free = (size_t)MIN2(old_gen->committed().byte_size() - old_gen->used_in_bytes() + free_mem_in_os, + (uint64_t)SIZE_MAX); + if (promotion_estimate > actual_free) { + log_debug(gc, ergo)("Run full-gc; predicted promotion size > free space in old-gen and OS: %zu > %zu", + promotion_estimate, actual_free); + return ShouldRunFullGC; + } + } + } + + // No particular reasons to run full-gc, so young-gc. + return ShouldRunYoungGC; } // Adaptive size policy support. From 6f8d07ae21e49f87f64a5d4e10c930c4447ec8b6 Mon Sep 17 00:00:00 2001 From: Johny Jose Date: Mon, 27 Oct 2025 10:23:48 +0000 Subject: [PATCH 070/736] 8368500: ContextClassLoader cannot be reset on threads in ForkJoinPool.commonPool() Reviewed-by: vklang, alanb --- .../util/concurrent/ForkJoinWorkerThread.java | 6 +- .../forkjoin/ContextClassLoaderTest.java | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 test/jdk/java/util/concurrent/forkjoin/ContextClassLoaderTest.java diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java index b942d3ecd09..566fc417952 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java @@ -267,10 +267,8 @@ public class ForkJoinWorkerThread extends Thread { @Override // to record changes public void setContextClassLoader(ClassLoader cl) { - if (ClassLoader.getSystemClassLoader() != cl) { - resetCCL = true; - super.setContextClassLoader(cl); - } + resetCCL = ClassLoader.getSystemClassLoader() != cl; + super.setContextClassLoader(cl); } @Override // to re-establish CCL if necessary diff --git a/test/jdk/java/util/concurrent/forkjoin/ContextClassLoaderTest.java b/test/jdk/java/util/concurrent/forkjoin/ContextClassLoaderTest.java new file mode 100644 index 00000000000..eb6465e9619 --- /dev/null +++ b/test/jdk/java/util/concurrent/forkjoin/ContextClassLoaderTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8368500 + * @run junit/othervm ContextClassLoaderTest + * @summary Check the context classloader is reset + */ +import java.net.URL; +import java.net.URLClassLoader; +import java.util.concurrent.Future; +import java.util.concurrent.ForkJoinPool; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class ContextClassLoaderTest { + + @Test + void testContextClassLoaderIsSetAndRestored() throws Exception { + Future future = ForkJoinPool.commonPool().submit(() -> { + Thread thread = Thread.currentThread(); + ClassLoader originalCCL = thread.getContextClassLoader(); + ClassLoader customCCL = new URLClassLoader(new URL[0], originalCCL); + // Set custom context classloader and verify it + thread.setContextClassLoader(customCCL); + assertSame(customCCL, thread.getContextClassLoader(), "Custom context class loader not set"); + + // Reset to original and verify restoration + thread.setContextClassLoader(originalCCL); + assertSame(originalCCL, thread.getContextClassLoader(), "Original context class loader not restored"); + }); + future.get(); + } +} + From 7bb490c4bf7ae55547e4468da0795dac0a873d2b Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 27 Oct 2025 10:35:02 +0000 Subject: [PATCH 071/736] 8370318: AES-GCM vector intrinsic may read out of bounds (x86_64, AVX-512) Reviewed-by: kvn, roland --- src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 2 ++ .../cpu/x86/stubGenerator_x86_64_aes.cpp | 20 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 44d13bbbf31..0887225d3e8 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -393,6 +393,8 @@ class StubGenerator: public StubCodeGenerator { XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, XMMRegister xmm8); void ghash_last_8_avx2(Register subkeyHtbl); + void check_key_offset(Register key, int offset, int load_size); + // Load key and shuffle operation void ev_load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask); void ev_load_key(XMMRegister xmmdst, Register key, int offset, Register rscratch); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index 6f698b954ad..f0726ded7e5 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -1759,25 +1759,43 @@ void StubGenerator::roundDeclast(XMMRegister xmm_reg) { __ vaesdeclast(xmm8, xmm8, xmm_reg, Assembler::AVX_512bit); } +// Check incoming byte offset against the int[] len. key is the pointer to the int[0]. +// This check happens often, so it is important for it to be very compact. +void StubGenerator::check_key_offset(Register key, int offset, int load_size) { +#ifdef ASSERT + Address key_length(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)); + assert((offset + load_size) % 4 == 0, "Alignment is good: %d + %d", offset, load_size); + int end_offset = (offset + load_size) / 4; + Label L_good; + __ cmpl(key_length, end_offset); + __ jccb(Assembler::greaterEqual, L_good); + __ hlt(); + __ bind(L_good); +#endif +} // Utility routine for loading a 128-bit key word in little endian format void StubGenerator::load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask) { + check_key_offset(key, offset, 16); __ movdqu(xmmdst, Address(key, offset)); __ pshufb(xmmdst, xmm_shuf_mask); } void StubGenerator::load_key(XMMRegister xmmdst, Register key, int offset, Register rscratch) { + check_key_offset(key, offset, 16); __ movdqu(xmmdst, Address(key, offset)); __ pshufb(xmmdst, ExternalAddress(key_shuffle_mask_addr()), rscratch); } void StubGenerator::ev_load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask) { + check_key_offset(key, offset, 16); __ movdqu(xmmdst, Address(key, offset)); __ pshufb(xmmdst, xmm_shuf_mask); __ evshufi64x2(xmmdst, xmmdst, xmmdst, 0x0, Assembler::AVX_512bit); } void StubGenerator::ev_load_key(XMMRegister xmmdst, Register key, int offset, Register rscratch) { + check_key_offset(key, offset, 16); __ movdqu(xmmdst, Address(key, offset)); __ pshufb(xmmdst, ExternalAddress(key_shuffle_mask_addr()), rscratch); __ evshufi64x2(xmmdst, xmmdst, xmmdst, 0x0, Assembler::AVX_512bit); @@ -3205,12 +3223,12 @@ void StubGenerator::ghash16_encrypt_parallel16_avx512(Register in, Register out, //AES round 9 roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); - ev_load_key(AESKEY2, key, 11 * 16, rbx); //AES rounds up to 11 (AES192) or 13 (AES256) //AES128 is done __ cmpl(NROUNDS, 52); __ jcc(Assembler::less, last_aes_rnd); __ bind(aes_192); + ev_load_key(AESKEY2, key, 11 * 16, rbx); roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); ev_load_key(AESKEY1, key, 12 * 16, rbx); roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); From 5ed6c201ba0a9dc78960f2f3a5afce268e84a82d Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Mon, 27 Oct 2025 12:29:22 +0000 Subject: [PATCH 072/736] 8370681: [BACKOUT] Improve memory ordering in new CPU Time Profiler Reviewed-by: mdoerr --- .../sampling/jfrCPUTimeThreadSampler.cpp | 38 +++++++++++-------- .../sampling/jfrCPUTimeThreadSampler.hpp | 20 ++++------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp index 031dfb7e8ad..7507b9c994e 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp @@ -82,7 +82,14 @@ JfrCPUTimeTraceQueue::~JfrCPUTimeTraceQueue() { bool JfrCPUTimeTraceQueue::enqueue(JfrCPUTimeSampleRequest& request) { assert(JavaThread::current()->jfr_thread_local()->is_cpu_time_jfr_enqueue_locked(), "invariant"); assert(&JavaThread::current()->jfr_thread_local()->cpu_time_jfr_queue() == this, "invariant"); - _data[_head++] = request; + u4 elementIndex; + do { + elementIndex = AtomicAccess::load_acquire(&_head); + if (elementIndex >= _capacity) { + return false; + } + } while (AtomicAccess::cmpxchg(&_head, elementIndex, elementIndex + 1) != elementIndex); + _data[elementIndex] = request; return true; } @@ -94,19 +101,19 @@ JfrCPUTimeSampleRequest& JfrCPUTimeTraceQueue::at(u4 index) { static volatile u4 _lost_samples_sum = 0; u4 JfrCPUTimeTraceQueue::size() const { - return _head; + return AtomicAccess::load_acquire(&_head); } void JfrCPUTimeTraceQueue::set_size(u4 size) { - _head = size; + AtomicAccess::release_store(&_head, size); } u4 JfrCPUTimeTraceQueue::capacity() const { - return _capacity; + return AtomicAccess::load_acquire(&_capacity); } void JfrCPUTimeTraceQueue::set_capacity(u4 capacity) { - if (capacity == _capacity) { + if (capacity == AtomicAccess::load(&_capacity)) { return; } _head = 0; @@ -119,15 +126,15 @@ void JfrCPUTimeTraceQueue::set_capacity(u4 capacity) { } else { _data = nullptr; } - _capacity = capacity; + AtomicAccess::release_store(&_capacity, capacity); } bool JfrCPUTimeTraceQueue::is_empty() const { - return _head == 0; + return AtomicAccess::load_acquire(&_head) == 0; } u4 JfrCPUTimeTraceQueue::lost_samples() const { - return _lost_samples; + return AtomicAccess::load(&_lost_samples); } void JfrCPUTimeTraceQueue::increment_lost_samples() { @@ -136,7 +143,7 @@ void JfrCPUTimeTraceQueue::increment_lost_samples() { } void JfrCPUTimeTraceQueue::increment_lost_samples_due_to_queue_full() { - _lost_samples_due_to_queue_full++; + AtomicAccess::inc(&_lost_samples_due_to_queue_full); } u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples() { @@ -144,9 +151,7 @@ u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples() { } u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples_due_to_queue_full() { - u4 lost = _lost_samples_due_to_queue_full; - _lost_samples_due_to_queue_full = 0; - return lost; + return AtomicAccess::xchg(&_lost_samples_due_to_queue_full, (u4)0); } void JfrCPUTimeTraceQueue::init() { @@ -154,7 +159,7 @@ void JfrCPUTimeTraceQueue::init() { } void JfrCPUTimeTraceQueue::clear() { - _head = 0; + AtomicAccess::release_store(&_head, (u4)0); } void JfrCPUTimeTraceQueue::resize_if_needed() { @@ -162,8 +167,9 @@ void JfrCPUTimeTraceQueue::resize_if_needed() { if (lost_samples_due_to_queue_full == 0) { return; } - if (_capacity < CPU_TIME_QUEUE_MAX_CAPACITY) { - float ratio = (float)lost_samples_due_to_queue_full / (float)_capacity; + u4 capacity = AtomicAccess::load(&_capacity); + if (capacity < CPU_TIME_QUEUE_MAX_CAPACITY) { + float ratio = (float)lost_samples_due_to_queue_full / (float)capacity; int factor = 1; if (ratio > 8) { // idea is to quickly scale the queue in the worst case factor = ratio; @@ -175,7 +181,7 @@ void JfrCPUTimeTraceQueue::resize_if_needed() { factor = 2; } if (factor > 1) { - u4 new_capacity = MIN2(CPU_TIME_QUEUE_MAX_CAPACITY, _capacity * factor); + u4 new_capacity = MIN2(CPU_TIME_QUEUE_MAX_CAPACITY, capacity * factor); set_capacity(new_capacity); } } diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp index 48fe28d22f0..e7c915fc8be 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp @@ -43,24 +43,19 @@ struct JfrCPUTimeSampleRequest { // Fixed size async-signal-safe SPSC linear queue backed by an array. // Designed to be only used under lock and read linearly -// The lock in question is the tri-state CPU time JFR lock in JfrThreadLocal -// This allows us to skip most of the atomic accesses and memory barriers, -// holding a lock acts as a memory barrier -// Only the _lost_samples property is atomic, as it can be accessed even after -// acquiring the lock failed. -// Important to note is that the queue is also only accessed under lock in signal -// handlers. class JfrCPUTimeTraceQueue { + // the default queue capacity, scaled if the sampling period is smaller than 10ms + // when the thread is started + static const u4 CPU_TIME_QUEUE_CAPACITY = 500; + JfrCPUTimeSampleRequest* _data; - u4 _capacity; + volatile u4 _capacity; // next unfilled index - u4 _head; + volatile u4 _head; - // the only property accessible without a lock volatile u4 _lost_samples; - - u4 _lost_samples_due_to_queue_full; + volatile u4 _lost_samples_due_to_queue_full; static const u4 CPU_TIME_QUEUE_INITIAL_CAPACITY = 20; static const u4 CPU_TIME_QUEUE_MAX_CAPACITY = 2000; @@ -87,7 +82,6 @@ public: u4 lost_samples() const; - // the only method callable without holding a lock void increment_lost_samples(); void increment_lost_samples_due_to_queue_full(); From 1e49376ece39e8f9b5c72b58688b1e195a0014be Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Mon, 27 Oct 2025 15:09:59 +0000 Subject: [PATCH 073/736] 8368321: Rethink compilation delay strategy for lukewarm methods Reviewed-by: kvn, vlivanov --- .../share/compiler/compilationPolicy.cpp | 65 ++++++++++++------- .../share/compiler/compilationPolicy.hpp | 9 +-- .../share/compiler/compiler_globals.hpp | 7 -- src/hotspot/share/oops/trainingData.cpp | 3 + src/hotspot/share/oops/trainingData.hpp | 7 ++ 5 files changed, 55 insertions(+), 36 deletions(-) diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 177fd04fbbc..1cc44602186 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -423,13 +423,16 @@ void CompilationPolicy::print_counters_on(outputStream* st, const char* prefix, st->print(" %smax levels=%d,%d", prefix, m->highest_comp_level(), m->highest_osr_comp_level()); } -void CompilationPolicy::print_training_data_on(outputStream* st, const char* prefix, Method* method) { +void CompilationPolicy::print_training_data_on(outputStream* st, const char* prefix, Method* method, CompLevel cur_level) { methodHandle m(Thread::current(), method); st->print(" %smtd: ", prefix); MethodTrainingData* mtd = MethodTrainingData::find(m); if (mtd == nullptr) { st->print("null"); } else { + if (should_delay_standard_transition(m, cur_level, mtd)) { + st->print("delayed, "); + } MethodData* md = mtd->final_profile(); st->print("mdo="); if (md == nullptr) { @@ -536,9 +539,9 @@ void CompilationPolicy::print_event_on(outputStream *st, EventType type, Method* st->print("in-queue"); } else st->print("idle"); - print_training_data_on(st, "", m); + print_training_data_on(st, "", m, level); if (inlinee_event) { - print_training_data_on(st, "inlinee ", im); + print_training_data_on(st, "inlinee ", im, level); } } st->print_cr("]"); @@ -1153,7 +1156,7 @@ CompLevel CompilationPolicy::trained_transition_from_none(const methodHandle& me // Now handle the case of level 4. assert(highest_training_level == CompLevel_full_optimization, "Unexpected compilation level: %d", highest_training_level); if (!training_has_profile) { - // The method was a part of a level 4 compile, but don't have a stored profile, + // The method was a part of a level 4 compile, but doesn't have a stored profile, // we need to profile it. return CompLevel_full_profile; } @@ -1308,33 +1311,53 @@ CompLevel CompilationPolicy::common(const methodHandle& method, CompLevel cur_le if (mtd == nullptr) { // We haven't see compilations of this method in training. It's either very cold or the behavior changed. // Feed it to the standard TF with no profiling delay. - next_level = standard_transition(method, cur_level, false /*delay_profiling*/, disable_feedback); + next_level = standard_transition(method, cur_level, disable_feedback); } else { next_level = trained_transition(method, cur_level, mtd, THREAD); - if (cur_level == next_level) { + if (cur_level == next_level && !should_delay_standard_transition(method, cur_level, mtd)) { // trained_transtion() is going to return the same level if no startup/warmup optimizations apply. // In order to catch possible pathologies due to behavior change we feed the event to the regular // TF but with profiling delay. - next_level = standard_transition(method, cur_level, true /*delay_profiling*/, disable_feedback); + next_level = standard_transition(method, cur_level, disable_feedback); } } } else { - next_level = standard_transition(method, cur_level, false /*delay_profiling*/, disable_feedback); + next_level = standard_transition(method, cur_level, disable_feedback); } return (next_level != cur_level) ? limit_level(next_level) : next_level; } +bool CompilationPolicy::should_delay_standard_transition(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd) { + precond(mtd != nullptr); + CompLevel highest_training_level = static_cast(mtd->highest_top_level()); + if (highest_training_level != CompLevel_full_optimization && cur_level == CompLevel_limited_profile) { + // This is a lukewarm method - it hasn't been compiled with C2 during the tranining run and is currently + // running at level 2. Delay any further state changes until its counters exceed the training run counts. + MethodCounters* mc = method->method_counters(); + if (mc == nullptr) { + return false; + } + if (mc->invocation_counter()->carry() || mc->backedge_counter()->carry()) { + return false; + } + if (static_cast(mc->invocation_counter()->count()) <= mtd->invocation_count() && + static_cast(mc->backedge_counter()->count()) <= mtd->backedge_count()) { + return true; + } + } + return false; +} template -CompLevel CompilationPolicy::standard_transition(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback) { +CompLevel CompilationPolicy::standard_transition(const methodHandle& method, CompLevel cur_level, bool disable_feedback) { CompLevel next_level = cur_level; switch(cur_level) { default: break; case CompLevel_none: - next_level = transition_from_none(method, cur_level, delay_profiling, disable_feedback); + next_level = transition_from_none(method, cur_level, disable_feedback); break; case CompLevel_limited_profile: - next_level = transition_from_limited_profile(method, cur_level, delay_profiling, disable_feedback); + next_level = transition_from_limited_profile(method, cur_level, disable_feedback); break; case CompLevel_full_profile: next_level = transition_from_full_profile(method, cur_level); @@ -1343,16 +1366,8 @@ CompLevel CompilationPolicy::standard_transition(const methodHandle& method, Com return next_level; } -template static inline bool apply_predicate(const methodHandle& method, CompLevel cur_level, int i, int b, bool delay_profiling, double delay_profiling_scale) { - if (delay_profiling) { - return Predicate::apply_scaled(method, cur_level, i, b, delay_profiling_scale); - } else { - return Predicate::apply(method, cur_level, i, b); - } -} - template -CompLevel CompilationPolicy::transition_from_none(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback) { +CompLevel CompilationPolicy::transition_from_none(const methodHandle& method, CompLevel cur_level, bool disable_feedback) { precond(cur_level == CompLevel_none); CompLevel next_level = cur_level; int i = method->invocation_count(); @@ -1360,7 +1375,7 @@ CompLevel CompilationPolicy::transition_from_none(const methodHandle& method, Co // If we were at full profile level, would we switch to full opt? if (transition_from_full_profile(method, CompLevel_full_profile) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; - } else if (!CompilationModeFlag::disable_intermediate() && apply_predicate(method, cur_level, i, b, delay_profiling, Tier0ProfileDelayFactor)) { + } else if (!CompilationModeFlag::disable_intermediate() && Predicate::apply(method, cur_level, i, b)) { // C1-generated fully profiled code is about 30% slower than the limited profile // code that has only invocation and backedge counters. The observation is that // if C2 queue is large enough we can spend too much time in the fully profiled code @@ -1368,7 +1383,7 @@ CompLevel CompilationPolicy::transition_from_none(const methodHandle& method, Co // we introduce a feedback on the C2 queue size. If the C2 queue is sufficiently long // we choose to compile a limited profiled version and then recompile with full profiling // when the load on C2 goes down. - if (delay_profiling || (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) > Tier3DelayOn * compiler_count(CompLevel_full_optimization))) { + if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) > Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { next_level = CompLevel_limited_profile; } else { next_level = CompLevel_full_profile; @@ -1397,7 +1412,7 @@ CompLevel CompilationPolicy::transition_from_full_profile(const methodHandle& me } template -CompLevel CompilationPolicy::transition_from_limited_profile(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback) { +CompLevel CompilationPolicy::transition_from_limited_profile(const methodHandle& method, CompLevel cur_level, bool disable_feedback) { precond(cur_level == CompLevel_limited_profile); CompLevel next_level = cur_level; int i = method->invocation_count(); @@ -1407,7 +1422,7 @@ CompLevel CompilationPolicy::transition_from_limited_profile(const methodHandle& if (mdo->would_profile()) { if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - apply_predicate(method, cur_level, i, b, delay_profiling, Tier2ProfileDelayFactor))) { + Predicate::apply(method, cur_level, i, b))) { next_level = CompLevel_full_profile; } } else { @@ -1417,7 +1432,7 @@ CompLevel CompilationPolicy::transition_from_limited_profile(const methodHandle& // If there is no MDO we need to profile if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - apply_predicate(method, cur_level, i, b, delay_profiling, Tier2ProfileDelayFactor))) { + Predicate::apply(method, cur_level, i, b))) { next_level = CompLevel_full_profile; } } diff --git a/src/hotspot/share/compiler/compilationPolicy.hpp b/src/hotspot/share/compiler/compilationPolicy.hpp index d950ba418f9..3efc374d998 100644 --- a/src/hotspot/share/compiler/compilationPolicy.hpp +++ b/src/hotspot/share/compiler/compilationPolicy.hpp @@ -263,14 +263,15 @@ class CompilationPolicy : AllStatic { static CompLevel common(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD, bool disable_feedback = false); template - static CompLevel transition_from_none(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback); + static CompLevel transition_from_none(const methodHandle& method, CompLevel cur_level, bool disable_feedback); template - static CompLevel transition_from_limited_profile(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback); + static CompLevel transition_from_limited_profile(const methodHandle& method, CompLevel cur_level, bool disable_feedback); template static CompLevel transition_from_full_profile(const methodHandle& method, CompLevel cur_level); template - static CompLevel standard_transition(const methodHandle& method, CompLevel cur_level, bool delayprof, bool disable_feedback); + static CompLevel standard_transition(const methodHandle& method, CompLevel cur_level, bool disable_feedback); + static bool should_delay_standard_transition(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd); static CompLevel trained_transition_from_none(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD); static CompLevel trained_transition_from_limited_profile(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD); static CompLevel trained_transition_from_full_profile(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD); @@ -284,7 +285,7 @@ class CompilationPolicy : AllStatic { // level. static CompLevel loop_event(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD); static void print_counters_on(outputStream* st, const char* prefix, Method* m); - static void print_training_data_on(outputStream* st, const char* prefix, Method* method); + static void print_training_data_on(outputStream* st, const char* prefix, Method* method, CompLevel cur_level); // Has a method been long around? // We don't remove old methods from the compile queue even if they have // very low activity (see select_task()). diff --git a/src/hotspot/share/compiler/compiler_globals.hpp b/src/hotspot/share/compiler/compiler_globals.hpp index 605c0c58869..3919c596d74 100644 --- a/src/hotspot/share/compiler/compiler_globals.hpp +++ b/src/hotspot/share/compiler/compiler_globals.hpp @@ -271,13 +271,6 @@ "Maximum rate sampling interval (in milliseconds)") \ range(1, max_intx) \ \ - product(double, Tier0ProfileDelayFactor, 100.0, DIAGNOSTIC, \ - "Delay profiling/compiling of methods that were " \ - "observed to be lukewarm") \ - \ - product(double, Tier2ProfileDelayFactor, 250.0, DIAGNOSTIC, \ - "Delay profiling of methods that were observed to be lukewarm") \ - \ product(bool, SkipTier2IfPossible, false, DIAGNOSTIC, \ "Compile at tier 4 instead of tier 2 in training replay " \ "mode if posssible") \ diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 24f82a53843..27ae3404f41 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -35,6 +35,7 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/method.hpp" +#include "oops/method.inline.hpp" #include "oops/methodCounters.hpp" #include "oops/trainingData.hpp" #include "runtime/arguments.hpp" @@ -352,6 +353,8 @@ void MethodTrainingData::prepare(Visitor& visitor) { _final_counters = holder()->method_counters(); _final_profile = holder()->method_data(); assert(_final_profile == nullptr || _final_profile->method() == holder(), ""); + _invocation_count = holder()->invocation_count(); + _backedge_count = holder()->backedge_count(); } for (int i = 0; i < CompLevel_count - 1; i++) { CompileTrainingData* ctd = _last_toplevel_compiles[i]; diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index 7ab5e179eea..c549004e76e 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -748,6 +748,9 @@ class MethodTrainingData : public TrainingData { MethodCounters* _final_counters; MethodData* _final_profile; + int _invocation_count; + int _backedge_count; + MethodTrainingData(); MethodTrainingData(Method* method, KlassTrainingData* ktd) : TrainingData(method) { _klass = ktd; @@ -758,6 +761,8 @@ class MethodTrainingData : public TrainingData { _highest_top_level = CompLevel_none; _level_mask = 0; _was_toplevel = false; + _invocation_count = 0; + _backedge_count = 0; } static int level_mask(int level) { @@ -772,6 +777,8 @@ class MethodTrainingData : public TrainingData { bool saw_level(CompLevel l) const { return (_level_mask & level_mask(l)) != 0; } int highest_top_level() const { return _highest_top_level; } MethodData* final_profile() const { return _final_profile; } + int invocation_count() const { return _invocation_count; } + int backedge_count() const { return _backedge_count; } Symbol* name() const { precond(has_holder()); From 583ff202b1cc1f018d798a34d93359301840cf06 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 27 Oct 2025 16:15:10 +0000 Subject: [PATCH 074/736] 8370251: C2: Inlining checks for method handle intrinsics are too strict Reviewed-by: kvn, roland --- src/hotspot/share/opto/doCall.cpp | 12 +- .../jtreg/compiler/jsr292/MHInlineTest.java | 157 +++++++++++++----- 2 files changed, 126 insertions(+), 43 deletions(-) diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index ad7b64f93f5..754b0fa8d1c 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -102,6 +102,8 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool (orig_callee->intrinsic_id() == vmIntrinsics::_linkToVirtual) || (orig_callee->intrinsic_id() == vmIntrinsics::_linkToInterface); + const bool check_access = !orig_callee->is_method_handle_intrinsic(); // method handle intrinsics don't perform access checks + // Dtrace currently doesn't work unless all calls are vanilla if (env()->dtrace_method_probes()) { allow_inline = false; @@ -239,7 +241,8 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool // this invoke because it may lead to bimorphic inlining which // a speculative type should help us avoid. receiver_method = callee->resolve_invoke(jvms->method()->holder(), - speculative_receiver_type); + speculative_receiver_type, + check_access); if (receiver_method == nullptr) { speculative_receiver_type = nullptr; } else { @@ -256,8 +259,9 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool (morphism == 2 && UseBimorphicInlining))) { // receiver_method = profile.method(); // Profiles do not suggest methods now. Look it up in the major receiver. + assert(check_access, "required"); receiver_method = callee->resolve_invoke(jvms->method()->holder(), - profile.receiver(0)); + profile.receiver(0)); } if (receiver_method != nullptr) { // The single majority receiver sufficiently outweighs the minority. @@ -268,8 +272,9 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool CallGenerator* next_hit_cg = nullptr; ciMethod* next_receiver_method = nullptr; if (morphism == 2 && UseBimorphicInlining) { + assert(check_access, "required"); next_receiver_method = callee->resolve_invoke(jvms->method()->holder(), - profile.receiver(1)); + profile.receiver(1)); if (next_receiver_method != nullptr) { next_hit_cg = this->call_generator(next_receiver_method, vtable_index, !call_does_dispatch, jvms, @@ -342,6 +347,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool if (singleton != nullptr) { assert(singleton != declared_interface, "not a unique implementor"); + assert(check_access, "required"); ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(caller->holder(), declared_interface, singleton); diff --git a/test/hotspot/jtreg/compiler/jsr292/MHInlineTest.java b/test/hotspot/jtreg/compiler/jsr292/MHInlineTest.java index a8e76f5797d..4638c27fe59 100644 --- a/test/hotspot/jtreg/compiler/jsr292/MHInlineTest.java +++ b/test/hotspot/jtreg/compiler/jsr292/MHInlineTest.java @@ -51,7 +51,8 @@ public class MHInlineTest { "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", "-XX:-TieredCompilation", "-Xbatch", "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", - "-XX:CompileCommand=dontinline,compiler.jsr292.MHInlineTest::test*", + "-XX:CompileCommand=quiet", + "-XX:CompileCommand=compileonly,compiler.jsr292.MHInlineTest::test*", Launcher.class.getName()); OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); @@ -60,13 +61,17 @@ public class MHInlineTest { // The test is applicable only to C2 (present in Server VM). if (analyzer.getStderr().contains("Server VM")) { + analyzer.shouldContain("compiler.jsr292.MHInlineTest$A::package_final_x (3 bytes) inline (hot)"); + analyzer.shouldContain("compiler.jsr292.MHInlineTest$A::private_x (3 bytes) inline (hot)"); + analyzer.shouldContain("compiler.jsr292.MHInlineTest$A::package_static_x (3 bytes) inline (hot)"); + analyzer.shouldContain("compiler.jsr292.MHInlineTest$B::public_x (3 bytes) inline (hot)"); analyzer.shouldContain("compiler.jsr292.MHInlineTest$B::protected_x (3 bytes) inline (hot)"); analyzer.shouldContain("compiler.jsr292.MHInlineTest$B::package_x (3 bytes) inline (hot)"); - analyzer.shouldContain("compiler.jsr292.MHInlineTest$A::package_final_x (3 bytes) inline (hot)"); analyzer.shouldContain("compiler.jsr292.MHInlineTest$B::private_x (3 bytes) inline (hot)"); analyzer.shouldContain("compiler.jsr292.MHInlineTest$B::private_static_x (3 bytes) inline (hot)"); - analyzer.shouldContain("compiler.jsr292.MHInlineTest$A::package_static_x (3 bytes) inline (hot)"); + + analyzer.shouldNotContain("failed to inline"); } else { throw new SkippedException("The test is applicable only to C2 (present in Server VM)"); } @@ -75,23 +80,24 @@ public class MHInlineTest { static class A { public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); - public Class public_x() { return A.class; } - protected Class protected_x() { return A.class; } - Class package_x() { return A.class; } - final Class package_final_x() { return A.class; } + public Class public_x() { return A.class; } + protected Class protected_x() { return A.class; } + /*package*/ Class package_x() { return A.class; } + /*package*/ final Class package_final_x() { return A.class; } + private Class private_x() { return A.class; } - static Class package_static_x() { return A.class; } + /*package*/ static Class package_static_x() { return A.class; } } static class B extends A { public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); - @Override public Class public_x() { return B.class; } - @Override protected Class protected_x() { return B.class; } - @Override Class package_x() { return B.class; } + @Override public Class public_x() { return B.class; } + @Override protected Class protected_x() { return B.class; } + @Override /*package*/ Class package_x() { return B.class; } - private Class private_x() { return B.class; } - static Class private_static_x() { return B.class; } + private Class private_x() { return B.class; } + private static Class private_static_x() { return B.class; } } static final MethodHandle A_PUBLIC_X; @@ -99,6 +105,7 @@ public class MHInlineTest { static final MethodHandle A_PACKAGE_X; static final MethodHandle A_PACKAGE_STATIC_X; static final MethodHandle A_PACKAGE_FINAL_X; + static final MethodHandle A_PRIVATE_X; static final MethodHandle B_PRIVATE_X; static final MethodHandle B_PRIVATE_STATIC_X; @@ -117,6 +124,8 @@ public class MHInlineTest { A.class, "package_final_x", MethodType.methodType(Class.class)); A_PACKAGE_STATIC_X = LOOKUP.findStatic( A.class, "package_static_x", MethodType.methodType(Class.class)); + A_PRIVATE_X = LOOKUP.findVirtual( + A.class, "private_x", MethodType.methodType(Class.class)); B_PRIVATE_X = B.LOOKUP.findVirtual( B.class, "private_x", MethodType.methodType(Class.class)); @@ -129,7 +138,18 @@ public class MHInlineTest { static final A a = new B(); - private static void testPublicMH() { + /* ============== public Class public_x() ============== */ + + private static void testPublicMH(A recv) { + try { + Class r = (Class)A_PUBLIC_X.invokeExact(recv); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPublicMHConst() { try { Class r = (Class)A_PUBLIC_X.invokeExact(a); assertEquals(r, B.class); @@ -138,7 +158,18 @@ public class MHInlineTest { } } - private static void testProtectedMH() { + /* ============== protected Class protected_x() ============== */ + + private static void testProtectedMH(A recv) { + try { + Class r = (Class)A_PROTECTED_X.invokeExact(recv); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testProtectedMHConst() { try { Class r = (Class)A_PROTECTED_X.invokeExact(a); assertEquals(r, B.class); @@ -147,7 +178,18 @@ public class MHInlineTest { } } - private static void testPackageMH() { + /* ============== Class package_x() ============== */ + + private static void testPackageMH(A recv) { + try { + Class r = (Class)A_PACKAGE_X.invokeExact(recv); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageMHConst() { try { Class r = (Class)A_PACKAGE_X.invokeExact(a); assertEquals(r, B.class); @@ -156,7 +198,9 @@ public class MHInlineTest { } } - private static void testPackageFinalMH() { + /* ============== final Class package_final_x() ============== */ + + private static void testPackageFinalMH(A recv) { try { Class r = (Class)A_PACKAGE_FINAL_X.invokeExact(a); assertEquals(r, A.class); @@ -165,16 +209,45 @@ public class MHInlineTest { } } - private static void testPackageStaticMH() { + private static void testPackageFinalMHConst() { try { - Class r = (Class)A_PACKAGE_STATIC_X.invokeExact(); + Class r = (Class)A_PACKAGE_FINAL_X.invokeExact(a); assertEquals(r, A.class); } catch (Throwable throwable) { throw new Error(throwable); } } - private static void testPrivateMH() { + /* ============== private Class private_x() ============== */ + + private static void testPrivateA_MH(A recv) { + try { + Class r = (Class)A_PRIVATE_X.invokeExact(recv); + assertEquals(r, A.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPrivateA_MHConst() { + try { + Class r = (Class)A_PRIVATE_X.invokeExact(a); + assertEquals(r, A.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPrivateB_MH(B recv) { + try { + Class r = (Class)B_PRIVATE_X.invokeExact(recv); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPrivateB_MHConst() { try { Class r = (Class)B_PRIVATE_X.invokeExact((B)a); assertEquals(r, B.class); @@ -183,7 +256,19 @@ public class MHInlineTest { } } - private static void testPrivateStaticMH() { + /* ============== static ============== */ + + private static void testPackageStaticMHConst() { + try { + Class r = (Class)A_PACKAGE_STATIC_X.invokeExact(); + assertEquals(r, A.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + + private static void testPrivateStaticMHConst() { try { Class r = (Class)B_PRIVATE_STATIC_X.invokeExact(); assertEquals(r, B.class); @@ -192,28 +277,20 @@ public class MHInlineTest { } } + /* ====================================================================== */ + static class Launcher { public static void main(String[] args) throws Exception { for (int i = 0; i < 20_000; i++) { - testPublicMH(); - } - for (int i = 0; i < 20_000; i++) { - testProtectedMH(); - } - for (int i = 0; i < 20_000; i++) { - testPackageMH(); - } - for (int i = 0; i < 20_000; i++) { - testPackageFinalMH(); - } - for (int i = 0; i < 20_000; i++) { - testPackageStaticMH(); - } - for (int i = 0; i < 20_000; i++) { - testPrivateMH(); - } - for (int i = 0; i < 20_000; i++) { - testPrivateStaticMH(); + testPublicMH(a); testPublicMHConst(); + testProtectedMH(a); testProtectedMHConst(); + testPackageMH(a); testPackageMHConst(); + testPackageFinalMH(a); testPackageFinalMHConst(); + testPrivateA_MH(a); testPrivateA_MHConst(); + testPrivateB_MH((B)a); testPrivateB_MHConst(); + + testPackageStaticMHConst(); + testPrivateStaticMHConst(); } } } From ebf9c5bfc1b2e8e9210cc37283a29d471f913916 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 27 Oct 2025 16:40:17 +0000 Subject: [PATCH 075/736] 8370250: Locale should mention the behavior for duplicate subtags Reviewed-by: naoto --- .../share/classes/java/util/Locale.java | 47 ++++++++++++++----- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index a55ddee648e..452b621ea05 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -204,15 +204,18 @@ import sun.util.locale.provider.TimeZoneNameUtility; * key="x"/value="java-1-7" * * - * BCP 47 deviation: Although BCP 47 requires field values to be registered - * in the IANA Language Subtag Registry, the {@code Locale} class - * does not validate this requirement. For example, the variant code "foobar" - * is well-formed since it is composed of 5 to 8 alphanumerics, but is not defined - * the IANA Language Subtag Registry. The {@link Builder} - * only checks if an individual field satisfies the syntactic - * requirement (is well-formed), but does not validate the value - * itself. Conversely, {@link #of(String, String, String) Locale::of} and its - * overloads do not make any syntactic checks on the input. + * BCP 47 deviation: BCP47 defines the following two levels of + * conformance, + * "valid" and "well-formed". A valid tag requires that it is well-formed, its + * subtag values are registered in the IANA Language Subtag Registry, and it does not + * contain duplicate variant or extension singleton subtags. The {@code Locale} + * class does not enforce that subtags are registered in the Subtag Registry. + * {@link Builder} only checks if an individual field satisfies the syntactic + * requirement (is well-formed). When passed duplicate variants, {@code Builder} + * accepts and includes them. When passed duplicate extension singletons, {@code + * Builder} accepts but ignores the duplicate key and its associated value. + * Conversely, {@link #of(String, String, String) Locale::of} and its + * overloads do not check if the input is well-formed at all. * *

    Unicode BCP 47 U Extension

    * @@ -246,7 +249,11 @@ import sun.util.locale.provider.TimeZoneNameUtility; * can be empty, or a series of subtags 3-8 alphanums in length). A * well-formed locale attribute has the form * {@code [0-9a-zA-Z]{3,8}} (it is a single subtag with the same - * form as a locale type subtag). + * form as a locale type subtag). Duplicate locale attributes as well + * as locale keys do not convey meaning. For methods in {@code Locale} and + * {@code Locale.Builder} that accept extensions, occurrences of duplicate + * locale attributes as well as locale keys and their associated type are accepted + * but ignored. * *

    The Unicode locale extension specifies optional behavior in * locale-sensitive services. Although the LDML specification defines @@ -561,6 +568,8 @@ import sun.util.locale.provider.TimeZoneNameUtility; * RFC 4647: Matching of Language Tags * @spec https://www.rfc-editor.org/info/rfc5646 * RFC 5646: Tags for Identifying Languages + * @spec https://www.rfc-editor.org/info/rfc6067 + * RFC 6067: BCP 47 Extension U * @spec https://www.unicode.org/reports/tr35 * Unicode Locale Data Markup Language (LDML) * @see Builder @@ -1743,6 +1752,12 @@ public final class Locale implements Cloneable, Serializable { * to {@link Locale.Builder#setLanguageTag(String)} which throws an exception * in this case. * + *

    Duplicate variants are accepted and included by the builder. + * However, duplicate extension singleton keys and their associated type + * are accepted but ignored. The same behavior applies to duplicate locale + * keys and attributes within a U extension. Note that subsequent subtags after + * the occurrence of a duplicate are not ignored. + * *

    The following conversions are performed: