From 5b7e32a8beee7cb157ef6b2b72637a98e702afa1 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Thu, 16 Oct 2025 10:10:42 -0400 Subject: [PATCH 1/3] 8369921: [lworld] Remove caches of primitive wrapper classes Disable use of wrapper cached values when --enable-preview Add javadoc descriptions for enable-preview. --- .../share/classes/java/lang/Byte.java | 25 +++++++++---- .../share/classes/java/lang/Character.java | 36 +++++++++++++------ .../share/classes/java/lang/Integer.java | 35 ++++++++++++------ .../share/classes/java/lang/Long.java | 34 ++++++++++++------ .../share/classes/java/lang/Short.java | 34 ++++++++++++------ 5 files changed, 117 insertions(+), 47 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Byte.java b/src/java.base/share/classes/java/lang/Byte.java index 25725897380..80df832a482 100644 --- a/src/java.base/share/classes/java/lang/Byte.java +++ b/src/java.base/share/classes/java/lang/Byte.java @@ -26,6 +26,7 @@ package java.lang; import jdk.internal.misc.CDS; +import jdk.internal.misc.PreviewFeatures; import jdk.internal.value.DeserializeConstructor; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -142,11 +143,23 @@ private ByteCache() {} /** * Returns a {@code Byte} instance representing the specified * {@code byte} value. - * If a new {@code Byte} instance is not required, this method - * should generally be used in preference to the constructor - * {@link #Byte(byte)}, as this method is likely to yield - * significantly better space and time performance since - * all byte values are cached. + *
+ *
+ *

+ * - When preview features are NOT enabled, {@code Byte} is an identity class. + * If a new {@code Byte} instance is not required, this method + * should generally be used in preference to the constructor + * {@link #Byte(byte)}, as this method is likely to yield + * significantly better space and time performance since + * all byte values are cached. + *

+ *

+ * - When preview features are enabled, {@code Byte} is a {@linkplain Class#isValue value class}. + * The {@code valueOf} behavior is the same as invoking the constructor, + * whether cached or not. + *

+ *
+ *
* * @param b a byte value. * @return a {@code Byte} instance representing {@code b}. @@ -156,7 +169,7 @@ private ByteCache() {} @DeserializeConstructor public static Byte valueOf(byte b) { final int offset = 128; - return ByteCache.cache[(int)b + offset]; + return (!PreviewFeatures.isEnabled()) ? ByteCache.cache[(int)b + offset] : new Byte(b); } /** diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index 493498bad13..7d303c84bf4 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -26,6 +26,7 @@ package java.lang; import jdk.internal.misc.CDS; +import jdk.internal.misc.PreviewFeatures; import jdk.internal.value.DeserializeConstructor; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -9271,15 +9272,26 @@ private CharacterCache(){} /** * Returns a {@code Character} instance representing the specified * {@code char} value. - * If a new {@code Character} instance is not required, this method - * should generally be used in preference to the constructor - * {@link #Character(char)}, as this method is likely to yield - * significantly better space and time performance by caching - * frequently requested values. - * - * This method will always cache values in the range {@code - * '\u005Cu0000'} to {@code '\u005Cu007F'}, inclusive, and may - * cache other values outside of this range. + *
+ *
+ *

+ * - When preview features are NOT enabled, {@code Character} is an identity class. + * If a new {@code Character} instance is not required, this method + * should generally be used in preference to the constructor + * {@link #Character(char)}, as this method is likely to yield + * significantly better space and time performance by caching + * frequently requested values. + * This method will always cache values in the range {@code + * '\u005Cu0000'} to {@code '\u005Cu007F'}, inclusive, and may + * cache other values outside of this range. + *

+ *

+ * - When preview features are enabled, {@code Character} is a {@linkplain Class#isValue value class}. + * The {@code valueOf} behavior is the same as invoking the constructor, + * whether cached or not. + *

+ *
+ *
* * @param c a char value. * @return a {@code Character} instance representing {@code c}. @@ -9288,8 +9300,10 @@ private CharacterCache(){} @IntrinsicCandidate @DeserializeConstructor public static Character valueOf(char c) { - if (c <= 127) { // must cache - return CharacterCache.cache[(int)c]; + if (!PreviewFeatures.isEnabled()) { + if (c <= 127) { // must cache + return CharacterCache.cache[(int) c]; + } } return new Character(c); } diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index d9cba6a7107..828e45d4a44 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -26,6 +26,7 @@ package java.lang; import jdk.internal.misc.CDS; +import jdk.internal.misc.PreviewFeatures; import jdk.internal.misc.VM; import jdk.internal.util.DecimalDigits; import jdk.internal.value.DeserializeConstructor; @@ -996,14 +997,26 @@ private IntegerCache() {} /** * Returns an {@code Integer} instance representing the specified - * {@code int} value. If a new {@code Integer} instance is not - * required, this method should generally be used in preference to - * the constructor {@link #Integer(int)}, as this method is likely - * to yield significantly better space and time performance by - * caching frequently requested values. - * - * This method will always cache values in the range -128 to 127, - * inclusive, and may cache other values outside of this range. + * {@code int} value. + *
+ *
+ *

+ * - When preview features are NOT enabled, {@code Integer} is an identity class. + * If a new {@code Integer} instance is not + * required, this method should generally be used in preference to + * the constructor {@link #Integer(int)}, as this method is likely + * to yield significantly better space and time performance by + * caching frequently requested values. + * This method will always cache values in the range -128 to 127, + * inclusive, and may cache other values outside of this range. + *

+ *

+ * - When preview features are enabled, {@code Integer} is a {@linkplain Class#isValue value class}. + * The {@code valueOf} behavior is the same as invoking the constructor, + * whether cached or not. + *

+ *
+ *
* * @param i an {@code int} value. * @return an {@code Integer} instance representing {@code i}. @@ -1012,8 +1025,10 @@ private IntegerCache() {} @IntrinsicCandidate @DeserializeConstructor public static Integer valueOf(int i) { - if (i >= IntegerCache.low && i <= IntegerCache.high) - return IntegerCache.cache[i + (-IntegerCache.low)]; + if (!PreviewFeatures.isEnabled()) { + if (i >= IntegerCache.low && i <= IntegerCache.high) + return IntegerCache.cache[i + (-IntegerCache.low)]; + } return new Integer(i); } diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 093e8916334..c1dc53cccf4 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -34,6 +34,7 @@ import java.util.Optional; import jdk.internal.misc.CDS; +import jdk.internal.misc.PreviewFeatures; import jdk.internal.value.DeserializeConstructor; import jdk.internal.util.DecimalDigits; import jdk.internal.vm.annotation.ForceInline; @@ -989,14 +990,25 @@ private LongCache() {} /** * Returns a {@code Long} instance representing the specified * {@code long} value. - * If a new {@code Long} instance is not required, this method - * should generally be used in preference to the constructor - * {@link #Long(long)}, as this method is likely to yield - * significantly better space and time performance by caching - * frequently requested values. - * - * This method will always cache values in the range -128 to 127, - * inclusive, and may cache other values outside of this range. + *
+ *
+ *

+ * - When preview features are NOT enabled, {@code Long} is an identity class. + * If a new {@code Long} instance is not required, this method + * should generally be used in preference to the constructor + * {@link #Long(long)}, as this method is likely to yield + * significantly better space and time performance by caching + * frequently requested values. + * This method will always cache values in the range -128 to 127, + * inclusive, and may cache other values outside of this range. + *

+ *

+ * - When preview features are enabled, {@code Long} is a {@linkplain Class#isValue value class}. + * The {@code valueOf} behavior is the same as invoking the constructor, + * whether cached or not. + *

+ *
+ *
* * @param l a long value. * @return a {@code Long} instance representing {@code l}. @@ -1006,8 +1018,10 @@ private LongCache() {} @DeserializeConstructor public static Long valueOf(long l) { final int offset = 128; - if (l >= -128 && l <= 127) { // will cache - return LongCache.cache[(int)l + offset]; + if (!PreviewFeatures.isEnabled()) { + if (l >= -128 && l <= 127) { // will cache + return LongCache.cache[(int) l + offset]; + } } return new Long(l); } diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index 8d3829d3202..24ca60f9fe7 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -26,6 +26,7 @@ package java.lang; import jdk.internal.misc.CDS; +import jdk.internal.misc.PreviewFeatures; import jdk.internal.value.DeserializeConstructor; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -269,14 +270,25 @@ private ShortCache() {} /** * Returns a {@code Short} instance representing the specified * {@code short} value. - * If a new {@code Short} instance is not required, this method - * should generally be used in preference to the constructor - * {@link #Short(short)}, as this method is likely to yield - * significantly better space and time performance by caching - * frequently requested values. - * - * This method will always cache values in the range -128 to 127, - * inclusive, and may cache other values outside of this range. + *
+ *
+ *

+ * - When preview features are NOT enabled, {@code Short} is an identity class. + * If a new {@code Short} instance is not required, this method + * should generally be used in preference to the constructor + * {@link #Short(short)}, as this method is likely to yield + * significantly better space and time performance by caching + * frequently requested values. + * This method will always cache values in the range -128 to 127, + * inclusive, and may cache other values outside of this range. + *

+ *

+ * - When preview features are enabled, {@code Short} is a {@linkplain Class#isValue value class}. + * The {@code valueOf} behavior is the same as invoking the constructor, + * whether cached or not. + *

+ *
+ *
* * @param s a short value. * @return a {@code Short} instance representing {@code s}. @@ -287,8 +299,10 @@ private ShortCache() {} public static Short valueOf(short s) { final int offset = 128; int sAsInt = s; - if (sAsInt >= -128 && sAsInt <= 127) { // must cache - return ShortCache.cache[sAsInt + offset]; + if (!PreviewFeatures.isEnabled()) { + if (sAsInt >= -128 && sAsInt <= 127) { // must cache + return ShortCache.cache[sAsInt + offset]; + } } return new Short(s); } From 10eab8143680d4a1bbee968262019d6e6755abf7 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Mon, 20 Oct 2025 12:57:38 -0400 Subject: [PATCH 2/3] Review suggestions to put constant locals into non-preview block and use the same code pattern for Boolean.valueOf. Update some tests to run in --enable-preview as well as non-preview. --- src/java.base/share/classes/java/lang/Boolean.java | 6 +++++- src/java.base/share/classes/java/lang/Long.java | 2 +- src/java.base/share/classes/java/lang/Short.java | 2 +- .../jtreg/compiler/eliminateAutobox/TestLongBoxing.java | 2 ++ .../cds/appcds/cacheObject/CheckIntegerCacheApp.java | 6 ++++++ test/jdk/java/lang/Integer/ValueOf.java | 1 + 6 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Boolean.java b/src/java.base/share/classes/java/lang/Boolean.java index 9146df083d3..50b4dd05cb7 100644 --- a/src/java.base/share/classes/java/lang/Boolean.java +++ b/src/java.base/share/classes/java/lang/Boolean.java @@ -25,6 +25,7 @@ package java.lang; +import jdk.internal.misc.PreviewFeatures; import jdk.internal.value.DeserializeConstructor; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -182,7 +183,10 @@ public boolean booleanValue() { @IntrinsicCandidate @DeserializeConstructor public static Boolean valueOf(boolean b) { - return (b ? TRUE : FALSE); + if (!PreviewFeatures.isEnabled()) { + return (b ? TRUE : FALSE); + } + return new Boolean(b); } /** diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index c1dc53cccf4..693fd96502d 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -1017,9 +1017,9 @@ private LongCache() {} @IntrinsicCandidate @DeserializeConstructor public static Long valueOf(long l) { - final int offset = 128; if (!PreviewFeatures.isEnabled()) { if (l >= -128 && l <= 127) { // will cache + final int offset = 128; return LongCache.cache[(int) l + offset]; } } diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index 24ca60f9fe7..b4be86872c9 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -297,9 +297,9 @@ private ShortCache() {} @IntrinsicCandidate @DeserializeConstructor public static Short valueOf(short s) { - final int offset = 128; int sAsInt = s; if (!PreviewFeatures.isEnabled()) { + final int offset = 128; if (sAsInt >= -128 && sAsInt <= 127) { // must cache return ShortCache.cache[sAsInt + offset]; } diff --git a/test/hotspot/jtreg/compiler/eliminateAutobox/TestLongBoxing.java b/test/hotspot/jtreg/compiler/eliminateAutobox/TestLongBoxing.java index a3548313f47..906368f86b6 100644 --- a/test/hotspot/jtreg/compiler/eliminateAutobox/TestLongBoxing.java +++ b/test/hotspot/jtreg/compiler/eliminateAutobox/TestLongBoxing.java @@ -28,6 +28,8 @@ * * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox * compiler.eliminateAutobox.TestLongBoxing + * @run main/othervm --enable-preview -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox + * compiler.eliminateAutobox.TestLongBoxing * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox * -XX:CompileCommand=exclude,compiler.eliminateAutobox.TestLongBoxing::dummy * -XX:CompileCommand=exclude,compiler.eliminateAutobox.TestLongBoxing::foo diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java index 256871d817f..1d872ff3d0a 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/CheckIntegerCacheApp.java @@ -27,6 +27,12 @@ // // args[0]: the expected maximum value expected to be archived // + +/* + * test + * @run main CheckIntegerCacheApp + * @run main/othervm --enable-preview CheckIntegerCacheApp + */ public class CheckIntegerCacheApp { public static void main(String[] args) throws Exception { if (args.length != 1) { diff --git a/test/jdk/java/lang/Integer/ValueOf.java b/test/jdk/java/lang/Integer/ValueOf.java index 3f21248baa1..37477f4913f 100644 --- a/test/jdk/java/lang/Integer/ValueOf.java +++ b/test/jdk/java/lang/Integer/ValueOf.java @@ -26,6 +26,7 @@ * @bug 6807702 * @summary Basic test for Integer.valueOf * @run main ValueOf + * @run main/othervm --enable-preview ValueOf * @run main/othervm -esa -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox * -XX:AutoBoxCacheMax=20000 ValueOf */ From 7a94a947a2b2e84c6f0442089fc3466577860ecd Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Fri, 24 Oct 2025 10:47:22 -0400 Subject: [PATCH 3/3] One more assignment into the !Preview block in Short. --- src/java.base/share/classes/java/lang/Short.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index b4be86872c9..be15f4723fb 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -297,9 +297,9 @@ private ShortCache() {} @IntrinsicCandidate @DeserializeConstructor public static Short valueOf(short s) { - int sAsInt = s; if (!PreviewFeatures.isEnabled()) { final int offset = 128; + int sAsInt = s; if (sAsInt >= -128 && sAsInt <= 127) { // must cache return ShortCache.cache[sAsInt + offset]; }