diff --git a/bin/idea.sh b/bin/idea.sh
index eb37964f396..a184884b61a 100644
--- a/bin/idea.sh
+++ b/bin/idea.sh
@@ -125,7 +125,8 @@ if [ -d "$TOPLEVEL_DIR/.hg" ] ; then
VCS_TYPE="hg4idea"
fi
-if [ -d "$TOPLEVEL_DIR/.git" ] ; then
+# Git worktrees use a '.git' file rather than directory, so test both.
+if [ -d "$TOPLEVEL_DIR/.git" -o -f "$TOPLEVEL_DIR/.git" ] ; then
VCS_TYPE="Git"
fi
diff --git a/doc/building.html b/doc/building.html
index f7af2648592..99eb3e0c473 100644
--- a/doc/building.html
+++ b/doc/building.html
@@ -1451,10 +1451,10 @@ of a cross-compiling toolchain and a sysroot environment which can
easily be used together with the --with-devkit configure
option to cross compile the JDK. On Linux/x86_64, the following
command:
bash configure --with-devkit=<devkit-path> --openjdk-target=ppc64-linux-gnu && make
-will configure and build the JDK for Linux/ppc64 assuming that
-<devkit-path> points to a Linux/x86_64 to Linux/ppc64
-devkit.
bash configure --with-devkit=<devkit-path> --openjdk-target=ppc64le-linux-gnu && make
+will configure and build the JDK for Linux/ppc64le assuming that
+<devkit-path> points to a Linux/x86_64 to
+Linux/ppc64le devkit.
Devkits can be created from the make/devkit directory by
executing:
make [ TARGETS="<TARGET_TRIPLET>+" ] [ BASE_OS=<OS> ] [ BASE_OS_VERSION=<VER> ]
@@ -1481,10 +1481,10 @@ following targets are known to work:
The report is stored in
build/$BUILD/test-results/jcov-output/diff_coverage_report
file.
See Testing +Ahead-of-time optimizations.
The test concurrency (-concurrency).
test/jtreg_test_thread_factory/ directory. This class gets
compiled during the test image build. The implementation of the Virtual
class creates a new virtual thread for executing each test class.
+Executes JTReg tests with JVM TI stress agent. The stress agent is
+the part of test library and located in
+test/lib/jdk/test/lib/jvmti/libJvmtiStressAgent.cpp. The
+value of this argument is set as JVM TI agent options. This mode uses
+ProblemList-jvmti-stress-agent.txt as an additional exclude list.
The test mode (agentvm or othervm).
Defaults to agentvm.
-wi <num>.
same values as -rff, i.e., text,
csv, scsv, json, or
latex.
+The path to the JDK that will be used to run the benchmarks.
+Defaults to build/<CONF-NAME>/jdk.
The path to the JAR containing the benchmarks.
+Defaults to test/micro/benchmarks.jar.
Additional VM arguments to provide to forked off VMs. Same as
-jvmArgs <args>
@Artifact class. (See
JTREG="JAVA_OPTIONS=-Djdk.test.lib.artifacts.nsslib-linux_aarch64=/path/to/NSS-libs"
For more notes about the PKCS11 tests, please refer to test/jdk/sun/security/pkcs11/README.
-One way to improve test coverage of ahead-of-time (AOT) optimizations in the JDK is to run existing jtreg test cases in a special "AOT_JDK" mode. Example:
diff --git a/doc/testing.md b/doc/testing.md index bb56c05c295..4cfc36c85f9 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -367,6 +367,10 @@ between the specified revision and the repository tip. The report is stored in `build/$BUILD/test-results/jcov-output/diff_coverage_report` file. +#### AOT_JDK + +See [Testing Ahead-of-time optimizations](#testing-ahead-of-time-optimizations). + ### JTReg keywords #### JOBS @@ -397,6 +401,13 @@ the `test/jtreg_test_thread_factory/` directory. This class gets compiled during the test image build. The implementation of the Virtual class creates a new virtual thread for executing each test class. +#### JVMTI_STRESS_AGENT + +Executes JTReg tests with JVM TI stress agent. The stress agent is the part of +test library and located in `test/lib/jdk/test/lib/jvmti/libJvmtiStressAgent.cpp`. +The value of this argument is set as JVM TI agent options. +This mode uses ProblemList-jvmti-stress-agent.txt as an additional exclude list. + #### TEST_MODE The test mode (`agentvm` or `othervm`). @@ -545,6 +556,18 @@ Amount of time to spend in each warmup iteration. Same as specifying `-w Specify to have the test run save a log of the values. Accepts the same values as `-rff`, i.e., `text`, `csv`, `scsv`, `json`, or `latex`. +#### TEST_JDK + +The path to the JDK that will be used to run the benchmarks. + +Defaults to `build/+ * WARNING: The caller of this method is assumed to have relinquished + * and transferred the ownership of the byte array. It can thus be + * exclusively used to construct the {@code String}. + * + * @param src byte array containing encoded characters + * @param cs charset the byte array encoded in + * + * @throws CharacterCodingException for malformed input or unmappable characters + */ static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException { try { return newStringNoRepl1(src, cs); @@ -778,7 +803,7 @@ public final class String return ""; } if (cs == UTF_8.INSTANCE) { - return newStringUTF8NoRepl(src, 0, src.length, false); + return newStringUTF8NoRepl(src, 0, src.length); } if (cs == ISO_8859_1.INSTANCE) { if (COMPACT_STRINGS) @@ -1019,7 +1044,7 @@ public final class String int sp = 0; int sl = len; while (sp < sl) { - int ret = StringCoding.implEncodeISOArray(val, sp, dst, dp, len); + int ret = StringCoding.encodeISOArray(val, sp, dst, dp, len); sp = sp + ret; dp = dp + ret; if (ret != len) { @@ -1284,13 +1309,18 @@ public final class String return encodeUTF8_UTF16(val, doReplace); } - if (!StringCoding.hasNegatives(val, 0, val.length)) { + int positives = StringCoding.countPositives(val, 0, val.length); + if (positives == val.length) { return val.clone(); } - int dp = 0; byte[] dst = StringUTF16.newBytesFor(val.length); - for (byte c : val) { + if (positives > 0) { + System.arraycopy(val, 0, dst, 0, positives); + } + int dp = positives; + for (int i = dp; i < val.length; i++) { + byte c = val[i]; if (c < 0) { dst[dp++] = (byte) (0xc0 | ((c & 0xff) >> 6)); dst[dp++] = (byte) (0x80 | (c & 0x3f)); diff --git a/src/java.base/share/classes/java/lang/StringCoding.java b/src/java.base/share/classes/java/lang/StringCoding.java index c02af28c37d..545f216b755 100644 --- a/src/java.base/share/classes/java/lang/StringCoding.java +++ b/src/java.base/share/classes/java/lang/StringCoding.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. * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,8 +26,11 @@ package java.lang; +import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.IntrinsicCandidate; +import java.util.function.BiFunction; + /** * Utility class for string encoding and decoding. */ @@ -38,7 +41,7 @@ class StringCoding { /** * Count the number of leading non-zero ascii chars in the range. */ - public static int countNonZeroAscii(String s) { + static int countNonZeroAscii(String s) { byte[] value = s.value(); if (s.isLatin1()) { return countNonZeroAsciiLatin1(value, 0, value.length); @@ -50,7 +53,7 @@ class StringCoding { /** * Count the number of non-zero ascii chars in the range. */ - public static int countNonZeroAsciiLatin1(byte[] ba, int off, int len) { + private static int countNonZeroAsciiLatin1(byte[] ba, int off, int len) { int limit = off + len; for (int i = off; i < limit; i++) { if (ba[i] <= 0) { @@ -63,7 +66,7 @@ class StringCoding { /** * Count the number of leading non-zero ascii chars in the range. */ - public static int countNonZeroAsciiUTF16(byte[] ba, int off, int strlen) { + private static int countNonZeroAsciiUTF16(byte[] ba, int off, int strlen) { int limit = off + strlen; for (int i = off; i < limit; i++) { char c = StringUTF16.charAt(ba, i); @@ -74,7 +77,7 @@ class StringCoding { return strlen; } - public static boolean hasNegatives(byte[] ba, int off, int len) { + static boolean hasNegatives(byte[] ba, int off, int len) { return countPositives(ba, off, len) != len; } @@ -85,9 +88,24 @@ class StringCoding { * bytes in the range. If there are negative bytes, the implementation must return * a value that is less than or equal to the index of the first negative byte * in the range. + * + * @param ba a byte array + * @param off the index of the first byte to start reading from + * @param len the total number of bytes to read + * @throws NullPointerException if {@code ba} is null + * @throws ArrayIndexOutOfBoundsException if the provided sub-range is + * {@linkplain Preconditions#checkFromIndexSize(int, int, int, BiFunction) out of bounds} */ + static int countPositives(byte[] ba, int off, int len) { + Preconditions.checkFromIndexSize( + off, len, + ba.length, // Implicit null check on `ba` + Preconditions.AIOOBE_FORMATTER); + return countPositives0(ba, off, len); + } + @IntrinsicCandidate - public static int countPositives(byte[] ba, int off, int len) { + private static int countPositives0(byte[] ba, int off, int len) { int limit = off + len; for (int i = off; i < limit; i++) { if (ba[i] < 0) { @@ -97,9 +115,37 @@ class StringCoding { return len; } + /** + * Encodes as many ISO-8859-1 codepoints as possible from the source byte + * array containing characters encoded in UTF-16, into the destination byte + * array, assuming that the encoding is ISO-8859-1 compatible. + * + * @param sa the source byte array containing characters encoded in UTF-16 + * @param sp the index of the character (not byte!) from the source array to start reading from + * @param da the target byte array + * @param dp the index of the target array to start writing to + * @param len the maximum number of characters (not bytes!) to be encoded + * @return the total number of characters (not bytes!) successfully encoded + * @throws NullPointerException if any of the provided arrays is null + */ + static int encodeISOArray(byte[] sa, int sp, + byte[] da, int dp, int len) { + // This method should tolerate invalid arguments, matching the lenient behavior of the VM intrinsic. + // Hence, using operator expressions instead of `Preconditions`, which throw on failure. + int sl; + if ((sp | dp | len) < 0 || + // Halving the length of `sa` to obtain the number of characters: + sp >= (sl = sa.length >>> 1) || // Implicit null check on `sa` + dp >= da.length) { // Implicit null check on `da` + return 0; + } + int minLen = Math.min(len, Math.min(sl - sp, da.length - dp)); + return encodeISOArray0(sa, sp, da, dp, minLen); + } + @IntrinsicCandidate - public static int implEncodeISOArray(byte[] sa, int sp, - byte[] da, int dp, int len) { + private static int encodeISOArray0(byte[] sa, int sp, + byte[] da, int dp, int len) { int i = 0; for (; i < len; i++) { char c = StringUTF16.getChar(sa, sp++); @@ -110,10 +156,35 @@ class StringCoding { return i; } + /** + * Encodes as many ASCII codepoints as possible from the source + * character array into the destination byte array, assuming that + * the encoding is ASCII compatible. + * + * @param sa the source character array + * @param sp the index of the source array to start reading from + * @param da the target byte array + * @param dp the index of the target array to start writing to + * @param len the maximum number of characters to be encoded + * @return the total number of characters successfully encoded + * @throws NullPointerException if any of the provided arrays is null + */ + static int encodeAsciiArray(char[] sa, int sp, + byte[] da, int dp, int len) { + // This method should tolerate invalid arguments, matching the lenient behavior of the VM intrinsic. + // Hence, using operator expressions instead of `Preconditions`, which throw on failure. + if ((sp | dp | len) < 0 || + sp >= sa.length || // Implicit null check on `sa` + dp >= da.length) { // Implicit null check on `da` + return 0; + } + int minLen = Math.min(len, Math.min(sa.length - sp, da.length - dp)); + return encodeAsciiArray0(sa, sp, da, dp, minLen); + } + @IntrinsicCandidate - public static int implEncodeAsciiArray(char[] sa, int sp, - byte[] da, int dp, int len) - { + static int encodeAsciiArray0(char[] sa, int sp, + byte[] da, int dp, int len) { int i = 0; for (; i < len; i++) { char c = sa[sp++]; diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 1d62d698896..f046ed4111a 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -55,7 +55,6 @@ import java.util.Properties; import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.Executor; -import java.util.concurrent.ScheduledExecutorService; import java.util.function.Supplier; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; @@ -2127,6 +2126,11 @@ public final class System { public int countNonZeroAscii(String s) { return StringCoding.countNonZeroAscii(s); } + + public String uncheckedNewStringWithLatin1Bytes(byte[] bytes) { + return String.newStringWithLatin1Bytes(bytes); + } + public String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException { return String.newStringNoRepl(bytes, cs); } @@ -2140,10 +2144,6 @@ public final class System { return String.getBytesNoRepl(s, cs); } - public String newStringUTF8NoRepl(byte[] bytes, int off, int len) { - return String.newStringUTF8NoRepl(bytes, off, len, true); - } - public byte[] getBytesUTF8NoRepl(String s) { return String.getBytesUTF8NoRepl(s); } @@ -2156,8 +2156,8 @@ public final class System { return String.decodeASCII(src, srcOff, dst, dstOff, len); } - public int uncheckedEncodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len) { - return StringCoding.implEncodeAsciiArray(src, srcOff, dst, dstOff, len); + public int encodeASCII(char[] sa, int sp, byte[] da, int dp, int len) { + return StringCoding.encodeAsciiArray(sa, sp, da, dp, len); } public InputStream initialSystemIn() { diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index e640700c2e9..c1070bbcc77 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -175,6 +175,11 @@ public sealed interface CodeBuilder * A builder for blocks of code. Its {@link #startLabel()} and {@link * #endLabel()} do not enclose the entire method body, but from the start to * the end of the block. + *
+ * The location where a block of code merges back to its parent block, as + * represented by the {@link #breakLabel()}, is expected to be reachable, + * either from this block or the parent block. The built code may be + * malformed if there is no executable code at that location. * * @since 24 */ @@ -325,6 +330,11 @@ public sealed interface CodeBuilder /** * A builder to add catch blocks. + *
+ * The order of catch blocks is significant. When an exception is thrown + * by the try block, the first catch block whose exception type is {@linkplain + * Class#isAssignableFrom(Class) the same class as or a superclass of} the + * class of exception thrown is branched to (JVMS {@jvms 2.10}). * * @see #trying * @see ExceptionCatch @@ -343,13 +353,16 @@ public sealed interface CodeBuilder * If the type of exception is {@code null} then the catch block catches * all exceptions. * + * @apiNote + * If the type of exception to catch is already handled by previous + * catch blocks, this block will never be executed. + * * @param exceptionType the type of exception to catch, may be {@code null} * @param catchHandler handler that receives a {@link BlockCodeBuilder} to * generate the body of the catch block * @return this builder - * @throws IllegalArgumentException if an existing catch block catches - * an exception of the given type or {@code exceptionType} - * represents a primitive type + * @throws IllegalArgumentException if {@code exceptionType} represents + * a primitive type * @see #catchingMulti * @see #catchingAll */ @@ -367,12 +380,16 @@ public sealed interface CodeBuilder * If list of exception types is empty then the catch block catches all * exceptions. * + * @apiNote + * If every type of exception to catch is already handled by previous + * catch blocks, this block will never be executed. + * * @param exceptionTypes the types of exception to catch * @param catchHandler handler that receives a {@link BlockCodeBuilder} * to generate the body of the catch block * @return this builder - * @throws IllegalArgumentException if an existing catch block catches - * one or more exceptions of the given types + * @throws IllegalArgumentException if any exception type represents a + * primitive type * @see #catching * @see #catchingAll */ @@ -387,10 +404,12 @@ public sealed interface CodeBuilder * The caught exception will be on top of the operand stack when the * catch block is entered. * + * @apiNote + * Since this block intercepts all exceptions, all subsequent catch + * blocks will never be executed. + * * @param catchAllHandler handler that receives a {@link BlockCodeBuilder} * to generate the body of the catch block - * @throws IllegalArgumentException if an existing catch block catches - * all exceptions * @see #catching * @see #catchingMulti */ diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java index e924ca718e7..b0e5af2941e 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java @@ -39,8 +39,10 @@ import jdk.internal.classfile.impl.AbstractPseudoInstruction; * A pseudo-instruction modeling an entry in the {@code exception_table} array * of a {@link CodeAttribute Code} attribute. Catch (JVMS {@jvms 3.12}) and * finally (JVMS {@jvms 3.14}) blocks in Java source code compile to exception - * table entries. Delivered as a {@link CodeElement} when traversing the - * contents of a {@link CodeModel}. + * table entries. The order of exception table entries is significant: when an + * exception is thrown in a method, execution branches to the first matching + * exception handler if such a handler exists (JVMS {@jvms 2.10}). Delivered as + * a {@link CodeElement} when traversing the contents of a {@link CodeModel}. *
* An exception table entry is composite:
* {@snippet lang=text :
diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java
index c976342033f..0ef45ec34bb 100644
--- a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java
+++ b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java
@@ -44,7 +44,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import static java.lang.constant.DirectMethodHandleDesc.*;
import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC;
/**
@@ -338,9 +337,6 @@ public final class ConstantDescs {
*/
public static final MethodTypeDesc MTD_void = MethodTypeDesc.of(CD_void);
- static final DirectMethodHandleDesc MHD_METHODHANDLE_ASTYPE
- = MethodHandleDesc.ofMethod(Kind.VIRTUAL, CD_MethodHandle, "asType",
- MethodTypeDesc.of(CD_MethodHandle, CD_MethodType));
/**
* Returns a {@link MethodHandleDesc} corresponding to a bootstrap method for
* an {@code invokedynamic} callsite, which is a static method whose leading
diff --git a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
index 6a3541bf5e9..18786481fa6 100644
--- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
+++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2024, 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
@@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import jdk.internal.constant.AsTypeMethodHandleDesc;
import jdk.internal.constant.DirectMethodHandleDescImpl;
import static java.lang.constant.ConstantDescs.CD_void;
diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java
index 3b7d9e0d65b..c24998344c1 100644
--- a/src/java.base/share/classes/java/math/BigDecimal.java
+++ b/src/java.base/share/classes/java/math/BigDecimal.java
@@ -35,8 +35,6 @@ import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.io.StreamCorruptedException;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects;
@@ -4149,11 +4147,7 @@ public class BigDecimal extends Number implements Comparable If the locale contains "rg" (region override)
- * Unicode extension,
- * the symbols are overridden for the designated region.
+ * The "rg" (region override), "nu" (numbering system), and "cu" (currency)
+ * {@code Locale} Unicode
+ * extensions are supported which may override values within the symbols.
+ * For both "nu" and "cu", if they are specified in addition to "rg" by the
+ * backing {@code Locale}, the respective values from the "nu" and "cu" extension
+ * supersede the implicit ones from the "rg" extension.
*
* @see java.util.Locale
* @see DecimalFormat
@@ -88,7 +91,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
* @see java.util.Locale.Category#FORMAT
*/
public DecimalFormatSymbols() {
- initialize( Locale.getDefault(Locale.Category.FORMAT) );
+ initialize(Locale.getDefault(Locale.Category.FORMAT));
}
/**
@@ -111,8 +114,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
* @param locale the desired locale
* @throws NullPointerException if {@code locale} is null
*/
- public DecimalFormatSymbols( Locale locale ) {
- initialize( locale );
+ public DecimalFormatSymbols(Locale locale) {
+ initialize(locale);
}
/**
@@ -812,7 +815,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
/**
* Initializes the symbols from the FormatData resource bundle.
*/
- private void initialize( Locale locale ) {
+ private void initialize(Locale locale) {
this.locale = locale;
// check for region override
diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java
index 3eeabb7e77e..41c143178da 100644
--- a/src/java.base/share/classes/java/text/DigitList.java
+++ b/src/java.base/share/classes/java/text/DigitList.java
@@ -42,6 +42,7 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import jdk.internal.math.FloatingDecimal;
+import jdk.internal.util.ArraysSupport;
/**
* Digit List. Private to DecimalFormat.
@@ -51,11 +52,11 @@ import jdk.internal.math.FloatingDecimal;
* DecimalFormat is that DigitList handles the radix 10 representation
* issues; DecimalFormat handles the locale-specific issues such as
* positive/negative, grouping, decimal point, currency, and so on.
- *
+ *
* A DigitList is really a representation of a floating point value.
* It may be an integer value; we assume that a double has sufficient
* precision to represent all digits of a long.
- *
+ *
* The DigitList representation consists of a string of characters,
* which are the digits radix 10, from '0' to '9'. It also has a radix
* 10 exponent associated with it. The value represented by a DigitList
@@ -81,22 +82,22 @@ final class DigitList implements Cloneable {
/**
* These data members are intentionally public and can be set directly.
- *
+ *
* The value represented is given by placing the decimal point before
* digits[decimalAt]. If decimalAt is < 0, then leading zeros between
* the decimal point and the first nonzero digit are implied. If decimalAt
* is > count, then trailing zeros between the digits[count-1] and the
* decimal point are implied.
- *
+ *
* Equivalently, the represented value is given by f * 10^decimalAt. Here
* f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
* the right of the decimal.
- *
+ *
* DigitList is normalized, so if it is non-zero, digits[0] is non-zero. We
* don't allow denormalized numbers because our exponent is effectively of
* unlimited magnitude. The count value contains the number of significant
* digits present in digits[].
- *
+ *
* Zero is represented by any DigitList with count == 0 or with each digits[i]
* for all i <= count == '0'.
*/
@@ -153,7 +154,7 @@ final class DigitList implements Cloneable {
*/
public void append(char digit) {
if (count == digits.length) {
- char[] data = new char[count + 100];
+ char[] data = new char[ArraysSupport.newLength(count, 1, count)];
System.arraycopy(digits, 0, data, 0, count);
digits = data;
}
@@ -165,7 +166,7 @@ final class DigitList implements Cloneable {
* If (count == 0) this returns 0.0,
* unlike Double.parseDouble("") which throws NumberFormatException.
*/
- public final double getDouble() {
+ public double getDouble() {
if (count == 0) {
return 0.0;
}
@@ -177,7 +178,7 @@ final class DigitList implements Cloneable {
* If (count == 0) this returns 0,
* unlike Long.parseLong("") which throws NumberFormatException.
*/
- public final long getLong() {
+ public long getLong() {
// for now, simple implementation; later, do proper IEEE native stuff
if (count == 0) {
@@ -207,7 +208,7 @@ final class DigitList implements Cloneable {
* If (count == 0) this does not throw a NumberFormatException,
* unlike BigDecimal("").
*/
- public final BigDecimal getBigDecimal() {
+ public BigDecimal getBigDecimal() {
if (count == 0) {
return BigDecimal.valueOf(0, -decimalAt);
}
@@ -279,10 +280,26 @@ final class DigitList implements Cloneable {
* @param maximumFractionDigits The most fractional digits which should
* be converted.
*/
- final void set(boolean isNegative, double source, int maximumFractionDigits) {
+ void set(boolean isNegative, double source, int maximumFractionDigits) {
set(isNegative, source, maximumFractionDigits, true);
}
+ /*
+ * This compatibility option will only be available for a *very* limited
+ * number of releases.
+ * It restores the original behavior to help migrating to the new one,
+ * and is used by adding
+ * -Djdk.compat.DecimalFormat=true
+ * to the launcher's command line.
+ *
+ * The new behavior differs from the old one only in very rare cases,
+ * so migration should be painless.
+ *
+ * When this option is removed, the old behavior, including relevant
+ * fields and methods, will be removed as well.
+ */
+ private static final boolean COMPAT = Boolean.getBoolean("jdk.compat.DecimalFormat");
+
/**
* Set the digit list to a representation of the given double value.
* This method supports both fixed-point and exponential notation.
@@ -294,9 +311,9 @@ final class DigitList implements Cloneable {
* @param fixedPoint If true, then maximumDigits is the maximum
* fractional digits to be converted. If false, total digits.
*/
- final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
-
- FloatingDecimal.BinaryToASCIIConverter fdConverter = FloatingDecimal.getBinaryToASCIIConverter(source);
+ void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
+ FloatingDecimal.BinaryToASCIIConverter fdConverter =
+ FloatingDecimal.getBinaryToASCIIConverter(source, COMPAT);
boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp();
boolean valueExactAsDecimal = fdConverter.decimalDigitsExact();
assert !fdConverter.isExceptional();
@@ -414,7 +431,7 @@ final class DigitList implements Cloneable {
*
* Upon return, count will be less than or equal to maximumDigits.
*/
- private final void round(int maximumDigits,
+ private void round(int maximumDigits,
boolean alreadyRounded,
boolean valueExactAsDecimal) {
// Eliminate digits beyond maximum digits to be displayed.
@@ -581,7 +598,7 @@ final class DigitList implements Cloneable {
/**
* Utility routine to set the value of the digit list from a long
*/
- final void set(boolean isNegative, long source) {
+ void set(boolean isNegative, long source) {
set(isNegative, source, 0);
}
@@ -594,7 +611,7 @@ final class DigitList implements Cloneable {
* If maximumDigits is lower than the number of significant digits
* in source, the representation will be rounded. Ignored if <= 0.
*/
- final void set(boolean isNegative, long source, int maximumDigits) {
+ void set(boolean isNegative, long source, int maximumDigits) {
this.isNegative = isNegative;
// This method does not expect a negative number. However,
@@ -644,7 +661,7 @@ final class DigitList implements Cloneable {
* @param fixedPoint If true, then maximumDigits is the maximum
* fractional digits to be converted. If false, total digits.
*/
- final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
+ void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
String s = source.toString();
extendDigits(s.length());
@@ -661,7 +678,7 @@ final class DigitList implements Cloneable {
* If maximumDigits is lower than the number of significant digits
* in source, the representation will be rounded. Ignored if <= 0.
*/
- final void set(boolean isNegative, BigInteger source, int maximumDigits) {
+ void set(boolean isNegative, BigInteger source, int maximumDigits) {
this.isNegative = isNegative;
String s = source.toString();
int len = s.length();
@@ -771,7 +788,7 @@ final class DigitList implements Cloneable {
}
}
- private final char[] getDataChars(int length) {
+ private char[] getDataChars(int length) {
if (data == null || data.length < length) {
data = new char[length];
}
diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java
index bd4ec53656a..0f4da56de0c 100644
--- a/src/java.base/share/classes/java/text/NumberFormat.java
+++ b/src/java.base/share/classes/java/text/NumberFormat.java
@@ -103,10 +103,13 @@ import sun.util.locale.provider.LocaleServiceProviderPool;
*
- * If both "nu" and "rg" are specified, the decimal digits from the "nu"
- * extension supersedes the implicit one from the "rg" extension.
+ * For both "nu" and "cu", if they are specified in addition to "rg", the respective
+ * values from the "nu" and "cu" extension supersede the implicit ones from the "rg" extension.
* Although Unicode extensions
* defines various keys and values, actual locale-sensitive service implementations
* in a Java Runtime Environment might not support any particular Unicode locale
diff --git a/src/java.base/share/classes/java/util/HexFormat.java b/src/java.base/share/classes/java/util/HexFormat.java
index 99d047995fd..aebb8b9af52 100644
--- a/src/java.base/share/classes/java/util/HexFormat.java
+++ b/src/java.base/share/classes/java/util/HexFormat.java
@@ -33,8 +33,6 @@ import jdk.internal.util.HexDigits;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.CharBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.StandardCharsets;
/**
* {@code HexFormat} converts between bytes and chars and hex-encoded strings which may include
@@ -460,12 +458,7 @@ public final class HexFormat {
// Delimiter formatting not to a single byte
return null;
}
- try {
- // Return a new string using the bytes without making a copy
- return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
- } catch (CharacterCodingException cce) {
- throw new AssertionError(cce);
- }
+ return jla.uncheckedNewStringWithLatin1Bytes(rep);
}
/**
@@ -695,11 +688,7 @@ public final class HexFormat {
byte[] rep = new byte[2];
rep[0] = (byte)toHighHexDigit(value);
rep[1] = (byte)toLowHexDigit(value);
- try {
- return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
- } catch (CharacterCodingException cce) {
- throw new AssertionError(cce);
- }
+ return jla.uncheckedNewStringWithLatin1Bytes(rep);
}
/**
@@ -731,11 +720,7 @@ public final class HexFormat {
rep[2] = (byte)toHighHexDigit((byte)value);
rep[3] = (byte)toLowHexDigit((byte)value);
- try {
- return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
- } catch (CharacterCodingException cce) {
- throw new AssertionError(cce);
- }
+ return jla.uncheckedNewStringWithLatin1Bytes(rep);
}
/**
@@ -759,11 +744,7 @@ public final class HexFormat {
rep[6] = (byte)toHighHexDigit((byte)value);
rep[7] = (byte)toLowHexDigit((byte)value);
- try {
- return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
- } catch (CharacterCodingException cce) {
- throw new AssertionError(cce);
- }
+ return jla.uncheckedNewStringWithLatin1Bytes(rep);
}
/**
@@ -795,11 +776,7 @@ public final class HexFormat {
rep[14] = (byte)toHighHexDigit((byte)value);
rep[15] = (byte)toLowHexDigit((byte)value);
- try {
- return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
- } catch (CharacterCodingException cce) {
- throw new AssertionError(cce);
- }
+ return jla.uncheckedNewStringWithLatin1Bytes(rep);
}
/**
@@ -823,11 +800,7 @@ public final class HexFormat {
rep[i] = (byte)toLowHexDigit((byte)(value));
value = value >>> 4;
}
- try {
- return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
- } catch (CharacterCodingException cce) {
- throw new AssertionError(cce);
- }
+ return jla.uncheckedNewStringWithLatin1Bytes(rep);
}
/**
diff --git a/src/java.base/share/classes/java/util/UUID.java b/src/java.base/share/classes/java/util/UUID.java
index 5961fce9cb2..d1c81badba6 100644
--- a/src/java.base/share/classes/java/util/UUID.java
+++ b/src/java.base/share/classes/java/util/UUID.java
@@ -25,8 +25,6 @@
package java.util;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.StandardCharsets;
import java.security.*;
import jdk.internal.access.JavaLangAccess;
@@ -479,11 +477,7 @@ public final class UUID implements java.io.Serializable, Comparable
+ * WARNING: The caller of this method shall relinquish and transfer the
+ * ownership of the byte array to the callee, since the latter will not
+ * make a copy.
+ *
+ * @param bytes the byte array source
+ * @return the newly created string
+ */
+ String uncheckedNewStringWithLatin1Bytes(byte[] bytes);
+
/**
* Constructs a new {@code String} by decoding the specified byte array
* using the specified {@linkplain java.nio.charset.Charset charset}.
@@ -350,16 +363,6 @@ public interface JavaLangAccess {
*/
byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException;
- /**
- * Returns a new string by decoding from the given UTF-8 bytes array.
- *
- * @param off the index of the first byte to decode
- * @param len the number of bytes to decode
- * @return the newly created string
- * @throws IllegalArgumentException for malformed or unmappable bytes.
- */
- String newStringUTF8NoRepl(byte[] bytes, int off, int len);
-
/**
* Get the {@code char} at {@code index} in a {@code byte[]} in internal
* UTF-16 representation.
@@ -422,15 +425,19 @@ public interface JavaLangAccess {
PrintStream initialSystemErr();
/**
- * Encodes as many ASCII codepoints as possible from the source array into
- * the destination byte array, assuming that the encoding is ASCII
- * compatible.
- *
- * WARNING: This method does not perform any bound checks.
+ * Encodes as many ASCII codepoints as possible from the source
+ * character array into the destination byte array, assuming that
+ * the encoding is ASCII compatible.
*
- * @return the number of bytes successfully encoded, or 0 if none
+ * @param sa the source character array
+ * @param sp the index of the source array to start reading from
+ * @param da the target byte array
+ * @param dp the index of the target array to start writing to
+ * @param len the total number of characters to be encoded
+ * @return the total number of characters successfully encoded
+ * @throws NullPointerException if any of the provided arrays is null
*/
- int uncheckedEncodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len);
+ int encodeASCII(char[] sa, int sp, byte[] da, int dp, int len);
/**
* Set the cause of Throwable
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java
index d520753326e..89d43135551 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,9 @@ package jdk.internal.classfile.impl;
import java.lang.classfile.CodeBuilder;
import java.lang.classfile.Label;
import java.lang.classfile.Opcode;
+import java.lang.classfile.constantpool.ClassEntry;
import java.lang.constant.ClassDesc;
-import java.lang.constant.ConstantDesc;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -39,14 +40,12 @@ public final class CatchBuilderImpl implements CodeBuilder.CatchBuilder {
final CodeBuilder b;
final BlockCodeBuilderImpl tryBlock;
final Label tryCatchEnd;
- final Set Entries in jimage are expressed as one of three {@link Node} types;
+ * resource nodes, directory nodes and link nodes.
+ *
+ * When remapping jimage entries, jimage location names (e.g. {@code
+ * "/java.base/java/lang/Integer.class"}) are prefixed with {@code "/modules"}
+ * to form the names of resource nodes. This aligns with the naming of module
+ * entries in jimage (e.g. "/modules/java.base/java/lang"), which appear as
+ * directory nodes in {@code ImageReader}.
+ *
+ * Package entries (e.g. {@code "/packages/java.lang"} appear as directory
+ * nodes containing link nodes, which resolve back to the root directory of the
+ * module in which that package exists (e.g. {@code "/modules/java.base"}).
+ * Unlike other nodes, the jimage file does not contain explicit entries for
+ * link nodes, and their existence is derived only from the contents of the
+ * parent directory.
+ *
+ * While similar to {@code BasicImageReader}, this class is not a conceptual
+ * subtype of it, and deliberately hides types such as {@code ImageLocation} to
+ * give a focused API based only on nodes.
+ *
* @implNote This class needs to maintain JDK 8 source compatibility.
*
* It is used internally in the JDK to implement jimage/jrtfs access,
@@ -60,6 +85,10 @@ public final class ImageReader implements AutoCloseable {
this.reader = reader;
}
+ /**
+ * Opens an image reader for a jimage file at the specified path, using the
+ * given byte order.
+ */
public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException {
Objects.requireNonNull(imagePath);
Objects.requireNonNull(byteOrder);
@@ -67,6 +96,10 @@ public final class ImageReader implements AutoCloseable {
return SharedImageReader.open(imagePath, byteOrder);
}
+ /**
+ * Opens an image reader for a jimage file at the specified path, using the
+ * platform native byte order.
+ */
public static ImageReader open(Path imagePath) throws IOException {
return open(imagePath, ByteOrder.nativeOrder());
}
@@ -92,146 +125,113 @@ public final class ImageReader implements AutoCloseable {
}
}
- // directory management interface
- public Directory getRootDirectory() throws IOException {
- ensureOpen();
- return reader.getRootDirectory();
- }
-
-
+ /**
+ * Finds the node with the given name.
+ *
+ * @param name a node name of the form {@code "/modules/ Note that no testing is performed to check whether the buffer about
+ * to be released actually came from a call to {@code getResourceBuffer()}.
+ */
public static void releaseByteBuffer(ByteBuffer buffer) {
BasicImageReader.releaseByteBuffer(buffer);
}
- public String getName() {
+ /**
+ * Returns the content of a resource node in a possibly cached byte buffer.
+ * Callers of this method must call {@link #releaseByteBuffer(ByteBuffer)}
+ * when they are finished with it.
+ */
+ public ByteBuffer getResourceBuffer(Node node) {
requireOpen();
- return reader.getName();
- }
-
- public ByteOrder getByteOrder() {
- requireOpen();
- return reader.getByteOrder();
- }
-
- public Path getImagePath() {
- requireOpen();
- return reader.getImagePath();
- }
-
- public ImageStringsReader getStrings() {
- requireOpen();
- return reader.getStrings();
- }
-
- public ImageLocation findLocation(String mn, String rn) {
- requireOpen();
- return reader.findLocation(mn, rn);
- }
-
- public boolean verifyLocation(String mn, String rn) {
- requireOpen();
- return reader.verifyLocation(mn, rn);
- }
-
- public ImageLocation findLocation(String name) {
- requireOpen();
- return reader.findLocation(name);
- }
-
- public String[] getEntryNames() {
- requireOpen();
- return reader.getEntryNames();
- }
-
- public String[] getModuleNames() {
- requireOpen();
- int off = "/modules/".length();
- return reader.findNode("/modules")
- .getChildren()
- .stream()
- .map(Node::getNameString)
- .map(s -> s.substring(off, s.length()))
- .toArray(String[]::new);
- }
-
- public long[] getAttributes(int offset) {
- requireOpen();
- return reader.getAttributes(offset);
- }
-
- public String getString(int offset) {
- requireOpen();
- return reader.getString(offset);
- }
-
- public byte[] getResource(String name) {
- requireOpen();
- return reader.getResource(name);
- }
-
- public byte[] getResource(ImageLocation loc) {
- requireOpen();
- return reader.getResource(loc);
- }
-
- public ByteBuffer getResourceBuffer(ImageLocation loc) {
- requireOpen();
- return reader.getResourceBuffer(loc);
- }
-
- public InputStream getResourceStream(ImageLocation loc) {
- requireOpen();
- return reader.getResourceStream(loc);
+ if (!node.isResource()) {
+ throw new IllegalArgumentException("Not a resource node: " + node);
+ }
+ return reader.getResourceBuffer(node.getLocation());
}
private static final class SharedImageReader extends BasicImageReader {
- static final int SIZE_OF_OFFSET = Integer.BYTES;
-
- static final Map> EXTENDED_PROVIDERS = StableValue.supplier(
+ new Supplier<>() { public List