/* * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ package java.lang.invoke; import sun.invoke.util.Wrapper; import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError; import static java.util.Objects.requireNonNull; import java.lang.reflect.Modifier; /** * Bootstrap methods for dynamically-computed constants. * *
The bootstrap methods in this class will throw a
* {@code NullPointerException} for any reference argument that is {@code null},
* unless the argument is specified to be unused or specified to accept a
* {@code null} value.
*
* @since 11
*/
public final class ConstantBootstraps {
/**
* Do not call.
*/
private ConstantBootstraps() {throw new AssertionError();}
// implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant:
/*non-public*/
// BEGIN Android-removed: Remove unused implementation.
/*
static Object makeConstant(MethodHandle bootstrapMethod,
// Callee information:
String name, Class> type,
// Extra arguments for BSM, if any:
Object info,
// Caller information:
Class> callerClass) {
// Restrict bootstrap methods to those whose first parameter is Lookup
// The motivation here is, in the future, to possibly support BSMs
// that do not accept the meta-data of lookup/name/type, thereby
// allowing the co-opting of existing methods to be used as BSMs as
// long as the static arguments can be passed as method arguments
MethodType mt = bootstrapMethod.type();
if (mt.parameterCount() < 2 ||
!MethodHandles.Lookup.class.isAssignableFrom(mt.parameterType(0))) {
throw new BootstrapMethodError(
"Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod);
}
// BSMI.invoke handles all type checking and exception translation.
// If type is not a reference type, the JVM is expecting a boxed
// version, and will manage unboxing on the other side.
return BootstrapMethodInvoker.invoke(
type, bootstrapMethod, name, type, info, callerClass);
}
*/
// END Android-removed: Remove unused implementation.
/**
* Returns a {@code null} object reference for the reference type specified
* by {@code type}.
*
* @param lookup unused
* @param name unused
* @param type a reference type
* @return a {@code null} value
* @throws IllegalArgumentException if {@code type} is not a reference type
*/
public static Object nullConstant(MethodHandles.Lookup lookup, String name, Class> type) {
if (requireNonNull(type).isPrimitive()) {
throw new IllegalArgumentException(String.format("not reference: %s", type));
}
return null;
}
/**
* Returns a {@link Class} mirror for the primitive type whose type
* descriptor is specified by {@code name}.
*
* @param lookup unused
* @param name the descriptor (JVMS 4.3) of the desired primitive type
* @param type the required result type (must be {@code Class.class})
* @return the {@link Class} mirror
* @throws IllegalArgumentException if the name is not a descriptor for a
* primitive type or the type is not {@code Class.class}
*/
public static Class> primitiveClass(MethodHandles.Lookup lookup, String name, Class> type) {
requireNonNull(name);
requireNonNull(type);
if (type != Class.class) {
throw new IllegalArgumentException();
}
if (name.length() != 1) {
throw new IllegalArgumentException(String.format("not primitive: %s", name));
}
return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType();
}
/**
* Returns an {@code enum} constant of the type specified by {@code type}
* with the name specified by {@code name}.
*
* @param lookup the lookup context describing the class performing the
* operation (normally stacked by the JVM)
* @param name the name of the constant to return, which must exactly match
* an enum constant in the specified type.
* @param type the {@code Class} object describing the enum type for which
* a constant is to be returned
* @param
* This method behaves as if the method handle to be invoked is the result
* of adapting the given method handle, via {@link MethodHandle#asType}, to
* adjust the return type to the desired type.
*
* @param lookup unused
* @param name unused
* @param type the desired type of the value to be returned, which must be
* compatible with the return type of the method handle
* @param handle the method handle to be invoked
* @param args the arguments to pass to the method handle, as if with
* {@link MethodHandle#invokeWithArguments}. Each argument may be
* {@code null}.
* @return the result of invoking the method handle
* @throws WrongMethodTypeException if the handle's method type cannot be
* adjusted to take the given number of arguments, or if the handle's return
* type cannot be adjusted to the desired type
* @throws ClassCastException if an argument or the result produced by
* invoking the handle cannot be converted by reference casting
* @throws Throwable anything thrown by the method handle invocation
*/
public static Object invoke(MethodHandles.Lookup lookup, String name, Class> type,
MethodHandle handle, Object... args) throws Throwable {
requireNonNull(type);
requireNonNull(handle);
requireNonNull(args);
if (type != handle.type().returnType()) {
// Adjust the return type of the handle to be invoked while
// preserving variable arity if present
handle = handle.asType(handle.type().changeReturnType(type)).
withVarargs(handle.isVarargsCollector());
}
return handle.invokeWithArguments(args);
}
/**
* Finds a {@link VarHandle} for an instance field.
*
* @param lookup the lookup context describing the class performing the
* operation (normally stacked by the JVM)
* @param name the name of the field
* @param type the required result type (must be {@code Class
* Given a destination type {@code dstType} and an input
* value {@code value}, one of the following will happen:
*
* Otherwise one of the following conversions is applied to {@code value}:
*
* The result is the same as when using the following code:
*
*
*
*
*
*
* @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 (RuntimeException|Error e) {
throw e; // let specified CCE and other runtime exceptions/errors through
} catch (Throwable throwable) {
throw new InternalError(throwable); // Not specified, throw InternalError
}
}
private static {@code
* MethodHandle id = MethodHandles.identity(dstType);
* MethodType mt = MethodType.methodType(dstType, Object.class);
* MethodHandle conv = MethodHandles.explicitCastArguments(id, mt);
* return conv.invoke(value);
* }