From 5e3f13d739836909f7632eb0e39046edd6c16476 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Sat, 9 Aug 2025 17:31:30 -0700 Subject: [PATCH 1/3] 8364751: ConstantBootstraps.explicitCast violates doc contracts for null-to-int --- .../java/lang/invoke/ConstantBootstraps.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java index b7983d18b2e5c..c377d2ecdba07 100644 --- a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java +++ b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -373,13 +373,14 @@ public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, * is applied to {@code value} as if by calling {@code dstType.cast(value)}. *
  • If {@code dstType} is a primitive type, then, if the runtime type * of {@code value} is a primitive wrapper type (such as {@link Integer}), - * a Java unboxing conversion is applied {@jls 5.1.8} followed by a - * Java casting conversion {@jls 5.5} converting either directly to + * a Java unboxing conversion is applied (JLS {@jls 5.1.8}) followed by a + * Java casting conversion (JLS {@jls 5.5}) converting either directly to * {@code dstType}, or, if {@code dstType} is {@code boolean}, * to {@code int}, which is then converted to either {@code true} * or {@code false} depending on whether the least-significant-bit - * is 1 or 0 respectively. If the runtime type of {@code value} is - * not a primitive wrapper type a {@link ClassCastException} is thrown. + * is 1 or 0 respectively. If {@code value} is null, the zero value for + * the {@code dstType} is returned. Otherwise, a {@link ClassCastException} + * is thrown. * *

    * The result is the same as when using the following code: @@ -397,8 +398,8 @@ public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, * @return the converted value * @throws ClassCastException when {@code dstType} is {@code void}, * when a cast per (1) fails, or when {@code dstType} is a primitive type - * and the runtime type of {@code value} is not a primitive wrapper type - * (such as {@link Integer}) + * and {@code value} is not null and its runtime type is not a primitive + * wrapper type (such as {@link Integer}) * * @since 15 */ From 3f69079bf77cbfbe5655ca4f273796269fd505b2 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Sat, 9 Aug 2025 17:54:32 -0700 Subject: [PATCH 2/3] Update and consolidate tests --- test/jdk/java/lang/constant/ConvertTest.java | 79 ------------------- .../invoke/condy/ConstantBootstrapsTest.java | 46 ++++++++++- 2 files changed, 44 insertions(+), 81 deletions(-) delete mode 100644 test/jdk/java/lang/constant/ConvertTest.java diff --git a/test/jdk/java/lang/constant/ConvertTest.java b/test/jdk/java/lang/constant/ConvertTest.java deleted file mode 100644 index d7018df635291..0000000000000 --- a/test/jdk/java/lang/constant/ConvertTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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. - * - * 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 - * @run testng ConvertTest - */ - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import java.lang.invoke.ConstantBootstraps; -import java.math.BigInteger; - -import static org.testng.Assert.assertEquals; - -public class ConvertTest { - - @DataProvider - public static Object[][] cceInputs() { - return new Object[][]{ - { void.class, null }, - { Integer.class, "a" }, - { int.class, BigInteger.ZERO }, - }; - } - - @Test(dataProvider = "cceInputs", expectedExceptions = ClassCastException.class) - public void testBadConversion(Class dstType, Object value) { - ConstantBootstraps.explicitCast(null, null, dstType, value); - } - - @DataProvider - public static Object[][] goodInputs() { - Object o = new Object(); - return new Object[][]{ - { Object.class, null, null }, - { Object.class, o, o }, - { String.class, "abc", "abc" }, - { short.class, 10, (short) 10 }, - { int.class, (short) 10, 10 }, - { boolean.class, 1, true }, - { boolean.class, 2, false }, - { int.class, true, 1 }, - { int.class, false, 0 }, - { int.class, 10, 10 }, - { Integer.class, 10, 10 }, - { Object.class, 10, 10 }, - { Number.class, 10, 10 }, - }; - } - - @Test(dataProvider = "goodInputs") - public void testSuccess(Class dstType, Object value, Object expected) { - Object actual = ConstantBootstraps.explicitCast(null, null, dstType, value); - assertEquals(actual, expected); - } - -} diff --git a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java index 640affeec5c3c..829f26704f943 100644 --- a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java +++ b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8186046 8195694 + * @bug 8186046 8195694 8241100 8364751 * @summary Test dynamic constant bootstraps * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper @@ -31,6 +31,7 @@ * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 ConstantBootstrapsTest */ +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; @@ -241,4 +242,45 @@ public void testVarHandleArray() throws Throwable { assertEquals(vhandle.varType(), String.class); assertEquals(vhandle.coordinateTypes(), List.of(String[].class, int.class)); } + + @DataProvider + public static Object[][] cceCasts() { + return new Object[][]{ + { void.class, null }, + { Integer.class, "a" }, + { int.class, BigInteger.ZERO }, + }; + } + + @Test(dataProvider = "cceCasts", expectedExceptions = ClassCastException.class) + public void testBadCasts(Class dstType, Object value) { + ConstantBootstraps.explicitCast(null, null, dstType, value); + } + + @DataProvider + public static Object[][] validCasts() { + Object o = new Object(); + return new Object[][]{ + { Object.class, null, null }, + { Object.class, o, o }, + { String.class, "abc", "abc" }, + { short.class, 10, (short) 10 }, + { int.class, (short) 10, 10 }, + { boolean.class, 1, true }, + { boolean.class, 2, false }, + { int.class, true, 1 }, + { int.class, false, 0 }, + { int.class, 10, 10 }, + { Integer.class, 10, 10 }, + { Object.class, 10, 10 }, + { Number.class, 10, 10 }, + { char.class, null, (char) 0 } + }; + } + + @Test(dataProvider = "validCasts") + public void testSuccessfulCasts(Class dstType, Object value, Object expected) { + Object actual = ConstantBootstraps.explicitCast(null, null, dstType, value); + assertEquals(actual, expected); + } } From c0b8e5c0ec49f82ae12193335136adbbcb49ec42 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 27 Aug 2025 12:05:09 -0500 Subject: [PATCH 3/3] Update wording and rendering again --- .../java/lang/invoke/ConstantBootstraps.java | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java index c377d2ecdba07..a62d8e720efd0 100644 --- a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java +++ b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java @@ -369,18 +369,32 @@ public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, *

    * Otherwise one of the following conversions is applied to {@code value}: *

      - *
    1. If {@code dstType} is a reference type, a reference cast - * is applied to {@code value} as if by calling {@code dstType.cast(value)}. - *
    2. If {@code dstType} is a primitive type, then, if the runtime type - * of {@code value} is a primitive wrapper type (such as {@link Integer}), - * a Java unboxing conversion is applied (JLS {@jls 5.1.8}) followed by a - * Java casting conversion (JLS {@jls 5.5}) converting either directly to - * {@code dstType}, or, if {@code dstType} is {@code boolean}, - * to {@code int}, which is then converted to either {@code true} - * or {@code false} depending on whether the least-significant-bit - * is 1 or 0 respectively. If {@code value} is null, the zero value for - * the {@code dstType} is returned. Otherwise, a {@link ClassCastException} - * is thrown. + *
    3. If {@code dstType} is a reference type, a reference cast is applied + * to {@code value} as if by calling {@link Class#cast(Object) + * dstType.cast(value)}. + *
    4. Otherwise, {@code dstType} is a primitive type: + *
        + *
      1. If {@code value} is null, the default value (JVMS {@jvms 2.3}) + * of {@code dstType} is returned. + *
      2. If the runtime type of {@code value} is a primitive wrapper type + * (such as {@link Integer}), a Java unboxing conversion is applied + * (JLS {@jls 5.1.8}). + *
          + *
        • If the runtime type is {@link Boolean}, the unboxing result + * is then converted to {@code int}, where {@code true} becomes + * {@code 1} and {@code false} becomes {@code 0}. + *
        + * Followed by a Java casting conversion (JLS {@jls 5.5}): + *
          + *
        • If {@code dstType} is not {@code boolean}, the cast converts + * directly to {@code dstType}. + *
        • If {@code dstType} is {@code boolean}, the cast converts to + * {@code int}, and the resulting {@code boolean} is produced + * by testing whether the least significant bit of the cast + * {@code int} is 1. + *
        + *
      3. Otherwise, a {@link ClassCastException} is thrown. + *
      *
    *

    * The result is the same as when using the following code: @@ -394,13 +408,10 @@ public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, * @param lookup unused * @param name unused * @param dstType the destination type of the conversion - * @param value the value to be converted + * @param value the value to be converted, may be null * @return the converted value - * @throws ClassCastException when {@code dstType} is {@code void}, - * when a cast per (1) fails, or when {@code dstType} is a primitive type - * and {@code value} is not null and its runtime type is not a primitive - * wrapper type (such as {@link Integer}) - * + * @throws ClassCastException when {@code dstType} is {@code void}, when + * a cast per (1) fails, or according to (2).(3) * @since 15 */ public static Object explicitCast(MethodHandles.Lookup lookup, String name, Class dstType, Object value)