2 * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
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).
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.
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
28 import java.lang.reflect.Constructor;
29 import sun.dyn.Access;
30 import sun.dyn.MemberName;
31 import sun.dyn.MethodHandleImpl;
32 import sun.dyn.util.VerifyAccess;
33 import sun.dyn.util.Wrapper;
34 import java.lang.reflect.Field;
35 import java.lang.reflect.Method;
36 import java.lang.reflect.Modifier;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import sun.dyn.Invokers;
40 import sun.dyn.MethodTypeImpl;
41 import sun.reflect.Reflection;
42 import static sun.dyn.MemberName.newIllegalArgumentException;
43 import static sun.dyn.MemberName.newNoAccessException;
46 * Fundamental operations and utilities for MethodHandle.
48 * <em>API Note:</em> The matching of method types in this API cannot
49 * be completely checked by Java's generic type system for three reasons:
51 * <li>Method types range over all possible arities,
52 * from no arguments to an arbitrary number of arguments.
53 * Generics are not variadic, and so cannot represent this.</li>
54 * <li>Method types can specify arguments of primitive types,
55 * which Java generic types cannot range over.</li>
56 * <li>Method types can optionally specify varargs (ellipsis).</li>
58 * @author John Rose, JSR 292 EG
60 public class MethodHandles {
62 private MethodHandles() { } // do not instantiate
64 private static final Access IMPL_TOKEN = Access.getToken();
65 private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
66 static { MethodHandleImpl.initStatics(); }
67 // See IMPL_LOOKUP below.
69 //// Method handle creation from ordinary methods.
71 public static Lookup lookup() {
76 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
77 * A factory object for creating method handles, when the creation
78 * requires access checking. Method handles do not perform
79 * access checks when they are called; this is a major difference
80 * from reflective {@link Method}, which performs access checking
81 * against every caller, on every call. Method handle access
82 * restrictions are enforced when a method handle is created.
83 * The caller class against which those restrictions are enforced
84 * is known as the "lookup class". {@link Lookup} embodies an
85 * authenticated lookup class, and can be used to create any number
86 * of access-checked method handles, all checked against a single
89 * A class which needs to create method handles will call
90 * {@code MethodHandles.lookup()} to create a factory for itself.
91 * It may then use this factory to create method handles on
92 * all of its methods, including private ones.
93 * It may also delegate the lookup (e.g., to a metaobject protocol)
94 * by passing the {@code Lookup} object to other code.
95 * If this other code creates method handles, they will be access
96 * checked against the original lookup class, and not with any higher
99 * Note that access checks only apply to named and reflected methods.
100 * Other method handle creation methods, such as {@link #convertArguments},
101 * do not require any access checks, and can be done independently
102 * of any lookup class.
104 * <em>A note about error conditions:<em> A lookup can fail, because
105 * the containing class is not accessible to the lookup class, or
106 * because the desired class member is missing, or because the
107 * desired class member is not accessible to the lookup class.
108 * It can also fail if a security manager is installed and refuses
109 * access. In any of these cases, an exception will be
110 * thrown from the attempted lookup.
111 * In general, the conditions under which a method handle may be
112 * created for a method {@code M} are exactly as restrictive as the conditions
113 * under which the lookup class could have compiled a call to {@code M}.
114 * At least some of these error conditions are likely to be
115 * represented by checked exceptions in the final version of this API.
119 private final Class<?> lookupClass;
121 /** Which class is performing the lookup? It is this class against
122 * which checks are performed for visibility and access permissions.
124 * This value is null if and only if this lookup is {@link #PUBLIC_LOOKUP}.
126 public Class<?> lookupClass() {
130 /** Embody the current class (the lookupClass) as a lookup class
131 * for method handle creation.
132 * Must be called by from a method in this package,
133 * which in turn is called by a method not in this package.
134 * Also, don't make it private, lest javac interpose
135 * an access$N method.
138 Class caller = getCallerClassAtEntryPoint();
139 // make sure we haven't accidentally picked up this class:
140 checkUnprivilegedlookupClass(caller);
141 this.lookupClass = caller;
144 private Lookup(Class<?> lookupClass) {
145 this.lookupClass = lookupClass;
148 private static final Class<?> PUBLIC_ONLY = sun.dyn.empty.Empty.class;
150 /** Version of lookup which is trusted minimally.
151 * It can only be used to create method handles to
152 * publicly accessible members.
154 public static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_ONLY);
156 /** Package-private version of lookup which is trusted. */
157 static final Lookup IMPL_LOOKUP = new Lookup(null);
158 static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); }
160 private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
161 String name = lookupClass.getName();
162 if (name.startsWith("java.dyn.") || name.startsWith("sun.dyn."))
163 throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
167 public String toString() {
168 if (lookupClass == PUBLIC_ONLY)
170 if (lookupClass == null)
172 return lookupClass.getName();
175 // call this from an entry point method in Lookup with extraFrames=0.
176 private static Class<?> getCallerClassAtEntryPoint() {
177 final int CALLER_DEPTH = 4;
178 // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
179 // 2: Lookup.<init>, 3: MethodHandles.*, 4: caller
180 // Note: This should be the only use of getCallerClass in this file.
181 return Reflection.getCallerClass(CALLER_DEPTH);
185 * Produce a method handle for a static method.
186 * The type of the method handle will be that of the method.
187 * The method and all its argument types must be accessible to the lookup class.
188 * If the method's class has not yet been initialized, that is done
189 * immediately, before the method handle is returned.
190 * @param defc the class from which the method is accessed
191 * @param name the name of the method
192 * @param type the type of the method
193 * @return the desired method handle
194 * @exception SecurityException <em>TBD</em>
195 * @exception NoAccessException if the method does not exist or access checking fails
198 MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException {
199 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass);
200 checkStatic(true, method, lookupClass);
201 //throw NoSuchMethodException
202 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass);
206 * Produce a method handle for a virtual method.
207 * The type of the method handle will be that of the method,
208 * with the receiver type ({@code defc}) prepended.
209 * The method and all its argument types must be accessible to the lookup class.
211 * (<em>BUG NOTE:</em> The type {@code Object} may be prepended instead
212 * of the receiver type, if the receiver type is not on the boot class path.
213 * This is due to a temporary JVM limitation, in which MethodHandle
214 * claims to be unable to access such classes. To work around this
215 * bug, use {@code convertArguments} to normalize the type of the leading
216 * argument to a type on the boot class path, such as {@code Object}.)
218 * When called, the handle will treat the first argument as a receiver
219 * and dispatch on the receiver's type to determine which method
220 * implementation to enter.
221 * (The dispatching action is identical with that performed by an
222 * {@code invokevirtual} or {@code invokeinterface} instruction.)
223 * @param defc the class or interface from which the method is accessed
224 * @param name the name of the method
225 * @param type the type of the method, with the receiver argument omitted
226 * @return the desired method handle
227 * @exception SecurityException <em>TBD</em>
228 * @exception NoAccessException if the method does not exist or access checking fails
230 public MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException {
231 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), true, lookupClass);
232 checkStatic(false, method, lookupClass);
233 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass);
237 * Produce an early-bound method handle for a virtual method,
238 * as if called from an {@code invokespecial}
239 * instruction from {@code caller}.
240 * The type of the method handle will be that of the method,
241 * with a suitably restricted receiver type (such as {@code caller}) prepended.
242 * The method and all its argument types must be accessible
245 * When called, the handle will treat the first argument as a receiver,
246 * but will not dispatch on the receiver's type.
247 * (This direct invocation action is identical with that performed by an
248 * {@code invokespecial} instruction.)
250 * If the explicitly specified caller class is not identical with the
251 * lookup class, a security check TBD is performed.
252 * @param defc the class or interface from which the method is accessed
253 * @param name the name of the method, or "<init>" for a constructor
254 * @param type the type of the method, with the receiver argument omitted
255 * @param specialCaller the proposed calling class to perform the {@code invokespecial}
256 * @return the desired method handle
257 * @exception SecurityException <em>TBD</em>
258 * @exception NoAccessException if the method does not exist or access checking fails
260 public MethodHandle findSpecial(Class<?> defc, String name, MethodType type,
261 Class<?> specialCaller) throws NoAccessException {
262 checkSpecialCaller(specialCaller, lookupClass);
263 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, specialCaller);
264 checkStatic(false, method, lookupClass);
265 if (name.equals("<init>")) {
266 throw newNoAccessException("cannot directly invoke a constructor", method, null);
267 } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) {
268 throw newNoAccessException("method must be in a superclass of lookup class", method, lookupClass);
270 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
274 * Produce an early-bound method handle for a non-static method.
275 * The receiver must have a supertype {@code defc} in which a method
276 * of the given name and type is accessible to the lookup class.
277 * The method and all its argument types must be accessible to the lookup class.
278 * The type of the method handle will be that of the method.
279 * The given receiver will be bound into the method handle.
281 * Equivalent to the following expression:
283 * {@link #insertArgument}({@link #findVirtual}(defc, name, type), receiver)
285 * @param receiver the object from which the method is accessed
286 * @param name the name of the method
287 * @param type the type of the method, with the receiver argument omitted
288 * @return the desired method handle
289 * @exception SecurityException <em>TBD</em>
290 * @exception NoAccessException if the method does not exist or access checking fails
292 public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
293 Class<? extends Object> rcvc = receiver.getClass(); // may get NPE
294 MemberName reference = new MemberName(rcvc, name, type);
295 MemberName method = IMPL_NAMES.resolveOrFail(reference, true, lookupClass);
296 checkStatic(false, method, lookupClass);
297 MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass);
298 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver);
300 throw newNoAccessException(method, lookupClass);
305 * Make a direct method handle to <i>m</i>, if the lookup class has permission.
306 * If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
307 * If <i>m</i> is virtual, overriding is respected on every call.
308 * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
309 * The type of the method handle will be that of the method,
310 * with the receiver type prepended (but only if it is non-static).
311 * If the method's {@code accessible} flag is not set,
312 * access checking is performed immediately on behalf of the lookup class.
313 * If <i>m</i> is not public, do not share the resulting handle with untrusted parties.
314 * @param m the reflected method
315 * @return a method handle which can invoke the reflected method
316 * @exception NoAccessException if access checking fails
318 public MethodHandle unreflect(Method m) throws NoAccessException {
319 return unreflectImpl(new MemberName(m), m.isAccessible(), true, lookupClass);
323 * Produce a method handle for a reflected method.
324 * It will bypass checks for overriding methods on the receiver,
325 * as if by the {@code invokespecial} instruction.
326 * The type of the method handle will be that of the method,
327 * with the receiver type prepended.
328 * If the method's {@code accessible} flag is not set,
329 * access checking is performed immediately on behalf of the lookup class,
330 * as if {@code invokespecial} instruction were being linked.
331 * @param m the reflected method
332 * @return a method handle which can invoke the reflected method
333 * @exception NoAccessException if access checking fails
335 public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException {
336 checkSpecialCaller(specialCaller, lookupClass);
337 MemberName mname = new MemberName(m);
338 checkStatic(false, mname, lookupClass);
339 return unreflectImpl(mname, m.isAccessible(), false, specialCaller);
343 * Produce a method handle for a reflected constructor.
344 * The type of the method handle will be that of the constructor.
345 * The method handle will perform a {@code newInstance} operation,
346 * creating a new instance of the constructor's class on the
347 * arguments passed to the method handle.
349 * If the constructor's {@code accessible} flag is not set,
350 * access checking is performed immediately on behalf of the lookup class,
351 * as if {@code invokespecial} instruction were being linked.
352 * @param ctor the reflected constructor
353 * @return a method handle which can invoke the reflected constructor
354 * @exception NoAccessException if access checking fails
356 public MethodHandle unreflectConstructor(Constructor ctor) throws NoAccessException {
357 MemberName m = new MemberName(ctor);
358 return unreflectImpl(m, ctor.isAccessible(), false, lookupClass);
362 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
363 * Produce a method handle giving read access to a reflected field.
364 * The type of the method handle will have a return type of the field's
365 * value type. Its sole argument will be the field's containing class
366 * (but only if it is non-static).
367 * If the method's {@code accessible} flag is not set,
368 * access checking is performed immediately on behalf of the lookup class.
369 * @param f the reflected field
370 * @return a method handle which can load values from the reflected field
371 * @exception NoAccessException if access checking fails
373 public MethodHandle unreflectGetter(Field f) throws NoAccessException {
374 return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), false, lookupClass);
378 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
379 * Produce a method handle giving write access to a reflected field.
380 * The type of the method handle will have a void return type.
381 * Its last argument will be the field's value type.
382 * Its other argument will be the field's containing class
383 * (but only if it is non-static).
384 * If the method's {@code accessible} flag is not set,
385 * access checking is performed immediately on behalf of the lookup class.
386 * @param f the reflected field
387 * @return a method handle which can store values into the reflected field
388 * @exception NoAccessException if access checking fails
390 public MethodHandle unreflectSetter(Field f) throws NoAccessException {
391 return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), true, lookupClass);
396 static /*must not be public*/
397 MethodHandle findStaticFrom(Class<?> lookupClass,
398 Class<?> defc, String name, MethodType type) throws NoAccessException {
399 MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass);
400 checkStatic(true, method, lookupClass);
401 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass);
404 static void checkStatic(boolean wantStatic, MemberName m, Class<?> lookupClass) {
405 if (wantStatic != m.isStatic()) {
406 String message = wantStatic ? "expected a static method" : "expected a non-static method";
407 throw newNoAccessException(message, m, lookupClass);
411 static void checkSpecialCaller(Class<?> specialCaller, Class<?> lookupClass) {
412 if (lookupClass == Lookup.IMPL_LOOKUP.lookupClass())
413 return; // privileged action
414 if (lookupClass == null || // public-only access
415 !VerifyAccess.isSamePackageMember(specialCaller, lookupClass))
416 throw newNoAccessException("no private access", new MemberName(specialCaller), lookupClass);
419 // Helper for creating handles on reflected methods and constructors.
420 static MethodHandle unreflectImpl(MemberName m, boolean isAccessible,
421 boolean doDispatch, Class<?> lookupClass) {
422 MethodType mtype = m.getInvocationType();
423 Class<?> defc = m.getDeclaringClass();
424 int mods = m.getModifiers();
427 VerifyAccess.isAccessible(defc, mods, false, lookupClass) == null)
428 throw newNoAccessException(m, lookupClass);
432 // abbreviated access check for "unlocked" method
433 constraint = doDispatch ? defc : lookupClass;
435 constraint = VerifyAccess.isAccessible(defc, mods, doDispatch, lookupClass);
437 if (constraint != defc && !constraint.isAssignableFrom(defc)) {
438 if (!defc.isAssignableFrom(constraint))
439 throw newNoAccessException("receiver must be in caller class", m, lookupClass);
440 mtype = mtype.changeParameterType(0, constraint);
443 return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookupClass);
447 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
448 * Produce a method handle giving read access to elements of an array.
449 * The type of the method handle will have a return type of the array's
450 * element type. Its first argument will be the array type,
451 * and the second will be {@code int}.
452 * @param arrayClass an array type
453 * @return a method handle which can load values from the given array type
454 * @throws IllegalArgumentException if arrayClass is not an array type
457 MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
458 return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false);
462 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
463 * Produce a method handle giving write access to elements of an array.
464 * The type of the method handle will have a void return type.
465 * Its last argument will be the array's element type.
466 * The first and second arguments will be the array type and int.
467 * @return a method handle which can store values into the array type
468 * @throws IllegalArgumentException if arrayClass is not an array type
471 MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
472 return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true);
476 /// method handle invocation (reflective style)
479 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
480 * Call the {@code invoke} method of a given method handle,
481 * with arguments that exactly match the parameter types of the method handle.
482 * The length of the arguments array must equal the parameter count
483 * of the target's type.
484 * The arguments array is spread into separate arguments, and
485 * basic reference and unboxing conversions are applied.
487 * In order to match the type of the target, the following argument
488 * conversions are applied as necessary:
490 * <li>reference casting
493 * The following conversions are not applied:
495 * <li>primitive conversions (e.g., {@code byte} to {@code int}
496 * <li>varargs conversions other than the initial spread
497 * <li>any application-specific conversions (e.g., string to number)
499 * The result returned by the call is boxed if it is a primitive,
500 * or forced to null if the return type is void.
502 * This call is a convenience method for the following code:
504 * MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
505 * Object result = invoker.invoke(arguments);
507 * @param target the method handle to invoke
508 * @param arguments the arguments to pass to the target
509 * @return the result returned by the target
512 Object invoke(MethodHandle target, Object... arguments) {
513 int argc = arguments == null ? 0 : arguments.length;
514 MethodType type = target.type();
516 MethodHandle invoker = invokers(type).genericInvoker();
518 case 0: return invoker.<Object>invoke(target);
519 case 1: return invoker.<Object>invoke(target,
521 case 2: return invoker.<Object>invoke(target,
522 arguments[0], arguments[1]);
523 case 3: return invoker.<Object>invoke(target,
524 arguments[0], arguments[1], arguments[2]);
525 case 4: return invoker.<Object>invoke(target,
526 arguments[0], arguments[1], arguments[2], arguments[3]);
529 MethodHandle invoker = invokers(type).varargsInvoker();
530 return invoker.<Object>invoke(target, arguments);
534 Object invoke_0(MethodHandle target) {
535 MethodHandle invoker = invokers(target.type()).genericInvoker();
536 return invoker.<Object>invoke(target);
539 Object invoke_1(MethodHandle target, Object a0) {
540 MethodHandle invoker = invokers(target.type()).genericInvoker();
541 return invoker.<Object>invoke(target, a0);
544 Object invoke_2(MethodHandle target, Object a0, Object a1) {
545 MethodHandle invoker = invokers(target.type()).genericInvoker();
546 return invoker.<Object>invoke(target, a0, a1);
549 Object invoke_3(MethodHandle target, Object a0, Object a1, Object a2) {
550 MethodHandle invoker = invokers(target.type()).genericInvoker();
551 return invoker.<Object>invoke(target, a0, a1, a2);
554 Object invoke_4(MethodHandle target, Object a0, Object a1, Object a2, Object a3) {
555 MethodHandle invoker = invokers(target.type()).genericInvoker();
556 return invoker.<Object>invoke(target, a0, a1, a2, a3);
560 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
561 * Give a method handle which will invoke any method handle of the
562 * given type on a standard set of {@code Object} type arguments.
563 * The the resulting invoker will be a method handle with the following
566 * <li>a single {@code MethodHandle} target
567 * <li>zero or more {@code Object} values
568 * <li>an optional {@code Object[]} array containing more arguments
570 * The invoker will spread the varargs array (if present), apply
571 * reference casts as necessary, and unbox primitive arguments.
572 * The return value of the invoker will be an {@code Object} reference,
573 * boxing a primitive value if the original type returns a primitive,
574 * and always null if the original type returns void.
576 * This is a convenience method equivalent to the following code:
578 * MethodHandle invoker = exactInvoker(type);
579 * MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs);
580 * genericType = genericType.insertParameterType(0, MethodHandle.class);
582 * return convertArguments(invoker, genericType);
584 * return spreadArguments(invoker, genericType);
586 * @param type the desired target type
587 * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
588 * @param varargs if true, the invoker will accept a final {@code Object[]} argument
589 * @return a method handle suitable for invoking any method handle of the given type
592 MethodHandle genericInvoker(MethodType type, int objectArgCount, boolean varargs) {
593 return invokers(type).genericInvoker();
597 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
598 * Give a method handle which will take a invoke any method handle of the
599 * given type. The resulting invoker will have a type which is
600 * exactly equal to the desired type, except that it will accept
601 * an additional leading argument of type {@code MethodHandle}.
603 * This is a convenience method equivalent to the following code:
605 * MethodHandles.lookup().findVirtual(MethodHandle.class, "invoke", type);
607 * @param type the desired target type
608 * @return a method handle suitable for invoking any method handle of the given type
611 MethodHandle exactInvoker(MethodType type) {
612 return invokers(type).exactInvoker();
615 static private Invokers invokers(MethodType type) {
616 return MethodTypeImpl.invokers(IMPL_TOKEN, type);
620 * <em>WORK IN PROGRESS:</em>
621 * Perform value checking, exactly as if for an adapted method handle.
622 * It is assumed that the given value is either null, of type T0,
623 * or (if T0 is primitive) of the wrapper type corresponding to T0.
624 * The following checks and conversions are made:
626 * <li>If T0 and T1 are references, then a cast to T1 is applied.
627 * (The types do not need to be related in any particular way.)
628 * <li>If T0 and T1 are primitives, then a widening or narrowing
629 * conversion is applied, if one exists.
630 * <li>If T0 is a primitive and T1 a reference, and
631 * T0 has a wrapper type TW, a boxing conversion to TW is applied,
632 * possibly followed by a reference conversion.
633 * T1 must be TW or a supertype.
634 * <li>If T0 is a reference and T1 a primitive, and
635 * T1 has a wrapper type TW, an unboxing conversion is applied,
636 * possibly preceded by a reference conversion.
637 * T0 must be TW or a supertype.
638 * <li>If T1 is void, the return value is discarded
639 * <li>If T0 is void and T1 a reference, a null value is introduced.
640 * <li>If T0 is void and T1 a primitive, a zero value is introduced.
642 * If the value is discarded, null will be returned.
645 * @return the value, converted if necessary
646 * @throws java.lang.ClassCastException if a cast fails
649 <T0, T1> T1 checkValue(Class<T0> t0, Class<T1> t1, Object value)
650 throws ClassCastException
653 // no conversion needed; just reassert the same type
654 if (t0.isPrimitive())
655 return Wrapper.asPrimitiveType(t1).cast(value);
657 return Wrapper.OBJECT.cast(value, t1);
659 boolean prim0 = t0.isPrimitive(), prim1 = t1.isPrimitive();
661 // check contract with caller
662 Wrapper.OBJECT.cast(value, t0);
664 return Wrapper.OBJECT.cast(value, t1);
666 // convert reference to primitive by unboxing
667 Wrapper w1 = Wrapper.forPrimitiveType(t1);
668 return w1.cast(value, t1);
670 // check contract with caller:
671 Wrapper.asWrapperType(t0).cast(value);
672 Wrapper w1 = Wrapper.forPrimitiveType(t1);
673 return w1.cast(value, t1);
677 Object checkValue(Class<?> T1, Object value)
678 throws ClassCastException
684 T0 = value.getClass();
685 return checkValue(T0, T1, value);
688 /// method handle modification (creation from other method handles)
691 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
692 * Produce a method handle which adapts the type of the
693 * given method handle to a new type, by pairwise argument conversion,
694 * and/or varargs conversion.
695 * The original type and new type must have the same number of
696 * arguments, or else one or both them the must be varargs types.
697 * The resulting method handle is guaranteed to confess a type
698 * which is equal to the desired new type, with any varargs property erased.
700 * If the original type and new type are equal, returns target.
702 * The following conversions are applied as needed both to
703 * arguments and return types. Let T0 and T1 be the differing
704 * new and old parameter types (or old and new return types)
705 * for corresponding values passed by the new and old method types.
707 * If an ordinary (non-varargs) parameter of the new type is
708 * to be boxed in a varargs parameter of the old type of type T1[],
709 * then T1 is the element type of the varargs array.
710 * Otherwise, if a varargs parameter of the new type of type T0[]
711 * is to be spread into one or more outgoing old type parameters,
712 * then T0 is the element type of the
713 * If the new type is varargs and the old type is not, the varargs
714 * argument will be checked and must be a non-null array of exactly
715 * the right length. If there are no parameters in the old type
716 * corresponding to the new varargs parameter, the varargs argument
717 * is also allowed to be null.
719 * Given those types T0, T1, one of the following conversions is applied
722 * <li>If T0 and T1 are references, then a cast to T2 is applied,
723 * where T2 is Object if T1 is an interface, else T1.
724 * (The types do not need to be related in any particular way.
725 * The treatment of interfaces follows the usage of the bytecode verifier.)
726 * <li>If T0 and T1 are primitives, then a Java casting
727 * conversion (JLS 5.5) is applied, if one exists.
728 * <li>If T0 and T1 are primitives and one is boolean,
729 * the boolean is treated as a one-bit unsigned integer.
730 * (This treatment follows the usage of the bytecode verifier.)
731 * A conversion from another primitive type behaves as if
732 * it first converts to byte, and then masks all but the low bit.
733 * <li>If T0 is a primitive and T1 a reference, a boxing
734 * conversion is applied if one exists, possibly followed by
735 * an reference conversion to a superclass.
736 * T1 must be a wrapper class or a supertype of one.
737 * If T1 is a wrapper class, T0 is converted if necessary
738 * to T1's primitive type by one of the preceding conversions.
739 * Otherwise, T0 is boxed, and its wrapper converted to T1.
740 * <li>If T0 is a reference and T1 a primitive, an unboxing
741 * conversion is applied if one exists, possibly preceded by
742 * a reference conversion to a wrapper class.
743 * T0 must be a wrapper class or a supertype of one.
744 * If T0 is a wrapper class, its primitive value is converted
745 * if necessary to T1 by one of the preceding conversions.
746 * Otherwise, T0 is converted directly to the wrapper type for T1,
747 * which is then unboxed.
748 * <li>If T1 is void, any returned value is discarded
749 * <li>If T0 is void and T1 a reference, a null value is introduced.
750 * <li>If T0 is void and T1 a primitive, a zero value is introduced.
752 * @param target the method handle to invoke after arguments are retyped
753 * @param newType the expected type of the new method handle
754 * @return a method handle which delegates to {@code target} after performing
755 * any necessary argument conversions, and arranges for any
756 * necessary return value conversions
757 * @throws WrongMethodTypeException if the conversion cannot be made
760 MethodHandle convertArguments(MethodHandle target, MethodType newType) {
761 MethodType oldType = target.type();
762 if (oldType.equals(newType))
764 MethodHandle res = MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
765 newType, oldType, null);
767 throw newIllegalArgumentException("cannot convert to "+newType+": "+target);
772 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
773 * Produce a method handle which adapts the calling sequence of the
774 * given method handle to a new type, by reordering the arguments.
775 * The resulting method handle is guaranteed to confess a type
776 * which is equal to the desired new type.
778 * The given array controls the reordering.
779 * Call {@code #I} the number of incoming parameters (the value
780 * {@code newType.parameterCount()}, and call {@code #O} the number
781 * of outgoing parameters (the value {@code target.type().parameterCount()}).
782 * Then the length of the reordering array must be {@code #O},
783 * and each element must be a non-negative number less than {@code #I}.
784 * For every {@code N} less than {@code #O}, the {@code N}-th
785 * outgoing argument will be taken from the {@code I}-th incoming
786 * argument, where {@code I} is {@code reorder[N]}.
788 * The reordering array need not specify an actual permutation.
789 * An incoming argument will be duplicated if its index appears
790 * more than once in the array, and an incoming argument will be dropped
791 * if its index does not appear in the array.
793 * Pairwise conversions are applied as needed to arguments and return
794 * values, as with {@link #convertArguments}.
795 * @param target the method handle to invoke after arguments are reordered
796 * @param newType the expected type of the new method handle
797 * @param reorder a string which controls the reordering
798 * @return a method handle which delegates to {@code target} after performing
799 * any necessary argument motion and conversions, and arranges for any
800 * necessary return value conversions
803 MethodHandle permuteArguments(MethodHandle target, MethodType newType, int[] reorder) {
804 MethodType oldType = target.type();
805 checkReorder(reorder, newType, oldType);
806 return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
811 private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
812 if (reorder.length == oldType.parameterCount()) {
813 int limit = newType.parameterCount();
815 for (int i : reorder) {
816 if (i < 0 || i >= limit) {
822 throw newIllegalArgumentException("bad reorder array");
826 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
827 * Produce a method handle which adapts the type of the
828 * given method handle to a new type, by spreading the final argument.
829 * The resulting method handle is guaranteed to confess a type
830 * which is equal to the desired new type.
832 * The final parameter type of the new type must be an array type T[].
833 * This is the type of what is called the <i>spread</i> argument.
834 * All other arguments of the new type are called <i>ordinary</i> arguments.
836 * The ordinary arguments of the new type are pairwise converted
837 * to the initial parameter types of the old type, according to the
838 * rules in {@link #convertArguments}.
839 * Any additional arguments in the old type
840 * are converted from the array element type T,
841 * again according to the rules in {@link #convertArguments}.
842 * The return value is converted according likewise.
844 * The call verifies that the spread argument is in fact an array
845 * of exactly the type length, i.e., the excess number of
846 * arguments in the old type over the ordinary arguments in the new type.
847 * If there are no excess arguments, the spread argument is also
848 * allowed to be null.
849 * @param target the method handle to invoke after the argument is prepended
850 * @param newType the expected type of the new method handle
851 * @return a new method handle which spreads its final argument,
852 * before calling the original method handle
855 MethodHandle spreadArguments(MethodHandle target, MethodType newType) {
856 MethodType oldType = target.type();
857 int inargs = newType.parameterCount();
858 int outargs = oldType.parameterCount();
859 int spreadPos = inargs - 1;
860 int numSpread = (outargs - spreadPos);
861 MethodHandle res = null;
862 if (spreadPos >= 0 && numSpread >= 0) {
863 res = MethodHandleImpl.spreadArguments(IMPL_TOKEN, target, newType, spreadPos);
866 throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType);
872 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
873 * Produce a method handle which adapts the type of the
874 * given method handle to a new type, by collecting a series of
875 * trailing arguments into an array.
876 * The resulting method handle is guaranteed to confess a type
877 * which is equal to the desired new type.
879 * This method is inverse to {@link #spreadArguments}.
880 * The final parameter type of the old type must be an array type T[],
881 * which is the type of what is called the <i>spread</i> argument.
882 * The trailing arguments of the new type which correspond to
883 * the spread argument are all converted to type T and collected
884 * into an array before the original method is called.
886 * ISSUE: Unify this with combineArguments. CollectArguments
887 * is combineArguments with (a) new Object[]{...} as a combiner,
888 * and (b) the combined arguments dropped, in favor of the combined result.
889 * @param target the method handle to invoke after the argument is prepended
890 * @param newType the expected type of the new method handle
891 * @return a new method handle which collects some trailings argument
892 * into an array, before calling the original method handle
895 MethodHandle collectArguments(MethodHandle target, MethodType newType) {
896 MethodType oldType = target.type();
897 int inargs = newType.parameterCount();
898 int outargs = oldType.parameterCount();
899 int collectPos = outargs - 1;
900 int numCollect = (inargs - collectPos);
901 if (collectPos < 0 || numCollect < 0)
902 throw newIllegalArgumentException("wrong number of arguments");
903 return MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos);
907 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
908 * Produce a method handle which calls the original method handle,
909 * after inserting the given argument at the given position.
910 * The type of the new method handle will drop the corresponding argument
911 * type from the original handle's type.
913 * The given argument object must match the dropped argument type.
914 * If the dropped argument type is a primitive, the argument object
915 * must be a wrapper, and is unboxed to produce the primitive.
917 * The <i>pos</i> may range between zero and <i>N</i> (inclusively),
918 * where <i>N</i> is the number of argument types in <i>target</i>,
919 * meaning to insert the new argument as the first or last (respectively),
920 * or somewhere in between.
921 * @param target the method handle to invoke after the argument is inserted
922 * @param pos where to insert the argument (zero for the first)
923 * @param value the argument to insert
924 * @return a new method handle which inserts an additional argument,
925 * before calling the original method handle
928 MethodHandle insertArgument(MethodHandle target, int pos, Object value) {
929 MethodType oldType = target.type();
930 ArrayList<Class<?>> ptypes =
931 new ArrayList<Class<?>>(oldType.parameterList());
932 int outargs = oldType.parameterCount();
933 int inargs = outargs - 1;
934 if (pos < 0 || pos >= outargs)
935 throw newIllegalArgumentException("no argument type to append");
936 Class<?> valueType = ptypes.remove(pos);
937 value = checkValue(valueType, value);
938 if (pos == 0 && !valueType.isPrimitive()) {
939 // At least for now, make bound method handles a special case.
940 // This lets us get by with minimal JVM support, at the expense
941 // of generating signature-specific adapters as Java bytecodes.
942 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, target, value);
943 if (bmh != null) return bmh;
944 // else fall through to general adapter machinery
946 return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value);
950 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
951 * Produce a method handle which calls the original method handle,
952 * after dropping the given argument(s) at the given position.
953 * The type of the new method handle will insert the given argument
954 * type(s), at that position, into the original handle's type.
956 * The <i>pos</i> may range between zero and <i>N-1</i>,
957 * where <i>N</i> is the number of argument types in <i>target</i>,
958 * meaning to drop the first or last argument (respectively),
959 * or an argument somewhere in between.
960 * @param target the method handle to invoke after the argument is dropped
961 * @param valueTypes the type(s) of the argument to drop
962 * @param pos which argument to drop (zero for the first)
963 * @return a new method handle which drops an argument of the given type,
964 * before calling the original method handle
967 MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
968 if (valueTypes.length == 0) return target;
969 MethodType oldType = target.type();
970 int outargs = oldType.parameterCount();
971 int inargs = outargs + valueTypes.length;
972 if (pos < 0 || pos >= inargs)
973 throw newIllegalArgumentException("no argument type to remove");
974 ArrayList<Class<?>> ptypes =
975 new ArrayList<Class<?>>(oldType.parameterList());
976 ptypes.addAll(pos, Arrays.asList(valueTypes));
977 MethodType newType = MethodType.make(oldType.returnType(), ptypes);
978 return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos);
982 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
983 * Make a method handle which adapts a target method handle,
984 * by guarding it with a test, a boolean-valued method handle.
985 * If the guard fails, a fallback handle is called instead.
986 * All three method handles must have the same corresponding
987 * argument and return types, except that the return type
988 * of the test must be boolean.
989 * <p> Here is pseudocode for the resulting adapter:
992 * boolean test(A...);
995 * T adapter(A... a) {
997 * return target(a...);
999 * return fallback(a...);
1001 * </pre></blockquote>
1002 * @param test method handle used for test, must return boolean
1003 * @param target method handle to call if test passes
1004 * @param fallback method handle to call if test fails
1005 * @return method handle which incorporates the specified if/then/else logic
1006 * @throws IllegalArgumentException if {@code test} does not return boolean,
1007 * or if all three method types do not match (with the return
1008 * type of {@code test} changed to match that of {@code target}).
1011 MethodHandle guardWithTest(MethodHandle test,
1012 MethodHandle target,
1013 MethodHandle fallback) {
1014 if (target.type() != fallback.type())
1015 throw newIllegalArgumentException("target and fallback types do not match");
1016 if (target.type().changeReturnType(boolean.class) != test.type())
1017 throw newIllegalArgumentException("target and test types do not match");
1019 MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type());
1020 static MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) {
1023 static MethodHandle compose(MethodHandle f, MethodHandle g) {
1024 Class<?> initargs = g.type().parameterArray();
1025 f = dropArguments(f, 1, initargs); // ignore 2nd copy of args
1026 return combineArguments(f, g);
1028 // choose = \z.(z ? target : fallback)
1029 MethodHandle choose = findVirtual(MethodHandles.class, "choose",
1030 MethodType.make(boolean.class, MethodHandle.class, MethodHandle.class));
1031 choose = appendArgument(choose, target);
1032 choose = appendArgument(choose, fallback);
1033 MethodHandle dispatch = compose(choose, test);
1034 // dispatch = \(a...).(test(a...) ? target : fallback)
1035 return combineArguments(invoke, dispatch, 0);
1036 // return \(a...).((test(a...) ? target : fallback).invoke(a...))
1038 return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
1042 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
1043 * Adapt a target method handle {@code target} by first processing
1044 * its arguments, and then calling the target.
1045 * The initial processing is performed by a second method handle, the {@code combiner}.
1046 * After this, control passes to the {@code target}, with the same arguments.
1048 * The return value of the {@code combiner} is inserted into the argument list
1049 * for the {@code target} at the indicated position {@code pos}, if it is non-negative.
1050 * Except for this inserted argument (if any), the argument types of
1051 * the target {@code target} and the {@code combiner} must be identical.
1053 * (Note that {@link #dropArguments} can be used to remove any arguments
1054 * that either the {@code combiner} or {@code target} does not wish to receive.)
1056 * The combiner handle must have the same argument types as the
1057 * target handle, but must return {@link MethodHandle} instead of
1058 * the ultimate return type. The returned method handle, in turn,
1059 * is required to have exactly the given final method type.
1060 * <p> Here is pseudocode for the resulting adapter:
1062 * signature V(A[pos]..., B...);
1063 * signature T(A[pos]..., V, B...);
1064 * T target(A... a, V v, B... b);
1065 * V combiner(A..., B...);
1066 * T adapter(A... a, B... b) {
1067 * V v = combiner(a..., b...);
1068 * return target(a..., v, b...);
1070 * </pre></blockquote>
1071 * @param target the method handle to invoke after arguments are combined
1072 * @param pos where the return value of {@code combiner} is to
1073 * be inserted as an argument to {@code target}
1074 * @param combiner method handle to call initially on the incoming arguments
1075 * @return method handle which incorporates the specified dispatch logic
1076 * @throws IllegalArgumentException if {@code combiner} does not itself
1077 * return either void or the {@code pos}-th argument of {@code target},
1078 * or does not have the same argument types as {@code target}
1079 * (minus the inserted argument)
1082 MethodHandle combineArguments(MethodHandle target, int pos, MethodHandle combiner) {
1083 MethodType mhType = target.type();
1084 Class<?> combineType = combiner.type().returnType();
1085 MethodType incomingArgs;
1087 // No inserted argument; target & combiner must have same argument types.
1088 incomingArgs = mhType;
1089 if (!incomingArgs.changeReturnType(combineType).equals(combiner.type()))
1090 throw newIllegalArgumentException("target and combiner types do not match");
1092 // Inserted argument.
1093 if (pos >= mhType.parameterCount()
1094 || mhType.parameterType(pos) != combineType)
1095 throw newIllegalArgumentException("inserted combiner argument does not match target");
1096 incomingArgs = mhType.dropParameterType(pos);
1098 if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) {
1099 throw newIllegalArgumentException("target and combiner types do not match");
1101 return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos);