undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
166
test/jdk/java/lang/runtime/CarriersTest.java
Normal file
166
test/jdk/java/lang/runtime/CarriersTest.java
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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 features provided by the Carriers class.
|
||||
* @modules java.base/java.lang.runtime
|
||||
* @enablePreview true
|
||||
* @compile --patch-module java.base=${test.src} CarriersTest.java
|
||||
* @run main/othervm --patch-module java.base=${test.class.path} java.lang.runtime.CarriersTest
|
||||
*/
|
||||
|
||||
package java.lang.runtime;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class CarriersTest {
|
||||
public static void main(String[] args) throws Throwable {
|
||||
primitivesTest();
|
||||
primitivesTestLarge();
|
||||
limitsTest();
|
||||
}
|
||||
|
||||
static void assertTrue(boolean test, String message) {
|
||||
if (!test) {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final int MAX_COMPONENTS = 254;
|
||||
|
||||
static void primitivesTest() throws Throwable {
|
||||
MethodType methodType =
|
||||
MethodType.methodType(Object.class, byte.class, short.class,
|
||||
char.class, int.class, long.class,
|
||||
float.class, double.class,
|
||||
boolean.class, String.class);
|
||||
MethodHandle constructor = Carriers.initializingConstructor(methodType);
|
||||
Object object = (Object)constructor.invokeExact((byte)0xFF, (short)0xFFFF,
|
||||
'C', 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFL,
|
||||
1.0f / 3.0f, 1.0 / 3.0,
|
||||
true, "abcde");
|
||||
List<MethodHandle> components = Carriers.components(methodType);
|
||||
assertTrue((byte)components.get(0).invokeExact(object) == (byte)0xFF,
|
||||
"primitive byte test failure");
|
||||
assertTrue((short)components.get(1).invokeExact(object) == (short)0xFFFF,
|
||||
"primitive short test failure");
|
||||
assertTrue((char)components.get(2).invokeExact(object) == 'C',
|
||||
"primitive char test failure");
|
||||
assertTrue((int)components.get(3).invokeExact(object) == 0xFFFFFFFF,
|
||||
"primitive int test failure");
|
||||
assertTrue((long)components.get(4).invokeExact(object) == 0xFFFFFFFFFFFFFFFFL,
|
||||
"primitive long test failure");
|
||||
assertTrue((float)components.get(5).invokeExact(object) == 1.0f / 3.0f,
|
||||
"primitive float test failure");
|
||||
assertTrue((double)components.get(6).invokeExact(object) == 1.0 / 3.0,
|
||||
"primitive double test failure");
|
||||
assertTrue((boolean)components.get(7).invokeExact(object),
|
||||
"primitive boolean test failure");
|
||||
assertTrue("abcde".equals((String)components.get(8).invokeExact(object)),
|
||||
"primitive String test failure");
|
||||
}
|
||||
|
||||
static void primitivesTestLarge() throws Throwable {
|
||||
MethodType methodType =
|
||||
MethodType.methodType(Object.class, byte.class, short.class,
|
||||
char.class, int.class, long.class,
|
||||
float.class, double.class,
|
||||
boolean.class, String.class,
|
||||
Object.class, Object.class,Object.class,Object.class,
|
||||
Object.class, Object.class,Object.class,Object.class,
|
||||
Object.class, Object.class,Object.class,Object.class,
|
||||
Object.class, Object.class,Object.class,Object.class,
|
||||
Object.class, Object.class,Object.class,Object.class,
|
||||
Object.class, Object.class,Object.class,Object.class,
|
||||
Object.class, Object.class,Object.class,Object.class
|
||||
);
|
||||
MethodHandle constructor = Carriers.initializingConstructor(methodType);
|
||||
Object object = (Object)constructor.invokeExact((byte)0xFF, (short)0xFFFF,
|
||||
'C', 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFL,
|
||||
1.0f / 3.0f, 1.0 / 3.0,
|
||||
true, "abcde",
|
||||
(Object)null, (Object)null, (Object)null, (Object)null,
|
||||
(Object)null, (Object)null, (Object)null, (Object)null,
|
||||
(Object)null, (Object)null, (Object)null, (Object)null,
|
||||
(Object)null, (Object)null, (Object)null, (Object)null,
|
||||
(Object)null, (Object)null, (Object)null, (Object)null,
|
||||
(Object)null, (Object)null, (Object)null, (Object)null,
|
||||
(Object)null, (Object)null, (Object)null, (Object)null
|
||||
);
|
||||
List<MethodHandle> components = Carriers.components(methodType);
|
||||
assertTrue((byte)components.get(0).invokeExact(object) == (byte)0xFF,
|
||||
"large primitive byte test failure");
|
||||
assertTrue((short)components.get(1).invokeExact(object) == (short)0xFFFF,
|
||||
"large primitive short test failure");
|
||||
assertTrue((char)components.get(2).invokeExact(object) == 'C',
|
||||
"large primitive char test failure");
|
||||
assertTrue((int)components.get(3).invokeExact(object) == 0xFFFFFFFF,
|
||||
"large primitive int test failure");
|
||||
assertTrue((long)components.get(4).invokeExact(object) == 0xFFFFFFFFFFFFFFFFL,
|
||||
"large primitive long test failure");
|
||||
assertTrue((float)components.get(5).invokeExact(object) == 1.0f / 3.0f,
|
||||
"large primitive float test failure");
|
||||
assertTrue((double)components.get(6).invokeExact(object) == 1.0 / 3.0,
|
||||
"large primitive double test failure");
|
||||
assertTrue((boolean)components.get(7).invokeExact(object),
|
||||
"large primitive boolean test failure");
|
||||
assertTrue("abcde".equals((String)components.get(8).invokeExact(object)),
|
||||
"large primitive String test failure");
|
||||
}
|
||||
|
||||
static void limitsTest() {
|
||||
boolean passed;
|
||||
|
||||
passed = false;
|
||||
try {
|
||||
Class<?>[] ptypes = new Class<?>[MAX_COMPONENTS + 1];
|
||||
Arrays.fill(ptypes, Object.class);
|
||||
MethodType methodType = MethodType.methodType(Object.class, ptypes);
|
||||
MethodHandle constructor = Carriers.constructor(methodType);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
passed = true;
|
||||
}
|
||||
|
||||
if (!passed) {
|
||||
throw new RuntimeException("failed to report too many components ");
|
||||
}
|
||||
|
||||
passed = false;
|
||||
try {
|
||||
Class<?>[] ptypes = new Class<?>[MAX_COMPONENTS / 2 + 1];
|
||||
Arrays.fill(ptypes, long.class);
|
||||
MethodType methodType = MethodType.methodType(Object.class, ptypes);
|
||||
MethodHandle constructor = Carriers.constructor(methodType);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
passed = true;
|
||||
}
|
||||
|
||||
if (!passed) {
|
||||
throw new RuntimeException("failed to report too many components ");
|
||||
}
|
||||
}
|
||||
}
|
||||
214
test/jdk/java/lang/runtime/ExactnessConversionsSupportTest.java
Normal file
214
test/jdk/java/lang/runtime/ExactnessConversionsSupportTest.java
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.lang.runtime.ExactConversionsSupport;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8304487
|
||||
* @summary Verify boundary and special cases of exact conversion predicates
|
||||
* @compile ExactnessConversionsSupportTest.java
|
||||
* @run junit/othervm ExactnessConversionsSupportTest
|
||||
*/
|
||||
public class ExactnessConversionsSupportTest {
|
||||
|
||||
@Test
|
||||
public void testByte() {
|
||||
assertEquals(true, ExactConversionsSupport.isIntToByteExact((byte) (Byte.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToByteExact((byte) (0)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToByteExact((byte) (Byte.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToByteExact((short) (Short.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToByteExact((short) (0)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToByteExact((short) (Short.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToByteExact((char) (Character.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToByteExact((char) (Character.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToByteExact(Integer.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToByteExact(0));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToByteExact(Integer.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isLongToByteExact(Long.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isLongToByteExact(0L));
|
||||
assertEquals(false, ExactConversionsSupport.isLongToByteExact(Long.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToByteExact(Float.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToByteExact((float) 0));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToByteExact(Float.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToByteExact(Float.NaN));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToByteExact(Float.POSITIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToByteExact(Float.NEGATIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToByteExact(-0.0f));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToByteExact(+0.0f));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToByteExact(Double.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToByteExact(0d));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToByteExact(Double.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToByteExact(Double.NaN));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToByteExact(Double.POSITIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToByteExact(Double.NEGATIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToByteExact(-0.0d));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToByteExact(+0.0d));
|
||||
}
|
||||
@Test
|
||||
public void testShort() {
|
||||
assertEquals(true, ExactConversionsSupport.isIntToShortExact((byte) (Byte.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToShortExact((byte) (0)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToShortExact((byte) (Byte.MIN_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToShortExact((short) (Short.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToShortExact((short) (0)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToShortExact((short) (Short.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToShortExact((char) (Character.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToShortExact((char) (Character.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToShortExact((Integer.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToShortExact((0)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToShortExact((Integer.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isLongToShortExact(Long.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isLongToShortExact(0L));
|
||||
assertEquals(false, ExactConversionsSupport.isLongToShortExact(Long.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToShortExact(Float.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToShortExact(0f));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToShortExact(Float.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToShortExact(Float.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToShortExact(Float.NaN));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToShortExact(Float.POSITIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToShortExact(Float.NEGATIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToShortExact(-0.0f));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToShortExact(+0.0f));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToShortExact(Double.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToShortExact((double) 0));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToShortExact(Double.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToShortExact(Double.NaN));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToShortExact(Double.POSITIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToShortExact(Double.NEGATIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToShortExact(-0.0d));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToShortExact(+0.0d));
|
||||
}
|
||||
@Test
|
||||
public void testChar() {
|
||||
assertEquals(true, ExactConversionsSupport.isIntToCharExact((byte) (Byte.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToCharExact((byte) (0)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToCharExact((byte) (Byte.MIN_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToCharExact((short) (Short.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToCharExact((short) (0)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToCharExact((short) (Short.MIN_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToCharExact((char) (Character.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToCharExact((char) (Character.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToCharExact (Integer.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToCharExact(0));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToCharExact(Integer.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isLongToCharExact(Long.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isLongToCharExact(0l));
|
||||
assertEquals(false, ExactConversionsSupport.isLongToCharExact(Long.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToCharExact(Float.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToCharExact((float) 0));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToCharExact(Float.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToCharExact(Float.NaN));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToCharExact(Float.POSITIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToCharExact(Float.NEGATIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToCharExact(-0.0f));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToCharExact(+0.0f));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToCharExact(Double.MAX_VALUE));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToCharExact((double) 0));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToCharExact(Double.MIN_VALUE));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToCharExact(Double.NaN));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToCharExact(Double.POSITIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToCharExact(Double.NEGATIVE_INFINITY));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToCharExact(-0.0d));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToCharExact(+0.0d));
|
||||
}
|
||||
@Test
|
||||
public void testInt() {
|
||||
assertEquals(false, ExactConversionsSupport.isLongToIntExact((Long.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isLongToIntExact((0L)));
|
||||
assertEquals(false, ExactConversionsSupport.isLongToIntExact((Long.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToIntExact((Float.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToIntExact(((float) 0)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToIntExact((Float.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToIntExact((Float.NaN)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToIntExact((Float.POSITIVE_INFINITY)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToIntExact((Float.NEGATIVE_INFINITY)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToIntExact((-0.0f)));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToIntExact((+0.0f)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToIntExact((Double.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToIntExact(((double) 0)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToIntExact((Double.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToIntExact((Double.NaN)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToIntExact((Double.POSITIVE_INFINITY)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToIntExact((Double.NEGATIVE_INFINITY)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToIntExact((-0.0d)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToIntExact((+0.0d)));
|
||||
}
|
||||
@Test
|
||||
public void testLong() {
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToLongExact((Float.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToLongExact(((float) 0)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToLongExact((Float.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToLongExact((Float.NaN)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToLongExact((Float.POSITIVE_INFINITY)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToLongExact((Float.NEGATIVE_INFINITY)));
|
||||
assertEquals(false, ExactConversionsSupport.isFloatToLongExact((-0.0f)));
|
||||
assertEquals(true, ExactConversionsSupport.isFloatToLongExact((+0.0f)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToLongExact((Double.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToLongExact(((double) 0)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToLongExact((Double.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToLongExact((Double.NaN)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToLongExact((Double.POSITIVE_INFINITY)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToLongExact((Double.NEGATIVE_INFINITY)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToLongExact((-0.0d)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToLongExact((+0.0d)));
|
||||
}
|
||||
@Test
|
||||
public void testFloat() {
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((byte) (Byte.MAX_VALUE))));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((byte) (0))));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((byte) (Byte.MIN_VALUE))));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((short) (Short.MAX_VALUE))));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((short) (0))));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((short) (Short.MIN_VALUE))));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((char) (Character.MAX_VALUE))));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact(((char) (Character.MIN_VALUE))));
|
||||
assertEquals(false, ExactConversionsSupport.isIntToFloatExact( (Integer.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact((0)));
|
||||
assertEquals(true, ExactConversionsSupport.isIntToFloatExact((Integer.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isLongToFloatExact((Long.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isLongToFloatExact((0l)));
|
||||
assertEquals(true, ExactConversionsSupport.isLongToFloatExact((Long.MIN_VALUE)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToFloatExact((Double.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToFloatExact(((double) 0)));
|
||||
assertEquals(false, ExactConversionsSupport.isDoubleToFloatExact((Double.MIN_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToFloatExact((Double.NaN)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToFloatExact((Double.POSITIVE_INFINITY)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToFloatExact((Double.NEGATIVE_INFINITY)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToFloatExact((-0.0d)));
|
||||
assertEquals(true, ExactConversionsSupport.isDoubleToFloatExact((+0.0d)));
|
||||
}
|
||||
@Test
|
||||
public void testDouble() {
|
||||
assertEquals(false, ExactConversionsSupport.isLongToDoubleExact((Long.MAX_VALUE)));
|
||||
assertEquals(true, ExactConversionsSupport.isLongToDoubleExact((0L)));
|
||||
assertEquals(true, ExactConversionsSupport.isLongToDoubleExact((Long.MIN_VALUE)));
|
||||
}
|
||||
|
||||
static void assertEquals(boolean expected, boolean actual) {
|
||||
if (expected != actual) {
|
||||
throw new AssertionError("Expected: " + expected + ", actual: " + actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
218
test/jdk/java/lang/runtime/ObjectMethodsTest.java
Normal file
218
test/jdk/java/lang/runtime/ObjectMethodsTest.java
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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 8246774
|
||||
* @summary Basic tests for ObjectMethods
|
||||
* @run junit ObjectMethodsTest
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.runtime.ObjectMethods;
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ObjectMethodsTest {
|
||||
|
||||
public static class C {
|
||||
static final MethodType EQUALS_DESC = methodType(boolean.class, C.class, Object.class);
|
||||
static final MethodType HASHCODE_DESC = methodType(int.class, C.class);
|
||||
static final MethodType TO_STRING_DESC = methodType(String.class, C.class);
|
||||
|
||||
static final MethodHandle[] ACCESSORS = accessors();
|
||||
static final String NAME_LIST = "x;y";
|
||||
private static MethodHandle[] accessors() {
|
||||
try {
|
||||
return new MethodHandle[]{
|
||||
MethodHandles.lookup().findGetter(C.class, "x", int.class),
|
||||
MethodHandles.lookup().findGetter(C.class, "y", int.class),
|
||||
};
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final int x;
|
||||
private final int y;
|
||||
C (int x, int y) { this.x = x; this.y = y; }
|
||||
public int x() { return x; }
|
||||
public int y() { return y; }
|
||||
}
|
||||
|
||||
static class Empty {
|
||||
static final MethodType EQUALS_DESC = methodType(boolean.class, Empty.class, Object.class);
|
||||
static final MethodType HASHCODE_DESC = methodType(int.class, Empty.class);
|
||||
static final MethodType TO_STRING_DESC = methodType(String.class, Empty.class);
|
||||
static final MethodHandle[] ACCESSORS = new MethodHandle[] { };
|
||||
static final String NAME_LIST = "";
|
||||
Empty () { }
|
||||
}
|
||||
|
||||
static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
||||
|
||||
@Test
|
||||
public void testEqualsC() throws Throwable {
|
||||
CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "equals", C.EQUALS_DESC, C.class, C.NAME_LIST, C.ACCESSORS);
|
||||
MethodHandle handle = cs.dynamicInvoker();
|
||||
C c = new C(5, 5);
|
||||
assertTrue((boolean)handle.invokeExact(c, (Object)c));
|
||||
assertTrue((boolean)handle.invokeExact(c, (Object)new C(5, 5)));
|
||||
assertFalse((boolean)handle.invokeExact(c, (Object)new C(5, 4)));
|
||||
assertFalse((boolean)handle.invokeExact(c, (Object)new C(4, 5)));
|
||||
assertFalse((boolean)handle.invokeExact(c, (Object)null));
|
||||
assertFalse((boolean)handle.invokeExact(c, new Object()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsEmpty() throws Throwable {
|
||||
CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "equals", Empty.EQUALS_DESC, Empty.class, Empty.NAME_LIST, Empty.ACCESSORS);
|
||||
MethodHandle handle = cs.dynamicInvoker();
|
||||
Empty e = new Empty();
|
||||
assertTrue((boolean)handle.invokeExact(e, (Object)e));
|
||||
assertTrue((boolean)handle.invokeExact(e, (Object)new Empty()));
|
||||
assertFalse((boolean)handle.invokeExact(e, (Object)null));
|
||||
assertFalse((boolean)handle.invokeExact(e, new Object()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashCodeC() throws Throwable {
|
||||
CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "hashCode", C.HASHCODE_DESC, C.class, "x;y", C.ACCESSORS);
|
||||
MethodHandle handle = cs.dynamicInvoker();
|
||||
C c = new C(6, 7);
|
||||
int hc = (int)handle.invokeExact(c);
|
||||
assertEquals(hashCombiner(c.x(), c.y()), hc);
|
||||
|
||||
assertEquals(hashCombiner(100, 1), (int)handle.invokeExact(new C(100, 1)));
|
||||
assertEquals(hashCombiner(0, 0), (int)handle.invokeExact(new C(0, 0)));
|
||||
assertEquals(hashCombiner(-1, 100), (int)handle.invokeExact(new C(-1, 100)));
|
||||
assertEquals(hashCombiner(100, 1), (int)handle.invokeExact(new C(100, 1)));
|
||||
assertEquals(hashCombiner(100, -1), (int)handle.invokeExact(new C(100, -1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashCodeEmpty() throws Throwable {
|
||||
CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "hashCode", Empty.HASHCODE_DESC, Empty.class, "", Empty.ACCESSORS);
|
||||
MethodHandle handle = cs.dynamicInvoker();
|
||||
Empty e = new Empty();
|
||||
assertEquals(0, (int)handle.invokeExact(e));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToStringC() throws Throwable {
|
||||
CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class, C.NAME_LIST, C.ACCESSORS);
|
||||
MethodHandle handle = cs.dynamicInvoker();
|
||||
assertEquals("C[x=8, y=9]", (String)handle.invokeExact(new C(8, 9)) );
|
||||
assertEquals("C[x=10, y=11]", (String)handle.invokeExact(new C(10, 11)) );
|
||||
assertEquals("C[x=100, y=-9]", (String)handle.invokeExact(new C(100, -9)));
|
||||
assertEquals("C[x=0, y=0]", (String)handle.invokeExact(new C(0, 0)) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToStringEmpty() throws Throwable {
|
||||
CallSite cs = (CallSite)ObjectMethods.bootstrap(LOOKUP, "toString", Empty.TO_STRING_DESC, Empty.class, Empty.NAME_LIST, Empty.ACCESSORS);
|
||||
MethodHandle handle = cs.dynamicInvoker();
|
||||
assertEquals("Empty[]", (String)handle.invokeExact(new Empty()));
|
||||
}
|
||||
|
||||
private static final Class<NullPointerException> NPE = NullPointerException.class;
|
||||
private static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
|
||||
|
||||
@Test
|
||||
public void exceptions() {
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "badName", C.EQUALS_DESC, C.class, C.NAME_LIST, C.ACCESSORS));
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class, "x;y;z", C.ACCESSORS));
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, C.class, "x;y", new MethodHandle[]{}));
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.TO_STRING_DESC, this.getClass(), "x;y", C.ACCESSORS));
|
||||
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "toString", C.EQUALS_DESC, C.class, "x;y", C.ACCESSORS));
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "hashCode", C.TO_STRING_DESC, C.class, "x;y", C.ACCESSORS));
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, "equals", C.HASHCODE_DESC, C.class, "x;y", C.ACCESSORS));
|
||||
}
|
||||
|
||||
record NamePlusType(String name, MethodType type) {}
|
||||
|
||||
static List<NamePlusType> namePlusTypeList() {
|
||||
return List.of(
|
||||
new NamePlusType("toString", C.TO_STRING_DESC),
|
||||
new NamePlusType("equals", C.EQUALS_DESC),
|
||||
new NamePlusType("hashCode", C.HASHCODE_DESC)
|
||||
);
|
||||
}
|
||||
|
||||
@MethodSource("namePlusTypeList")
|
||||
@ParameterizedTest
|
||||
void commonExceptions(NamePlusType npt) {
|
||||
String name = npt.name();
|
||||
MethodType type = npt.type();
|
||||
|
||||
// Null checks
|
||||
assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, name, type, C.class, "x;y", null));
|
||||
assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, name, type, C.class, "x;y", new MethodHandle[]{null}));
|
||||
assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, name, type, C.class, null, C.ACCESSORS));
|
||||
assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, name, type, null, "x;y", C.ACCESSORS));
|
||||
assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, name, null, C.class, "x;y", C.ACCESSORS));
|
||||
assertThrows(NPE, () -> ObjectMethods.bootstrap(LOOKUP, null, type, C.class, "x;y", C.ACCESSORS));
|
||||
assertThrows(NPE, () -> ObjectMethods.bootstrap(null, name, type, C.class, "x;y", C.ACCESSORS));
|
||||
|
||||
// Bad indy call receiver type - change C to this test class
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, name, type.changeParameterType(0, this.getClass()), C.class, "x;y", C.ACCESSORS));
|
||||
|
||||
// Bad getter types
|
||||
var wrongReceiverGetter = assertDoesNotThrow(() -> MethodHandles.lookup().findGetter(this.getClass(), "y", int.class));
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, name, type, C.class, "x;y",
|
||||
new MethodHandle[]{
|
||||
C.ACCESSORS[0],
|
||||
wrongReceiverGetter,
|
||||
}));
|
||||
var extraArgGetter = MethodHandles.dropArguments(C.ACCESSORS[1], 1, int.class);
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, name, type, C.class, "x;y",
|
||||
new MethodHandle[]{
|
||||
C.ACCESSORS[0],
|
||||
extraArgGetter,
|
||||
}));
|
||||
var voidReturnGetter = MethodHandles.empty(MethodType.methodType(void.class, C.class));
|
||||
assertThrows(IAE, () -> ObjectMethods.bootstrap(LOOKUP, name, type, C.class, "x;y",
|
||||
new MethodHandle[]{
|
||||
C.ACCESSORS[0],
|
||||
voidReturnGetter,
|
||||
}));
|
||||
}
|
||||
|
||||
// same field name and type as C::y, for wrongReceiverGetter
|
||||
private int y;
|
||||
|
||||
// Based on the ObjectMethods internal implementation
|
||||
private static int hashCombiner(int x, int y) {
|
||||
return x*31 + y;
|
||||
}
|
||||
}
|
||||
422
test/jdk/java/lang/runtime/SwitchBootstrapsTest.java
Normal file
422
test/jdk/java/lang/runtime/SwitchBootstrapsTest.java
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.io.Serializable;
|
||||
import java.lang.Enum.EnumDesc;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
import java.lang.runtime.SwitchBootstraps;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.lang.classfile.ClassFile;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8318144
|
||||
* @enablePreview
|
||||
* @compile SwitchBootstrapsTest.java
|
||||
* @run junit/othervm SwitchBootstrapsTest
|
||||
*/
|
||||
public class SwitchBootstrapsTest {
|
||||
|
||||
public static final MethodHandle BSM_TYPE_SWITCH;
|
||||
public static final MethodHandle BSM_ENUM_SWITCH;
|
||||
|
||||
static {
|
||||
try {
|
||||
BSM_TYPE_SWITCH = MethodHandles.lookup().findStatic(SwitchBootstraps.class, "typeSwitch",
|
||||
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class));
|
||||
BSM_ENUM_SWITCH = MethodHandles.lookup().findStatic(SwitchBootstraps.class, "enumSwitch",
|
||||
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class));
|
||||
}
|
||||
catch (ReflectiveOperationException e) {
|
||||
throw new AssertionError("Should not happen", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void testType(Object target, int start, int result, Object... labels) throws Throwable {
|
||||
MethodType switchType = MethodType.methodType(int.class, Object.class, int.class);
|
||||
MethodHandle indy = ((CallSite) BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels)).dynamicInvoker();
|
||||
assertEquals(result, (int) indy.invoke(target, start));
|
||||
assertEquals(-1, (int) indy.invoke(null, start));
|
||||
}
|
||||
|
||||
private void testPrimitiveType(Object target, Class<?> targetType, int start, int result, Object... labels) throws Throwable {
|
||||
MethodType switchType = MethodType.methodType(int.class, targetType, int.class);
|
||||
MethodHandle indy = ((CallSite) BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels)).dynamicInvoker();
|
||||
assertEquals(result, (int) indy.invoke(target, start));
|
||||
}
|
||||
|
||||
private void testEnum(Enum<?> target, int start, int result, Object... labels) throws Throwable {
|
||||
testEnum(target.getClass(), target, start, result, labels);
|
||||
}
|
||||
|
||||
private void testEnum(Class<?> targetClass, Enum<?> target, int start, int result, Object... labels) throws Throwable {
|
||||
MethodType switchType = MethodType.methodType(int.class, targetClass, int.class);
|
||||
MethodHandle indy = ((CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels)).dynamicInvoker();
|
||||
assertEquals(result, (int) indy.invoke(target, start));
|
||||
assertEquals(-1, (int) indy.invoke(null, start));
|
||||
}
|
||||
|
||||
public enum E1 {
|
||||
A,
|
||||
B;
|
||||
}
|
||||
|
||||
public enum E2 {
|
||||
C;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypes() throws Throwable {
|
||||
testType("", 0, 0, String.class, Object.class);
|
||||
testType("", 0, 0, Object.class);
|
||||
testType("", 0, 1, Integer.class);
|
||||
testType("", 0, 1, Integer.class, Serializable.class);
|
||||
testType(E1.A, 0, 0, E1.class, Object.class);
|
||||
testType(E2.C, 0, 1, E1.class, Object.class);
|
||||
testType(new Serializable() { }, 0, 1, Comparable.class, Serializable.class);
|
||||
testType("", 0, 0, "", String.class);
|
||||
testType("", 1, 1, "", String.class);
|
||||
testType("a", 0, 1, "", String.class);
|
||||
testType(1, 0, 0, 1, Integer.class);
|
||||
testType(2, 0, 1, 1, Integer.class);
|
||||
testType(Byte.valueOf((byte) 1), 0, 0, 1, Integer.class);
|
||||
testType(Short.valueOf((short) 1), 0, 0, 1, Integer.class);
|
||||
testType(Character.valueOf((char) 1), 0, 0, 1, Integer.class);
|
||||
testType(Integer.valueOf((int) 1), 0, 0, 1, Integer.class);
|
||||
testType(1, 0, 1, 1.0d, Integer.class);
|
||||
testType(1, 0, 1, 1.0f, Integer.class);
|
||||
testType(1, 0, 1, true, Integer.class);
|
||||
testType("", 0, 0, String.class, String.class, String.class, String.class, String.class);
|
||||
testType("", 1, 1, String.class, String.class, String.class, String.class, String.class);
|
||||
testType("", 2, 2, String.class, String.class, String.class, String.class, String.class);
|
||||
testType("", 3, 3, String.class, String.class, String.class, String.class, String.class);
|
||||
testType("", 3, 3, String.class, String.class, String.class, String.class, String.class);
|
||||
testType("", 4, 4, String.class, String.class, String.class, String.class, String.class);
|
||||
testType("", 0, 0);
|
||||
testType(new Object() {
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Long i) {
|
||||
return i == 1;
|
||||
}
|
||||
return super.equals(obj);
|
||||
}
|
||||
}, 0, 1, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrimitiveTypes() throws Throwable {
|
||||
testPrimitiveType((short) 1, short.class, 0, 1, String.class);
|
||||
testPrimitiveType((byte) 1, byte.class,0, 1, String.class, byte.class);
|
||||
testPrimitiveType(true, boolean.class,0, 1, false, boolean.class);
|
||||
testPrimitiveType(1, int.class,0, 1, String.class);
|
||||
testPrimitiveType(1, int.class,0, 1, true);
|
||||
testPrimitiveType(true, boolean.class,0, 1, false);
|
||||
testPrimitiveType((byte) 1, byte.class,0, 1, boolean.class, byte.class);
|
||||
testPrimitiveType((byte) 1, byte.class,0, 1, Boolean.class, byte.class);
|
||||
testPrimitiveType(true, boolean.class,0, 1, String.class, boolean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnums() throws Throwable {
|
||||
testEnum(E1.A, 0, 2, "B", "C", "A", E1.class);
|
||||
testEnum(E1.B, 0, 0, "B", "C", "A", E1.class);
|
||||
testEnum(E1.B, 1, 3, "B", "C", "A", E1.class);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
testEnum(E1.B, 0, -1, E2.class)
|
||||
);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
testEnum(E1.B, 0, -1, String.class)
|
||||
);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
testEnum(E1.B, 0, -1, 10)
|
||||
);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
testEnum(E1.B, 0, -1, new Object())
|
||||
);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
testEnum(E1.B, 0, -1, new Object[] { null })
|
||||
);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
testEnum(E1.B, 0, -1, "")
|
||||
);
|
||||
assertThrows(NullPointerException.class, () ->
|
||||
testEnum(E1.B, 0, -1, (Object[]) null)
|
||||
);
|
||||
testEnum(E1.B, 0, 0, "B", "A");
|
||||
testEnum(E1.A, 0, 1, "B", "A");
|
||||
testEnum(E1.A, 0, 0, "A", "A", "B");
|
||||
testEnum(E1.A, 1, 1, "A", "A", "B");
|
||||
testEnum(E1.A, 2, 3, "A", "A", "B");
|
||||
testEnum(E1.A, 0, 0);
|
||||
testEnum(E1.B, 0, 2, "A", "OLD_REMOVED_CONSTANT", "B", E1.class);
|
||||
testEnum(E1.B, 1, 2, "A", "OLD_REMOVED_CONSTANT", "B", E1.class);
|
||||
|
||||
//null invocation name:
|
||||
MethodType switchType = MethodType.methodType(int.class, E1.class, int.class);
|
||||
MethodHandle indy = ((CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), null, switchType)).dynamicInvoker();
|
||||
assertEquals(0, (int) indy.invoke(E1.A, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumsWithConstants() throws Throwable {
|
||||
enum E {
|
||||
A {},
|
||||
B {},
|
||||
C {}
|
||||
}
|
||||
ClassDesc eDesc = E.class.describeConstable().get();
|
||||
Object[] typeParams = new Object[] {
|
||||
EnumDesc.of(eDesc, "A"),
|
||||
EnumDesc.of(eDesc, "B"),
|
||||
EnumDesc.of(eDesc, "C"),
|
||||
"a",
|
||||
String.class
|
||||
};
|
||||
testType(E.A, 0, 0, typeParams);
|
||||
testType(E.B, 0, 1, typeParams);
|
||||
testType(E.C, 0, 2, typeParams);
|
||||
testType("a", 0, 3, typeParams);
|
||||
testType("x", 0, 4, typeParams);
|
||||
testType('a', 0, 5, typeParams);
|
||||
testEnum(E.class, E.A, 0, 0, "A", "B", "C");
|
||||
testEnum(E.class, E.B, 0, 1, "A", "B", "C");
|
||||
testEnum(E.class, E.C, 0, 2, "A", "B", "C");
|
||||
testEnum(E.class, E.C, 0, 2, "A", "B");
|
||||
testEnum(E.class, E.C, 1, 2, "A", "B");
|
||||
testEnum(E.class, E.C, 2, 2, "A", "B");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongSwitchTypes() throws Throwable {
|
||||
MethodType[] switchTypes = new MethodType[] {
|
||||
MethodType.methodType(int.class, Object.class),
|
||||
MethodType.methodType(int.class, Object.class, Integer.class)
|
||||
};
|
||||
for (MethodType switchType : switchTypes) {
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType)
|
||||
);
|
||||
}
|
||||
MethodType[] enumSwitchTypes = new MethodType[] {
|
||||
MethodType.methodType(int.class, Enum.class),
|
||||
MethodType.methodType(int.class, Object.class, int.class),
|
||||
MethodType.methodType(int.class, double.class, int.class),
|
||||
MethodType.methodType(int.class, Enum.class, Integer.class)
|
||||
};
|
||||
for (MethodType enumSwitchType : enumSwitchTypes) {
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchLabelTypes() throws Throwable {
|
||||
enum E {A}
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
testType(E.A, 0, -1, E.A)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchQualifiedEnum() throws Throwable {
|
||||
enum E {A, B, C}
|
||||
Object[] labels = new Object[] {
|
||||
EnumDesc.of(ClassDesc.of(E.class.getName()), "A"),
|
||||
EnumDesc.of(ClassDesc.of(E.class.getName()), "B"),
|
||||
EnumDesc.of(ClassDesc.of(E.class.getName()), "C")
|
||||
};
|
||||
testType(E.A, 0, 0, labels);
|
||||
testType(E.B, 0, 1, labels);
|
||||
testType(E.C, 0, 2, labels);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullLabels() throws Throwable {
|
||||
MethodType switchType = MethodType.methodType(int.class, Object.class, int.class);
|
||||
assertThrows(NullPointerException.class, () ->
|
||||
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, (Object[]) null)
|
||||
);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType,
|
||||
new Object[] {1, null, String.class})
|
||||
);
|
||||
MethodType enumSwitchType = MethodType.methodType(int.class, E1.class, int.class);
|
||||
assertThrows(NullPointerException.class, () ->
|
||||
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType, (Object[]) null)
|
||||
);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType,
|
||||
new Object[] {1, null, String.class})
|
||||
);
|
||||
//null invocationName is OK:
|
||||
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), null, switchType,
|
||||
new Object[] {Object.class});
|
||||
}
|
||||
|
||||
private static AtomicBoolean enumInitialized = new AtomicBoolean();
|
||||
@Test
|
||||
public void testEnumInitialization1() throws Throwable {
|
||||
enumInitialized.set(false);
|
||||
|
||||
enum E {
|
||||
A;
|
||||
|
||||
static {
|
||||
enumInitialized.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
MethodType enumSwitchType = MethodType.methodType(int.class, E.class, int.class);
|
||||
|
||||
CallSite invocation = (CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType, new Object[] {"A"});
|
||||
assertFalse(enumInitialized.get());
|
||||
assertEquals(-1, invocation.dynamicInvoker().invoke(null, 0));
|
||||
assertFalse(enumInitialized.get());
|
||||
E e = E.A;
|
||||
assertTrue(enumInitialized.get());
|
||||
assertEquals(0, invocation.dynamicInvoker().invoke(e, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumInitialization2() throws Throwable {
|
||||
enumInitialized.set(false);
|
||||
|
||||
enum E {
|
||||
A;
|
||||
|
||||
static {
|
||||
enumInitialized.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
MethodType switchType = MethodType.methodType(int.class, Object.class, int.class);
|
||||
Object[] labels = new Object[] {
|
||||
EnumDesc.of(ClassDesc.of(E.class.getName()), "A"),
|
||||
"test"
|
||||
};
|
||||
CallSite invocation = (CallSite) BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels);
|
||||
assertFalse(enumInitialized.get());
|
||||
assertEquals(-1, invocation.dynamicInvoker().invoke(null, 0));
|
||||
assertFalse(enumInitialized.get());
|
||||
assertEquals(1, invocation.dynamicInvoker().invoke("test", 0));
|
||||
assertFalse(enumInitialized.get());
|
||||
E e = E.A;
|
||||
assertTrue(enumInitialized.get());
|
||||
assertEquals(0, invocation.dynamicInvoker().invoke(e, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncorrectEnumLabels() throws Throwable {
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
testEnum(E1.B, 0, -1, "B", 1)
|
||||
);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
testEnum(E1.B, 0, -1, "B", null)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncorrectEnumStartIndex() throws Throwable {
|
||||
assertThrows(IndexOutOfBoundsException.class, () ->
|
||||
testEnum(E1.B, -1, -1, "B")
|
||||
); //OK
|
||||
assertThrows(IndexOutOfBoundsException.class, () ->
|
||||
testEnum(E1.B, 2, -1, "B")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncorrectTypeStartIndex() throws Throwable {
|
||||
assertThrows(IndexOutOfBoundsException.class, () ->
|
||||
testType("", -1, -1, "")
|
||||
);
|
||||
assertThrows(IndexOutOfBoundsException.class, () ->
|
||||
testType("", 2, -1, "")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHiddenClassAsCaseLabel() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
byte[] classBytes = createClass();
|
||||
Class<?> classA = lookup.defineHiddenClass(classBytes, false).lookupClass();
|
||||
Class<?> classB = lookup.defineHiddenClass(classBytes, false).lookupClass();
|
||||
Object[] labels = new Object[] {
|
||||
classA,
|
||||
classB,
|
||||
};
|
||||
testType(classA.getConstructor().newInstance(), 0, 0, labels);
|
||||
testType(classB.getConstructor().newInstance(), 0, 1, labels);
|
||||
}
|
||||
|
||||
private static byte[] createClass() {
|
||||
return ClassFile.of().build(ClassDesc.of("C"), clb -> {
|
||||
clb.withFlags(AccessFlag.SYNTHETIC)
|
||||
.withMethodBody("<init>",
|
||||
MethodTypeDesc.of(ConstantDescs.CD_void),
|
||||
ClassFile.ACC_PUBLIC,
|
||||
cb -> {
|
||||
cb.aload(0);
|
||||
cb.invokespecial(ConstantDescs.CD_Object,
|
||||
"<init>",
|
||||
MethodTypeDesc.of(ConstantDescs.CD_void));
|
||||
cb.return_();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullLookup() throws Throwable {
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
MethodType switchType = MethodType.methodType(int.class, Object.class, int.class);
|
||||
BSM_TYPE_SWITCH.invoke(null, "", switchType, Object.class);
|
||||
});
|
||||
enum E {}
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
MethodType switchType = MethodType.methodType(int.class, E.class, int.class);
|
||||
BSM_ENUM_SWITCH.invoke(null, "", switchType,
|
||||
new Object[] {});
|
||||
});
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
MethodType switchType = MethodType.methodType(int.class, E.class, int.class);
|
||||
BSM_ENUM_SWITCH.invoke(null, "", switchType,
|
||||
new Object[] {"A"});
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue