8241100: Make Boolean, Character, Byte, and Short implement Constable
Reviewed-by: jrose, briangoetz, psandoz
This commit is contained in:
parent
2d8bea8c1d
commit
31041d406a
@ -27,6 +27,15 @@ package java.lang;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.BSM_GET_STATIC_FINAL;
|
||||
import static java.lang.constant.ConstantDescs.CD_Boolean;
|
||||
|
||||
/**
|
||||
* The Boolean class wraps a value of the primitive type
|
||||
* {@code boolean} in an object. An object of type
|
||||
@ -43,7 +52,7 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class Boolean implements java.io.Serializable,
|
||||
Comparable<Boolean>
|
||||
Comparable<Boolean>, Constable
|
||||
{
|
||||
/**
|
||||
* The {@code Boolean} object corresponding to the primitive
|
||||
@ -344,4 +353,16 @@ public final class Boolean implements java.io.Serializable,
|
||||
public static boolean logicalXor(boolean a, boolean b) {
|
||||
return a ^ b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the nominal descriptor for this
|
||||
* instance.
|
||||
*
|
||||
* @return an {@link Optional} describing the {@linkplain Boolean} instance
|
||||
* @since 15
|
||||
*/
|
||||
@Override
|
||||
public Optional<DynamicConstantDesc<Boolean>> describeConstable() {
|
||||
return Optional.of(value ? ConstantDescs.TRUE : ConstantDescs.FALSE);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 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
|
||||
@ -28,6 +28,15 @@ package java.lang;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.BSM_EXPLICIT_CAST;
|
||||
import static java.lang.constant.ConstantDescs.CD_byte;
|
||||
import static java.lang.constant.ConstantDescs.CD_int;
|
||||
import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
|
||||
|
||||
/**
|
||||
*
|
||||
* The {@code Byte} class wraps a value of primitive type {@code byte}
|
||||
@ -44,7 +53,7 @@ import jdk.internal.misc.VM;
|
||||
* @see java.lang.Number
|
||||
* @since 1.1
|
||||
*/
|
||||
public final class Byte extends Number implements Comparable<Byte> {
|
||||
public final class Byte extends Number implements Comparable<Byte>, Constable {
|
||||
|
||||
/**
|
||||
* A constant holding the minimum value a {@code byte} can
|
||||
@ -77,6 +86,18 @@ public final class Byte extends Number implements Comparable<Byte> {
|
||||
return Integer.toString((int)b, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the nominal descriptor for this
|
||||
* instance.
|
||||
*
|
||||
* @return an {@link Optional} describing the {@linkplain Byte} instance
|
||||
* @since 15
|
||||
*/
|
||||
@Override
|
||||
public Optional<DynamicConstantDesc<Byte>> describeConstable() {
|
||||
return Optional.of(DynamicConstantDesc.ofNamed(BSM_EXPLICIT_CAST, DEFAULT_NAME, CD_byte, intValue()));
|
||||
}
|
||||
|
||||
private static class ByteCache {
|
||||
private ByteCache() {}
|
||||
|
||||
|
@ -25,14 +25,22 @@
|
||||
|
||||
package java.lang;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.BSM_EXPLICIT_CAST;
|
||||
import static java.lang.constant.ConstantDescs.CD_char;
|
||||
import static java.lang.constant.ConstantDescs.CD_int;
|
||||
import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
|
||||
|
||||
/**
|
||||
* The {@code Character} class wraps a value of the primitive
|
||||
* type {@code char} in an object. An object of class
|
||||
@ -122,7 +130,7 @@ import jdk.internal.misc.VM;
|
||||
* @since 1.0
|
||||
*/
|
||||
public final
|
||||
class Character implements java.io.Serializable, Comparable<Character> {
|
||||
class Character implements java.io.Serializable, Comparable<Character>, Constable {
|
||||
/**
|
||||
* The minimum radix available for conversion to and from strings.
|
||||
* The constant value of this field is the smallest value permitted
|
||||
@ -602,6 +610,17 @@ class Character implements java.io.Serializable, Comparable<Character> {
|
||||
*/
|
||||
public static final int MAX_CODE_POINT = 0X10FFFF;
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the nominal descriptor for this
|
||||
* instance.
|
||||
*
|
||||
* @return an {@link Optional} describing the {@linkplain Character} instance
|
||||
* @since 15
|
||||
*/
|
||||
@Override
|
||||
public Optional<DynamicConstantDesc<Character>> describeConstable() {
|
||||
return Optional.of(DynamicConstantDesc.ofNamed(BSM_EXPLICIT_CAST, DEFAULT_NAME, CD_char, (int) value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instances of this class represent particular subsets of the Unicode
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 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
|
||||
@ -28,6 +28,15 @@ package java.lang;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.BSM_EXPLICIT_CAST;
|
||||
import static java.lang.constant.ConstantDescs.CD_int;
|
||||
import static java.lang.constant.ConstantDescs.CD_short;
|
||||
import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
|
||||
|
||||
/**
|
||||
* The {@code Short} class wraps a value of primitive type {@code
|
||||
* short} in an object. An object of type {@code Short} contains a
|
||||
@ -43,7 +52,7 @@ import jdk.internal.misc.VM;
|
||||
* @see java.lang.Number
|
||||
* @since 1.1
|
||||
*/
|
||||
public final class Short extends Number implements Comparable<Short> {
|
||||
public final class Short extends Number implements Comparable<Short>, Constable {
|
||||
|
||||
/**
|
||||
* A constant holding the minimum value a {@code short} can
|
||||
@ -203,6 +212,18 @@ public final class Short extends Number implements Comparable<Short> {
|
||||
return valueOf(s, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the nominal descriptor for this
|
||||
* instance.
|
||||
*
|
||||
* @return an {@link Optional} describing the {@linkplain Short} instance
|
||||
* @since 15
|
||||
*/
|
||||
@Override
|
||||
public Optional<DynamicConstantDesc<Short>> describeConstable() {
|
||||
return Optional.of(DynamicConstantDesc.ofNamed(BSM_EXPLICIT_CAST, DEFAULT_NAME, CD_short, intValue()));
|
||||
}
|
||||
|
||||
private static class ShortCache {
|
||||
private ShortCache() {}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -194,10 +194,18 @@ public final class ConstantDescs {
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "enumConstant",
|
||||
CD_Enum);
|
||||
|
||||
/**
|
||||
* {@link MethodHandleDesc} representing {@link ConstantBootstraps#getStaticFinal(Lookup, String, Class, Class) ConstantBootstraps.getStaticFinal}
|
||||
* @since 15
|
||||
*/
|
||||
public static final DirectMethodHandleDesc BSM_GET_STATIC_FINAL
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "getStaticFinal",
|
||||
CD_Object, CD_Class);
|
||||
|
||||
/** {@link MethodHandleDesc} representing {@link ConstantBootstraps#nullConstant(Lookup, String, Class) ConstantBootstraps.nullConstant} */
|
||||
public static final DirectMethodHandleDesc BSM_NULL_CONSTANT
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "nullConstant",
|
||||
ConstantDescs.CD_Object);
|
||||
CD_Object);
|
||||
|
||||
/** {@link MethodHandleDesc} representing {@link ConstantBootstraps#fieldVarHandle(Lookup, String, Class, Class, Class) ConstantBootstraps.fieldVarHandle} */
|
||||
public static final DirectMethodHandleDesc BSM_VARHANDLE_FIELD
|
||||
@ -219,6 +227,14 @@ public final class ConstantDescs {
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "invoke",
|
||||
CD_Object, CD_MethodHandle, CD_Object.arrayType());
|
||||
|
||||
/**
|
||||
* {@link MethodHandleDesc} representing {@link ConstantBootstraps#explicitCast(Lookup, String, Class, Object)} ConstantBootstraps.explicitCast}
|
||||
* @since 15
|
||||
*/
|
||||
public static final DirectMethodHandleDesc BSM_EXPLICIT_CAST
|
||||
= ofConstantBootstrap(CD_ConstantBootstraps, "explicitCast",
|
||||
CD_Object, CD_Object);
|
||||
|
||||
/** {@link ClassDesc} representing the primitive type {@code int} */
|
||||
public static final ClassDesc CD_int = ClassDesc.ofDescriptor("I");
|
||||
|
||||
@ -251,6 +267,22 @@ public final class ConstantDescs {
|
||||
= DynamicConstantDesc.ofNamed(ConstantDescs.BSM_NULL_CONSTANT,
|
||||
DEFAULT_NAME, ConstantDescs.CD_Object);
|
||||
|
||||
/**
|
||||
* Nominal descriptor representing the constant {@linkplain Boolean#TRUE}
|
||||
* @since 15
|
||||
*/
|
||||
public static final DynamicConstantDesc<Boolean> TRUE
|
||||
= DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL,
|
||||
"TRUE", CD_Boolean, CD_Boolean);
|
||||
|
||||
/**
|
||||
* Nominal descriptor representing the constant {@linkplain Boolean#TRUE}
|
||||
* @since 15
|
||||
*/
|
||||
public static final DynamicConstantDesc<Boolean> FALSE
|
||||
= DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL,
|
||||
"FALSE", CD_Boolean, CD_Boolean);
|
||||
|
||||
static final DirectMethodHandleDesc MHD_METHODHANDLE_ASTYPE
|
||||
= MethodHandleDesc.ofMethod(Kind.VIRTUAL, CD_MethodHandle, "asType",
|
||||
MethodTypeDesc.of(CD_MethodHandle, CD_MethodType));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 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
|
||||
@ -355,6 +355,71 @@ public final class ConstantBootstraps {
|
||||
return MethodHandles.arrayElementVarHandle(validateClassAccess(lookup, arrayClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a conversion from a source type to a destination type.
|
||||
* <p>
|
||||
* Given a destination type {@code dstType} and an input
|
||||
* value {@code value}, one of the following will happen:
|
||||
* <ul>
|
||||
* <li>If {@code dstType} is {@code void.class},
|
||||
* a {@link ClassCastException} is thrown.
|
||||
* <li>If {@code dstType} is {@code Object.class}, {@code value} is returned as is.
|
||||
* </ul>
|
||||
* <p>
|
||||
* Otherwise one of the following conversions is applied to {@code value}:
|
||||
* <ol>
|
||||
* <li>If {@code dstType} is a reference type, a reference cast
|
||||
* is applied to {@code value} as if by calling {@code dstType.cast(value)}.
|
||||
* <li>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
|
||||
* {@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.
|
||||
* </ol>
|
||||
* <p>
|
||||
* The result is the same as when using the following code:
|
||||
* <blockquote><pre>{@code
|
||||
* MethodHandle id = MethodHandles.identity(dstType);
|
||||
* MethodType mt = MethodType.methodType(dstType, Object.class);
|
||||
* MethodHandle conv = MethodHandles.explicitCastArguments(id, mt);
|
||||
* return conv.invoke(value);
|
||||
* }</pre></blockquote>
|
||||
*
|
||||
* @param lookup unused
|
||||
* @param name unused
|
||||
* @param dstType the destination type of the conversion
|
||||
* @param value the value to be converted
|
||||
* @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})
|
||||
*
|
||||
* @since 15
|
||||
*/
|
||||
public static Object explicitCast(MethodHandles.Lookup lookup, String name, Class<?> dstType, Object value)
|
||||
throws ClassCastException {
|
||||
if (dstType == void.class)
|
||||
throw new ClassCastException("Can not convert to void");
|
||||
if (dstType == Object.class)
|
||||
return value;
|
||||
|
||||
MethodHandle id = MethodHandles.identity(dstType);
|
||||
MethodType mt = MethodType.methodType(dstType, Object.class);
|
||||
MethodHandle conv = MethodHandles.explicitCastArguments(id, mt);
|
||||
try {
|
||||
return conv.invoke(value);
|
||||
} catch (ClassCastException e) {
|
||||
throw e; // specified, let CCE through
|
||||
} catch (Throwable throwable) {
|
||||
throw new InternalError(throwable); // Not specified, throw InternalError
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> Class<T> validateClassAccess(MethodHandles.Lookup lookup, Class<T> type) {
|
||||
try {
|
||||
lookup.accessClass(type);
|
||||
|
79
test/jdk/java/lang/constant/ConvertTest.java
Normal file
79
test/jdk/java/lang/constant/ConvertTest.java
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
58
test/jdk/java/lang/constant/DescribeResolveTest.java
Normal file
58
test/jdk/java/lang/constant/DescribeResolveTest.java
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 DescribeResolveTest
|
||||
*/
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
public class DescribeResolveTest {
|
||||
|
||||
@DataProvider
|
||||
public static Object[][] constables() {
|
||||
return new Object[][]{
|
||||
{ true },
|
||||
{ false },
|
||||
{ (short) 10 },
|
||||
{ (byte) 10 },
|
||||
{ (char) 10 },
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "constables")
|
||||
public void testDescribeResolve(Constable constable) throws ReflectiveOperationException {
|
||||
ConstantDesc desc = constable.describeConstable().orElseThrow();
|
||||
Object resolved = desc.resolveConstantDesc(MethodHandles.lookup());
|
||||
assertEquals(constable, resolved);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user