1 /*
2  * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.lang.invoke;
26 
27 import sun.invoke.util.Wrapper;
28 
29 import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError;
30 import static java.util.Objects.requireNonNull;
31 
32 import java.lang.reflect.Modifier;
33 
34 /**
35  * Bootstrap methods for dynamically-computed constants.
36  *
37  * <p>The bootstrap methods in this class will throw a
38  * {@code NullPointerException} for any reference argument that is {@code null},
39  * unless the argument is specified to be unused or specified to accept a
40  * {@code null} value.
41  *
42  * @since 11
43  */
44 public final class ConstantBootstraps {
45     /**
46      * Do not call.
47      */
ConstantBootstraps()48     private ConstantBootstraps() {throw new AssertionError();}
49 
50     // implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant:
51     /*non-public*/
52     // BEGIN Android-removed: Remove unused implementation.
53     /*
54     static Object makeConstant(MethodHandle bootstrapMethod,
55                                // Callee information:
56                                String name, Class<?> type,
57                                // Extra arguments for BSM, if any:
58                                Object info,
59                                // Caller information:
60                                Class<?> callerClass) {
61         // Restrict bootstrap methods to those whose first parameter is Lookup
62         // The motivation here is, in the future, to possibly support BSMs
63         // that do not accept the meta-data of lookup/name/type, thereby
64         // allowing the co-opting of existing methods to be used as BSMs as
65         // long as the static arguments can be passed as method arguments
66         MethodType mt = bootstrapMethod.type();
67         if (mt.parameterCount() < 2 ||
68             !MethodHandles.Lookup.class.isAssignableFrom(mt.parameterType(0))) {
69             throw new BootstrapMethodError(
70                     "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod);
71         }
72 
73         // BSMI.invoke handles all type checking and exception translation.
74         // If type is not a reference type, the JVM is expecting a boxed
75         // version, and will manage unboxing on the other side.
76         return BootstrapMethodInvoker.invoke(
77                 type, bootstrapMethod, name, type, info, callerClass);
78     }
79     */
80     // END Android-removed: Remove unused implementation.
81 
82     /**
83      * Returns a {@code null} object reference for the reference type specified
84      * by {@code type}.
85      *
86      * @param lookup unused
87      * @param name unused
88      * @param type a reference type
89      * @return a {@code null} value
90      * @throws IllegalArgumentException if {@code type} is not a reference type
91      */
nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type)92     public static Object nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type) {
93         if (requireNonNull(type).isPrimitive()) {
94             throw new IllegalArgumentException(String.format("not reference: %s", type));
95         }
96 
97         return null;
98     }
99 
100     /**
101      * Returns a {@link Class} mirror for the primitive type whose type
102      * descriptor is specified by {@code name}.
103      *
104      * @param lookup unused
105      * @param name the descriptor (JVMS 4.3) of the desired primitive type
106      * @param type the required result type (must be {@code Class.class})
107      * @return the {@link Class} mirror
108      * @throws IllegalArgumentException if the name is not a descriptor for a
109      * primitive type or the type is not {@code Class.class}
110      */
primitiveClass(MethodHandles.Lookup lookup, String name, Class<?> type)111     public static Class<?> primitiveClass(MethodHandles.Lookup lookup, String name, Class<?> type) {
112         requireNonNull(name);
113         requireNonNull(type);
114         if (type != Class.class) {
115             throw new IllegalArgumentException();
116         }
117         if (name.length() != 1) {
118             throw new IllegalArgumentException(String.format("not primitive: %s", name));
119         }
120 
121         return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType();
122     }
123 
124     /**
125      * Returns an {@code enum} constant of the type specified by {@code type}
126      * with the name specified by {@code name}.
127      *
128      * @param lookup the lookup context describing the class performing the
129      * operation (normally stacked by the JVM)
130      * @param name the name of the constant to return, which must exactly match
131      * an enum constant in the specified type.
132      * @param type the {@code Class} object describing the enum type for which
133      * a constant is to be returned
134      * @param <E> The enum type for which a constant value is to be returned
135      * @return the enum constant of the specified enum type with the
136      * specified name
137      * @throws IllegalAccessError if the declaring class or the field is not
138      * accessible to the class performing the operation
139      * @throws IllegalArgumentException if the specified enum type has
140      * no constant with the specified name, or the specified
141      * class object does not represent an enum type
142      * @see Enum#valueOf(Class, String)
143      */
enumConstant(MethodHandles.Lookup lookup, String name, Class<E> type)144     public static <E extends Enum<E>> E enumConstant(MethodHandles.Lookup lookup, String name, Class<E> type) {
145         requireNonNull(lookup);
146         requireNonNull(name);
147         requireNonNull(type);
148         validateClassAccess(lookup, type);
149 
150         return Enum.valueOf(type, name);
151     }
152 
153     /**
154      * Returns the value of a static final field.
155      *
156      * @param lookup the lookup context describing the class performing the
157      * operation (normally stacked by the JVM)
158      * @param name the name of the field
159      * @param type the type of the field
160      * @param declaringClass the class in which the field is declared
161      * @return the value of the field
162      * @throws IllegalAccessError if the declaring class or the field is not
163      * accessible to the class performing the operation
164      * @throws NoSuchFieldError if the specified field does not exist
165      * @throws IncompatibleClassChangeError if the specified field is not
166      * {@code final}
167      */
getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type, Class<?> declaringClass)168     public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type,
169                                         Class<?> declaringClass) {
170         requireNonNull(lookup);
171         requireNonNull(name);
172         requireNonNull(type);
173         requireNonNull(declaringClass);
174 
175         MethodHandle mh;
176         try {
177             mh = lookup.findStaticGetter(declaringClass, name, type);
178             // Android-changed: Re-implement final modifier check with existing APIs.
179             // MemberName member = mh.internalMemberName();
180             // if (!member.isFinal()) {
181             MethodHandleInfo info = lookup.revealDirect(mh);
182             if (!Modifier.isFinal(info.getModifiers())) {
183                 throw new IncompatibleClassChangeError("not a final field: " + name);
184             }
185         }
186         catch (ReflectiveOperationException ex) {
187             throw mapLookupExceptionToError(ex);
188         }
189 
190         // Since mh is a handle to a static field only instances of
191         // VirtualMachineError are anticipated to be thrown, such as a
192         // StackOverflowError or an InternalError from the j.l.invoke code
193         try {
194             return mh.invoke();
195         }
196         catch (RuntimeException | Error e) {
197             throw e;
198         }
199         catch (Throwable e) {
200             throw new LinkageError("Unexpected throwable", e);
201         }
202     }
203 
204     /**
205      * Returns the value of a static final field declared in the class which
206      * is the same as the field's type (or, for primitive-valued fields,
207      * declared in the wrapper class.)  This is a simplified form of
208      * {@link #getStaticFinal(MethodHandles.Lookup, String, Class, Class)}
209      * for the case where a class declares distinguished constant instances of
210      * itself.
211      *
212      * @param lookup the lookup context describing the class performing the
213      * operation (normally stacked by the JVM)
214      * @param name the name of the field
215      * @param type the type of the field
216      * @return the value of the field
217      * @throws IllegalAccessError if the declaring class or the field is not
218      * accessible to the class performing the operation
219      * @throws NoSuchFieldError if the specified field does not exist
220      * @throws IncompatibleClassChangeError if the specified field is not
221      * {@code final}
222      * @see #getStaticFinal(MethodHandles.Lookup, String, Class, Class)
223      */
getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type)224     public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type) {
225         requireNonNull(type);
226 
227         Class<?> declaring = type.isPrimitive()
228                              ? Wrapper.forPrimitiveType(type).wrapperType()
229                              : type;
230         return getStaticFinal(lookup, name, type, declaring);
231     }
232 
233 
234     /**
235      * Returns the result of invoking a method handle with the provided
236      * arguments.
237      * <p>
238      * This method behaves as if the method handle to be invoked is the result
239      * of adapting the given method handle, via {@link MethodHandle#asType}, to
240      * adjust the return type to the desired type.
241      *
242      * @param lookup unused
243      * @param name unused
244      * @param type the desired type of the value to be returned, which must be
245      * compatible with the return type of the method handle
246      * @param handle the method handle to be invoked
247      * @param args the arguments to pass to the method handle, as if with
248      * {@link MethodHandle#invokeWithArguments}.  Each argument may be
249      * {@code null}.
250      * @return the result of invoking the method handle
251      * @throws WrongMethodTypeException if the handle's method type cannot be
252      * adjusted to take the given number of arguments, or if the handle's return
253      * type cannot be adjusted to the desired type
254      * @throws ClassCastException if an argument or the result produced by
255      * invoking the handle cannot be converted by reference casting
256      * @throws Throwable anything thrown by the method handle invocation
257      */
invoke(MethodHandles.Lookup lookup, String name, Class<?> type, MethodHandle handle, Object... args)258     public static Object invoke(MethodHandles.Lookup lookup, String name, Class<?> type,
259                                 MethodHandle handle, Object... args) throws Throwable {
260         requireNonNull(type);
261         requireNonNull(handle);
262         requireNonNull(args);
263 
264         if (type != handle.type().returnType()) {
265             // Adjust the return type of the handle to be invoked while
266             // preserving variable arity if present
267             handle = handle.asType(handle.type().changeReturnType(type)).
268                     withVarargs(handle.isVarargsCollector());
269         }
270 
271         return handle.invokeWithArguments(args);
272     }
273 
274     /**
275      * Finds a {@link VarHandle} for an instance field.
276      *
277      * @param lookup the lookup context describing the class performing the
278      * operation (normally stacked by the JVM)
279      * @param name the name of the field
280      * @param type the required result type (must be {@code Class<VarHandle>})
281      * @param declaringClass the class in which the field is declared
282      * @param fieldType the type of the field
283      * @return the {@link VarHandle}
284      * @throws IllegalAccessError if the declaring class or the field is not
285      * accessible to the class performing the operation
286      * @throws NoSuchFieldError if the specified field does not exist
287      * @throws IllegalArgumentException if the type is not {@code VarHandle}
288      */
fieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, Class<?> declaringClass, Class<?> fieldType)289     public static VarHandle fieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
290                                            Class<?> declaringClass, Class<?> fieldType) {
291         requireNonNull(lookup);
292         requireNonNull(name);
293         requireNonNull(type);
294         requireNonNull(declaringClass);
295         requireNonNull(fieldType);
296         if (type != VarHandle.class) {
297             throw new IllegalArgumentException();
298         }
299 
300         try {
301             return lookup.findVarHandle(declaringClass, name, fieldType);
302         }
303         catch (ReflectiveOperationException e) {
304             throw mapLookupExceptionToError(e);
305         }
306     }
307 
308     /**
309      * Finds a {@link VarHandle} for a static field.
310      *
311      * @param lookup the lookup context describing the class performing the
312      * operation (normally stacked by the JVM)
313      * @param name the name of the field
314      * @param type the required result type (must be {@code Class<VarHandle>})
315      * @param declaringClass the class in which the field is declared
316      * @param fieldType the type of the field
317      * @return the {@link VarHandle}
318      * @throws IllegalAccessError if the declaring class or the field is not
319      * accessible to the class performing the operation
320      * @throws NoSuchFieldError if the specified field does not exist
321      * @throws IllegalArgumentException if the type is not {@code VarHandle}
322      */
staticFieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, Class<?> declaringClass, Class<?> fieldType)323     public static VarHandle staticFieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
324                                                  Class<?> declaringClass, Class<?> fieldType) {
325         requireNonNull(lookup);
326         requireNonNull(name);
327         requireNonNull(type);
328         requireNonNull(declaringClass);
329         requireNonNull(fieldType);
330         if (type != VarHandle.class) {
331             throw new IllegalArgumentException();
332         }
333 
334         try {
335             return lookup.findStaticVarHandle(declaringClass, name, fieldType);
336         }
337         catch (ReflectiveOperationException e) {
338             throw mapLookupExceptionToError(e);
339         }
340     }
341 
342     /**
343      * Finds a {@link VarHandle} for an array type.
344      *
345      * @param lookup the lookup context describing the class performing the
346      * operation (normally stacked by the JVM)
347      * @param name unused
348      * @param type the required result type (must be {@code Class<VarHandle>})
349      * @param arrayClass the type of the array
350      * @return the {@link VarHandle}
351      * @throws IllegalAccessError if the component type of the array is not
352      * accessible to the class performing the operation
353      * @throws IllegalArgumentException if the type is not {@code VarHandle}
354      */
arrayVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, Class<?> arrayClass)355     public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
356                                            Class<?> arrayClass) {
357         requireNonNull(lookup);
358         requireNonNull(type);
359         requireNonNull(arrayClass);
360         if (type != VarHandle.class) {
361             throw new IllegalArgumentException();
362         }
363 
364         return MethodHandles.arrayElementVarHandle(validateClassAccess(lookup, arrayClass));
365     }
366 
367     /**
368      * Applies a conversion from a source type to a destination type.
369      * <p>
370      * Given a destination type {@code dstType} and an input
371      * value {@code value}, one of the following will happen:
372      * <ul>
373      * <li>If {@code dstType} is {@code void.class},
374      *     a {@link ClassCastException} is thrown.
375      * <li>If {@code dstType} is {@code Object.class}, {@code value} is returned as is.
376      * </ul>
377      * <p>
378      * Otherwise one of the following conversions is applied to {@code value}:
379      * <ol>
380      * <li>If {@code dstType} is a reference type, a reference cast
381      *     is applied to {@code value} as if by calling {@code dstType.cast(value)}.
382      * <li>If {@code dstType} is a primitive type, then, if the runtime type
383      *     of {@code value} is a primitive wrapper type (such as {@link Integer}),
384      *     a Java unboxing conversion is applied {@jls 5.1.8} followed by a
385      *     Java casting conversion {@jls 5.5} converting either directly to
386      *     {@code dstType}, or, if {@code dstType} is {@code boolean},
387      *     to {@code int}, which is then converted to either {@code true}
388      *     or {@code false} depending on whether the least-significant-bit
389      *     is 1 or 0 respectively. If the runtime type of {@code value} is
390      *     not a primitive wrapper type a {@link ClassCastException} is thrown.
391      * </ol>
392      * <p>
393      * The result is the same as when using the following code:
394      * <blockquote><pre>{@code
395      * MethodHandle id = MethodHandles.identity(dstType);
396      * MethodType mt = MethodType.methodType(dstType, Object.class);
397      * MethodHandle conv = MethodHandles.explicitCastArguments(id, mt);
398      * return conv.invoke(value);
399      * }</pre></blockquote>
400      *
401      * @param lookup unused
402      * @param name unused
403      * @param dstType the destination type of the conversion
404      * @param value the value to be converted
405      * @return the converted value
406      * @throws ClassCastException when {@code dstType} is {@code void},
407      *         when a cast per (1) fails, or when {@code dstType} is a primitive type
408      *         and the runtime type of {@code value} is not a primitive wrapper type
409      *         (such as {@link Integer})
410      *
411      * @since 15
412      */
explicitCast(MethodHandles.Lookup lookup, String name, Class<?> dstType, Object value)413     public static Object explicitCast(MethodHandles.Lookup lookup, String name, Class<?> dstType, Object value)
414             throws ClassCastException {
415         if (dstType == void.class)
416             throw new ClassCastException("Can not convert to void");
417         if (dstType == Object.class)
418             return value;
419 
420         MethodHandle id = MethodHandles.identity(dstType);
421         MethodType mt = MethodType.methodType(dstType, Object.class);
422         MethodHandle conv = MethodHandles.explicitCastArguments(id, mt);
423         try {
424             return conv.invoke(value);
425         } catch (RuntimeException|Error e) {
426             throw e; // let specified CCE and other runtime exceptions/errors through
427         } catch (Throwable throwable) {
428             throw new InternalError(throwable); // Not specified, throw InternalError
429         }
430     }
431 
validateClassAccess(MethodHandles.Lookup lookup, Class<T> type)432     private static <T> Class<T> validateClassAccess(MethodHandles.Lookup lookup, Class<T> type) {
433         try {
434             lookup.accessClass(type);
435             return type;
436         }
437         catch (ReflectiveOperationException ex) {
438             throw mapLookupExceptionToError(ex);
439         }
440     }
441 }
442