1 /*
2 * Copyright 2008-2009 Sun Microsystems, Inc. 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. 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.
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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.dyn;
27
28 import impl.java.dyn.Access;
29 import impl.java.dyn.MemberName;
30 import impl.java.dyn.MethodHandleImpl;
31 import impl.java.dyn.util.MethodHandleInvoker;
32 import impl.java.dyn.util.VerifyAccess;
33 import impl.java.dyn.util.Wrappers;
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.reflect.Reflection;
40 import static impl.java.dyn.MemberName.newIllegalArgumentException;
41 import static impl.java.dyn.MemberName.newNoAccessException;
42
43 /**
44 * Fundamental operations and utilities for MethodHandle.
45 * <p>
46 * <em>API Note:</em> The matching of method types in this API cannot
47 * be completely checked by Java's generic type system for three reasons:
48 * <ol>
49 * <li>Method types range over all possible arities,
50 * from no arguments to an arbitrary number of arguments.
51 * Generics are not variadic, and so cannot represent this.</li>
52 * <li>Method types can specify arguments of primitive types,
53 * which Java generic types cannot range over.</li>
54 * <li>Method types can optionally specify varargs (ellipsis).</li>
55 * </ol>
56 * @author John Rose, JSR 292 EG
57 */
58 public class MethodHandles {
59
60 private MethodHandles() { } // do not instantiate
61
62 private static final Access IMPL_TOKEN = Access.getToken();
63 private static final MemberName.Factory IMPL_LOOKUP = MemberName.getFactory(IMPL_TOKEN);
64
65 //// Method handle creation from ordinary methods.
66
67 /**
68 * Produce a method handle for a static method.
69 * The type of the method handle will be that of the method.
70 * The method and all its argument types must be accessible to the caller.
71 * If the method's class has not yet been initialized, that is done
72 * immediately, before the method handle is returned.
73 * @param defc the class from which the method is accessed
74 * @param name the name of the method
75 * @param type the type of the method
76 * @return the desired method handle, or null if no such method exists
77 * @exception SecurityException <em>TBD</em>
78 * @exception NoAccessException if access checking fails
79 */
80 public static
81 MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException {
82 Class<?> caller = Reflection.getCallerClass(2);
83 MemberName method = IMPL_LOOKUP.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, caller);
84 checkStatic(true, method, caller);
85 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, caller);
86 }
87
88 private static void checkStatic(boolean wantStatic, MemberName m, Class<?> caller) {
89 if (wantStatic != m.isStatic()) {
90 String message = wantStatic ? "expected a static method" : "expected a non-static method";
91 throw newNoAccessException(message, m, caller);
92 }
93 }
94
95 /**
96 * Produce a method handle for a virtual method.
97 * The type of the method handle will be that of the method,
98 * with the receiver type ({@code defc}) prepended.
99 * The method and all its argument types must be accessible to the caller.
100 * <p>
101 * When called, the handle will treat the first argument as a receiver
102 * and dispatch on the receiver's type to determine which method
103 * implementation to enter.
104 * (The dispatching action is identical with that performed by an
105 * {@code invokevirtual} or {@code invokeinterface} instruction.)
106 * @param defc the class or interface from which the method is accessed
107 * @param name the name of the method
108 * @param type the type of the method, with the receiver argument omitted
109 * @return the desired method handle, or null if no such method exists
110 * @exception SecurityException <em>TBD</em>
111 * @exception NoAccessException if access checking fails
112 */
113 public static
114 MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException {
115 Class<?> caller = Reflection.getCallerClass(2);
116 MemberName method = IMPL_LOOKUP.resolveOrFail(new MemberName(defc, name, type), true, caller);
117 checkStatic(false, method, caller);
118 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, caller);
119 }
120
121 /**
122 * Produce an early-bound method handle for a virtual method,
123 * or a handle for a constructor, as if called from an {@code invokespecial}
124 * instruction from {@code caller}.
125 * The type of the method handle will be that of the method or constructor,
126 * with a suitably restricted receiver type (such as {@code caller}) prepended.
127 * The method or constructor and all its argument types must be accessible
128 * to the caller.
129 * <p>
130 * When called, the handle will treat the first argument as a receiver,
131 * but will not dispatch on the receiver's type.
132 * (This direct invocation action is identical with that performed by an
133 * {@code invokespecial} instruction.)
134 * <p>
135 * If the explicitly specified caller class is not identical with the actual
136 * caller of {@code findSpecial}, a security check TBD is performed.
137 * @param defc the class or interface from which the method is accessed
138 * @param name the name of the method, or "<init>" for a constructor
139 * @param type the type of the method, with the receiver argument omitted
140 * @param specialCaller the proposed calling class to perform the {@code invokespecial}
141 * @return the desired method handle, or null if no such method exists
142 * @exception SecurityException <em>TBD</em>
143 * @exception NoAccessException if access checking fails
144 */
145 public static
146 MethodHandle findSpecial(Class<?> defc, String name, MethodType type,
147 Class<?> specialCaller) throws NoAccessException {
148 Class<?> caller = Reflection.getCallerClass(2);
149 checkSpecialCaller(specialCaller, caller);
150 MemberName method = IMPL_LOOKUP.resolveOrFail(new MemberName(defc, name, type), false, specialCaller);
151 checkStatic(false, method, caller);
152 if (name.equals("<init>")) {
153 if (defc != specialCaller)
154 throw newNoAccessException("constructor must be local to caller", method, caller);
155 } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) {
156 throw newNoAccessException("method must be in a superclass of caller", method, caller);
157 }
158 return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
159 }
160
161 /**
162 * Produce an early-bound method handle for a non-static method.
163 * The receiver must have a supertype {@code defc} in which a method
164 * of the given name and type is accessible to the caller.
165 * The method and all its argument types must be accessible to the caller.
166 * The type of the method handle will be that of the method.
167 * The given receiver will be bound into the method handle.
168 * <p>
169 * Equivalent to the following expression:
170 * <code>
171 * {@link #insertArgument}({@link #findVirtual}(defc, name, type), receiver)
172 * </code>
173 * @param receiver the object from which the method is accessed
174 * @param name the name of the method
175 * @param type the type of the method, with the receiver argument omitted
176 * @return the desired method handle, or null if no such method exists
177 * @exception SecurityException <em>TBD</em>
178 * @exception NoAccessException if access checking fails
179 */
180 public static
181 MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
182 Class<?> caller = Reflection.getCallerClass(2);
183 Class<? extends Object> rcvc = receiver.getClass(); // may get NPE
184 MemberName reference = new MemberName(rcvc, name, type);
185 MemberName method = IMPL_LOOKUP.resolveOrFail(reference, true, caller);
186 checkStatic(false, method, caller);
187 MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, caller);
188 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver);
189 if (bmh == null)
190 throw newNoAccessException(method, caller);
191 return bmh;
192 }
193
194 /**
195 * Make a direct method handle to <i>m</i>, if the current caller has permission.
196 * If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
197 * If <i>m</i> is virtual, overriding is respected on every call.
198 * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
199 * The type of the method handle will be that of the method,
200 * with the receiver type prepended (but only if it is non-static).
201 * If the method's {@code accessible} flag is not set,
202 * access checking is performed immediately on behalf of the caller.
203 * If <i>m</i> is not public, do not share the resulting handle with untrusted callers.
204 * @param m the reflected method
205 * @return a method handle which can invoke the reflected method
206 * @exception NoAccessException if access checking fails
207 */
208 public static
209 MethodHandle unreflect(Method m) throws NoAccessException {
210 Class<?> caller = Reflection.getCallerClass(2);
211 return unreflect(new MemberName(m), m.isAccessible(), true, caller);
212 }
213
214 /**
215 * Produce a method handle for a reflected method.
216 * It will bypass checks for overriding methods on the receiver,
217 * as if by the {@code invokespecial} instruction.
218 * The type of the method handle will be that of the method,
219 * with the receiver type prepended.
220 * If the method's {@code accessible} flag is not set,
221 * access checking is performed immediately on behalf of the caller,
222 * as if {@code invokespecial} instruction were being linked.
223 * @param m the reflected method
224 * @return a method handle which can invoke the reflected method
225 * @exception NoAccessException if access checking fails
226 */
227 public static
228 MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException {
229 Class<?> caller = Reflection.getCallerClass(2);
230 checkSpecialCaller(specialCaller, caller);
231 MemberName mname = new MemberName(m);
232 checkStatic(false, mname, caller);
233 return unreflect(mname, m.isAccessible(), false, specialCaller);
234 }
235
236 // /**
237 // * Produce a method handle for a reflected constructor.
238 // * It will allow direct access to the constructor,
239 // * as if by the {@code invokespecial} instruction.
240 // * The type of the method handle will be that of the method,
241 // * with the receiver type prepended.
242 // * If the constructor's {@code accessible} flag is not set,
243 // * access checking is performed immediately on behalf of the caller,
244 // * as if {@code invokespecial} instruction were being linked.
245 // * @param ctor the reflected constructor
246 // * @param specialCaller the proposed calling class to perform the {@code invokespecial}
247 // * @return a method handle which can invoke the reflected constructor
248 // * @exception NoAccessException if access checking fails
249 // */
250 // public static
251 // MethodHandle unreflectSpecial(Constructor ctor, Class<?> specialCaller) throws NoAccessException {
252 // Class<?> caller = Reflection.getCallerClass(2);
253 // checkSpecialCaller(specialCaller, caller);
254 // MemberName m = new MemberName(ctor);
255 // checkStatic(false, m, caller);
256 // return unreflect(m, ctor.isAccessible(), false, specialCaller);
257 // }
258
259 private static
260 void checkSpecialCaller(Class<?> specialCaller, Class<?> caller) {
261 if (caller != null && !VerifyAccess.isSamePackageMember(specialCaller, caller))
262 throw newNoAccessException("no private access", new MemberName(specialCaller), caller);
263 }
264
265 // Helper for creating handles on reflected methods and constructors.
266 private static
267 MethodHandle unreflect(MemberName m, boolean isAccessible, boolean doDispatch, Class<?> caller) {
268 MethodType mtype = m.getInvocationType();
269 Class<?> defc = m.getDeclaringClass();
270 int mods = m.getModifiers();
271 if (m.isStatic()) {
272 if (!isAccessible &&
273 VerifyAccess.isAccessible(defc, mods, false, caller) == null)
274 throw newNoAccessException(m, caller);
275 } else {
276 Class<?> constraint;
277 if (isAccessible) {
278 // abbreviated access check for "unlocked" method
279 constraint = doDispatch ? defc : caller;
280 } else {
281 constraint = VerifyAccess.isAccessible(defc, mods, doDispatch, caller);
282 }
283 if (constraint != defc && !constraint.isAssignableFrom(defc)) {
284 if (!defc.isAssignableFrom(constraint))
285 throw newNoAccessException("receiver must be in caller class", m, caller);
286 mtype = mtype.changeParameterType(0, constraint);
287 }
288 }
289 return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, caller);
290 }
291
292 /**
293 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
294 * Produce a method handle giving read access to a reflected field.
295 * The type of the method handle will have a return type of the field's
296 * value type. Its sole argument will be the field's containing class
297 * (but only if it is non-static).
298 * If the method's {@code accessible} flag is not set,
299 * access checking is performed immediately on behalf of the caller.
300 * @param f the reflected field
301 * @return a method handle which can load values from the reflected field
302 * @exception NoAccessException if access checking fails
303 */
304 public static
305 MethodHandle unreflectGetter(Field f) throws NoAccessException {
306 Class<?> caller = Reflection.getCallerClass(2);
307 return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), false, (Class)caller);
308 }
309
310 /**
311 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
312 * Produce a method handle giving write access to a reflected field.
313 * The type of the method handle will have a void return type.
314 * Its last argument will be the field's value type.
315 * Its other argument will be the field's containing class
316 * (but only if it is non-static).
317 * If the method's {@code accessible} flag is not set,
318 * access checking is performed immediately on behalf of the caller.
319 * @param f the reflected field
320 * @return a method handle which can store values into the reflected field
321 * @exception NoAccessException if access checking fails
322 */
323 public static
324 MethodHandle unreflectSetter(Field f) throws NoAccessException {
325 Class<?> caller = Reflection.getCallerClass(2);
326 return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), true, (Class)caller);
327 }
328
329 /**
330 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
331 * Produce a method handle giving read access to elements of an array.
332 * The type of the method handle will have a return type of the array's
333 * element type. Its first argument will be the array type,
334 * and the second will be {@code int}.
335 * @param arrayClass an array type
336 * @return a method handle which can load values from the given array type
337 * @throws IllegalArgumentException if arrayClass is not an array type
338 */
339 public static
340 MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
341 Class<?> caller = Reflection.getCallerClass(2);
342 return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false, (Class)caller);
343 }
344
345 /**
346 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
347 * Produce a method handle giving write access to elements of an array.
348 * The type of the method handle will have a void return type.
349 * Its last argument will be the array's element type.
350 * The first and second arguments will be the array type and int.
351 * @return a method handle which can store values into the array type
352 * @throws IllegalArgumentException if arrayClass is not an array type
353 */
354 public static
355 MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
356 Class<?> caller = Reflection.getCallerClass(2);
357 return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true, (Class)caller);
358 }
359
360
361 /// method handle invocation (reflective style)
362
363 /**
364 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
365 * Call the {@code invoke} method of a given method handle.
366 * The given arguments must exactly match the parameter types of the method handle.
367 * <em>TBD: Fill in the details.</em>
368 * No conversions are performed except reference casting and unboxing of primitives.
369 * @param target method handle to invoke
370 * @param arguments arguments to pass to the target (with any primitives wrapped)
371 * @return the result of the method (with any primitive wrapped)
372 */
373 public static
374 Object invoke(MethodHandle target, Object... arguments) {
375 // TO DO: Remove this checking logic; must be part of the invoker anyway.
376 int length = arguments.length;
377 MethodType type = target.type();
378 if (type.parameterCount() != length)
379 throw new WrongMethodTypeException("wrong number of arguments");
380 for (int i = 0; i < length; i++) {
381 Object argument = arguments[i];
382 Class<?> ptype = type.parameterType(i);
383 if (ptype.isPrimitive()) {
384 argument.getClass(); // provoke NPE if null
385 ptype = Wrappers.asWrapperType(ptype);
386 } else if (ptype.isInterface()) {
387 ptype = Object.class; // no check
388 }
389 if (ptype != Object.class) {
390 ptype.cast(argument);
391 }
392 }
393 // End of checking logic.
394 return MethodHandleInvoker.make(target.type()).invoke(target, arguments);
395 }
396
397 /**
398 * <em>WORK IN PROGRESS:</em>
399 * Perform value checking, exactly as if for an adapted method handle.
400 * It is assumed that the given value is either null, of type T0,
401 * or (if T0 is primitive) of the wrapper type corresponding to T0.
402 * The following checks and conversions are made:
403 * <ul>
404 * <li>If T0 and T1 are references, then a cast to T1 is applied.
405 * (The types do not need to be related in any particular way.)
406 * <li>If T0 and T1 are primitives, then a widening or narrowing
407 * conversion is applied, if one exists.
408 * <li>If T0 is a primitive and T1 a reference, and
409 * T0 has a wrapper type TW, a boxing conversion to TW is applied,
410 * possibly followed by a reference conversion.
411 * T1 must be TW or a supertype.
412 * <li>If T0 is a reference and T1 a primitive, and
413 * T1 has a wrapper type TW, an unboxing conversion is applied,
414 * possibly preceded by a reference conversion.
415 * T0 must be TW or a supertype.
416 * <li>If T1 is void, the return value is discarded
417 * <li>If T0 is void and T1 a reference, a null value is introduced.
418 * <li>If T0 is void and T1 a primitive, a zero value is introduced.
419 * </ul>
420 * If the value is discarded, null will be returned.
421 * @param valueType
422 * @param value
423 * @return the value, converted if necessary
424 * @throws java.lang.ClassCastException if a cast fails
425 */
426 static
427 Object checkValue(Class<?> T0, Class<?> T1, Object value)
428 throws ClassCastException
429 {
430 if (T0 == T1) {
431 // no conversion needed
432 return value;
433 }
434 boolean prim0 = T0.isPrimitive(), prim1 = T1.isPrimitive();
435 Class<?> TW;
436 if (!prim0) {
437 if (!prim1) {
438 return T1.cast(T0.cast(value));
439 }
440 // convert reference to primitive by unboxing
441 TW = Wrappers.asWrapperType(T0);
442 return T1.cast(TW.cast(value));
443 }
444 if (!prim1) {
445 // convert primitive to reference type by boxing
446 TW = Wrappers.asWrapperType(T1);
447 return TW.cast(T0.cast(value));
448 }
449 // convert primitive to primitive; this requires a real value change
450 if (value == null)
451 return Wrappers.zeroValue(T1);
452 // convert non-Number primitives to Integer:
453 if (value instanceof Character) {
454 char ch = (char) (Character) value;
455 value = Integer.valueOf(ch);
456 if (T1 == Integer.class)
457 return value;
458 } else if (value instanceof Boolean) {
459 boolean z = (boolean) (Boolean) value;
460 value = Integer.valueOf(z ? 1 : 0);
461 if (T1 == Integer.class)
462 return value;
463 }
464 Number numval = (Number) value;
465 switch (Wrappers.basicTypeChar(T1)) {
466 case 'Z': return (numval.intValue() != 0);
467 case 'B': return numval.byteValue();
468 case 'C': return (char) numval.intValue();
469 case 'S': return numval.shortValue();
470 case 'I': return numval.intValue();
471 case 'J': return numval.longValue();
472 case 'F': return numval.floatValue();
473 case 'D': return numval.doubleValue();
474 }
475 return null;
476 }
477
478 static
479 Object checkValue(Class<?> T1, Object value)
480 throws ClassCastException
481 {
482 Class<?> T0;
483 if (value == null)
484 T0 = Object.class;
485 else
486 T0 = value.getClass();
487 return checkValue(T0, T1, value);
488 }
489
490 /// method handle modification (creation from other method handles)
491
492 /**
493 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
494 * Produce a method handle which adapts the type of the
495 * given method handle to a new type, by pairwise argument conversion,
496 * and/or varargs conversion.
497 * The original type and new type must have the same number of
498 * arguments, or else one or both them the must be varargs types.
499 * The resulting method handle is guaranteed to confess a type
500 * which is equal to the desired new type, with any varargs property erased.
501 * <p>
502 * If the original type and new type are equal, returns target.
503 * <p>
504 * The following conversions are applied as needed both to
505 * arguments and return types. Let T0 and T1 be the differing
506 * new and old parameter types (or old and new return types)
507 * for corresponding values passed by the new and old method types.
508 * <p>
509 * If an ordinary (non-varargs) parameter of the new type is
510 * to be boxed in a varargs parameter of the old type of type T1[],
511 * then T1 is the element type of the varargs array.
512 * Otherwise, if a varargs parameter of the new type of type T0[]
513 * is to be spread into one or more outgoing old type parameters,
514 * then T0 is the element type of the
515 * If the new type is varargs and the old type is not, the varargs
516 * argument will be checked and must be a non-null array of exactly
517 * the right length. If there are no parameters in the old type
518 * corresponding to the new varargs parameter, the varargs argument
519 * is also allowed to be null.
520 * <p>
521 * Given those types T0, T1, one of the following conversions is applied
522 * if possible:
523 * <ul>
524 * <li>If T0 and T1 are references, then a cast to T2 is applied,
525 * where T2 is Object if T1 is an interface, else T1.
526 * (The types do not need to be related in any particular way.
527 * The treatment of interfaces follows the usage of the bytecode verifier.)
528 * <li>If T0 and T1 are primitives, then a Java casting
529 * conversion (JLS 5.5) is applied, if one exists.
530 * <li>If T0 and T1 are primitives and one is boolean,
531 * the boolean is treated as a one-bit unsigned integer.
532 * (This treatment follows the usage of the bytecode verifier.)
533 * A conversion from another primitive type behaves as if
534 * it first converts to byte, and then masks all but the low bit.
535 * <li>If T0 is a primitive and T1 a reference, a boxing
536 * conversion is applied if one exists, possibly followed by
537 * an reference conversion to a superclass.
538 * T1 must be a wrapper class or a supertype of one.
539 * If T1 is a wrapper class, T0 is converted if necessary
540 * to T1's primitive type by one of the preceding conversions.
541 * Otherwise, T0 is boxed, and its wrapper converted to T1.
542 * <li>If T0 is a reference and T1 a primitive, an unboxing
543 * conversion is applied if one exists, possibly preceded by
544 * a reference conversion to a wrapper class.
545 * T0 must be a wrapper class or a supertype of one.
546 * If T0 is a wrapper class, its primitive value is converted
547 * if necessary to T1 by one of the preceding conversions.
548 * Otherwise, T0 is converted directly to the wrapper type for T1,
549 * which is then unboxed.
550 * <li>If T1 is void, any returned value is discarded
551 * <li>If T0 is void and T1 a reference, a null value is introduced.
552 * <li>If T0 is void and T1 a primitive, a zero value is introduced.
553 * </ul>
554 * @param target the method handle to invoke after arguments are retyped
555 * @param newType the expected type of the new method handle
556 * @return a method handle which delegates to {@code target} after performing
557 * any necessary argument conversions, and arranges for any
558 * necessary return value conversions
559 */
560 public static
561 MethodHandle convertArguments(MethodHandle target, MethodType newType) {
562 MethodType oldType = target.type();
563 if (oldType.equals(newType))
564 return target;
565 return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
566 newType, target.type(), null);
567 }
568
569 /**
570 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
571 * Produce a method handle which adapts the calling sequence of the
572 * given method handle to a new type, by reordering the arguments.
573 * Duplication and omission is allowed.
574 * The resulting method handle is guaranteed to confess a type
575 * which is equal to the desired new type.
576 * <p>
577 * The given permutation string controls the reordering.
578 * The characters of the string are treated as small integers.
579 * All the characters must be in the range zero (i.e., '\0') to
580 * the number of incoming arguments (the parameter count of the new type).
581 * The length of the string must be equal to the number of outgoing
582 * parameters (the parameter count of the original method handle's type).
583 * If the n-th character of the string denotes the integer k,
584 * then the n-th incoming argument becomes the k-th outgoing argument.
585 * <p>
586 * Pairwise conversions are applied as needed to arguments and return
587 * values, as with {@link #convertArguments}.
588 * @param target the method handle to invoke after arguments are reordered
589 * @param newType the expected type of the new method handle
590 * @param permutation a string which controls the reordering
591 * @return a method handle which delegates to {@code target} after performing
592 * any necessary argument motion and conversions, and arranges for any
593 * necessary return value conversions
594 */
595 public static
596 MethodHandle permuteArguments(MethodHandle target, MethodType newType, String permutation) {
597 MethodType oldType = target.type();
598 return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
599 newType, target.type(),
600 permutation);
601 }
602
603 /**
604 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
605 * Produce a method handle which adapts the type of the
606 * given method handle to a new type, by spreading the final argument.
607 * The resulting method handle is guaranteed to confess a type
608 * which is equal to the desired new type.
609 * <p>
610 * The final parameter type of the new type must be an array type T[].
611 * This is the type of what is called the <i>spread</i> argument.
612 * All other arguments of the new type are called <i>ordinary</i> arguments.
613 * <p>
614 * The ordinary arguments of the new type are pairwise converted
615 * to the initial parameter types of the old type, according to the
616 * rules in {@link #convertArguments}.
617 * Any additional arguments in the old type
618 * are converted from the array element type T,
619 * again according to the rules in {@link #convertArguments}.
620 * The return value is converted according likewise.
621 * <p>
622 * The call verifies that the spread argument is in fact an array
623 * of exactly the type length, i.e., the excess number of
624 * arguments in the old type over the ordinary arguments in the new type.
625 * If there are no excess arguments, the spread argument is also
626 * allowed to be null.
627 * @param target the method handle to invoke after the argument is prepended
628 * @param newType the expected type of the new method handle
629 * @return a new method handle which spreads its final argument,
630 * before calling the original method handle
631 */
632 public static
633 MethodHandle spreadArguments(MethodHandle target, MethodType newType) {
634 MethodType oldType = target.type();
635 int inargs = newType.parameterCount();
636 int outargs = oldType.parameterCount();
637 int spreadPos = inargs - 1;
638 int numSpread = (outargs - spreadPos);
639 if (spreadPos < 0 || numSpread < 0)
640 throw newIllegalArgumentException("wrong number of arguments");
641 newType = newType.changeVarArgs(true);
642 return MethodHandleImpl.convertArguments(IMPL_TOKEN, target, newType, oldType, null);
643 }
644
645 /**
646 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
647 * Produce a method handle which adapts the type of the
648 * given method handle to a new type, by collecting a series of
649 * trailing arguments into an array.
650 * The resulting method handle is guaranteed to confess a type
651 * which is equal to the desired new type.
652 * <p>
653 * This method is inverse to {@link #spreadArguments}.
654 * The final parameter type of the old type must be an array type T[],
655 * which is the type of what is called the <i>spread</i> argument.
656 * The trailing arguments of the new type which correspond to
657 * the spread argument are all converted to type T and collected
658 * into an array before the original method is called.
659 * @param target the method handle to invoke after the argument is prepended
660 * @param newType the expected type of the new method handle
661 * @return a new method handle which collects some trailings argument
662 * into an array, before calling the original method handle
663 */
664 public static
665 MethodHandle collectArguments(MethodHandle target, MethodType newType) {
666 MethodType oldType = target.type();
667 int inargs = newType.parameterCount();
668 int outargs = oldType.parameterCount();
669 int collectPos = outargs - 1;
670 int numCollect = (inargs - collectPos);
671 if (collectPos < 0 || numCollect < 0)
672 throw newIllegalArgumentException("wrong number of arguments");
673 oldType = oldType.changeVarArgs(true);
674 return MethodHandleImpl.convertArguments(IMPL_TOKEN, target, newType, oldType, null);
675 }
676
677 /**
678 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
679 * Produce a method handle which calls the original method handle,
680 * after inserting the given argument as the first argument.
681 * The type of the new method handle will drop the first argument
682 * type from the original handle's type.
683 * <p>
684 * Equivalent to {@code insertArgument(target, value, 0)}.
685 */
686 public static
687 MethodHandle insertArgument(MethodHandle target, Object value) {
688 return insertArgument(target, value, 0);
689 }
690
691 /**
692 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
693 * Produce a method handle which calls the original method handle,
694 * after appending the given argument as the final argument.
695 * The type of the new method handle will drop the last argument
696 * type from the original handle's type.
697 * <p>
698 * Equivalent to {@code insertArgument(target, value, N)},
699 * where <i>N</i> is the number of arguments to <i>target</i>.
700 */
701 public static
702 MethodHandle appendArgument(MethodHandle target, Object value) {
703 return insertArgument(target, value, target.type().parameterCount());
704 }
705
706 /**
707 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
708 * Produce a method handle which calls the original method handle,
709 * after inserting the given argument at the given position.
710 * The type of the new method handle will drop the corresponding argument
711 * type from the original handle's type.
712 * <p>
713 * The given argument object must match the dropped argument type.
714 * If the dropped argument type is a primitive, the argument object
715 * must be a wrapper, and is unboxed to produce the primitive.
716 * <p>
717 * The <i>pos</i> may range between zero and <i>N</i> (inclusively),
718 * where <i>N</i> is the number of argument types in <i>target</i>,
719 * meaning to insert the new argument as the first or last (respectively),
720 * or somewhere in between.
721 * @param target the method handle to invoke after the argument is inserted
722 * @param value the argument to insert
723 * @param pos where to insert the argument (zero for the first)
724 * @return a new method handle which inserts an additional argument,
725 * before calling the original method handle
726 */
727 public static
728 MethodHandle insertArgument(MethodHandle target, Object value, int pos) {
729 MethodType oldType = target.type();
730 ArrayList<Class<?>> ptypes =
731 new ArrayList<Class<?>>(oldType.parameterList());
732 int outargs = oldType.parameterCount();
733 int inargs = outargs - 1;
734 if (pos < 0 || pos >= outargs)
735 throw newIllegalArgumentException("no argument type to append");
736 Class<?> valueType = ptypes.remove(pos);
737 value = checkValue(valueType, value);
738 if (pos == 0 && !valueType.isPrimitive()) {
739 // At least for now, make bound method handles a special case.
740 // This lets us get by with minimal JVM support, at the expense
741 // of generating signature-specific adapters as Java bytecodes.
742 MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, target, value);
743 if (bmh != null) return bmh;
744 // else fall through to general adapter machinery
745 }
746 return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value);
747 }
748
749 /**
750 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
751 * Produce a method handle which calls the original method handle,
752 * after dropping the given argument(s) at the given position.
753 * The type of the new method handle will insert the given argument
754 * type(s), at that position, into the original handle's type.
755 * <p>
756 * The <i>pos</i> may range between zero and <i>N-1</i>,
757 * where <i>N</i> is the number of argument types in <i>target</i>,
758 * meaning to drop the first or last argument (respectively),
759 * or an argument somewhere in between.
760 * @param target the method handle to invoke after the argument is dropped
761 * @param valueTypes the type(s) of the argument to drop
762 * @param pos which argument to drop (zero for the first)
763 * @return a new method handle which drops an argument of the given type,
764 * before calling the original method handle
765 */
766 public static
767 MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
768 if (valueTypes.length == 0) return target;
769 MethodType oldType = target.type();
770 int outargs = oldType.parameterCount();
771 int inargs = outargs + valueTypes.length;
772 if (pos < 0 || pos >= inargs)
773 throw newIllegalArgumentException("no argument type to remove");
774 ArrayList<Class<?>> ptypes =
775 new ArrayList<Class<?>>(oldType.parameterList());
776 ptypes.addAll(pos, Arrays.asList(valueTypes));
777 MethodType newType = MethodType.make(oldType.returnType(), ptypes);
778 return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos);
779 }
780
781 /**
782 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
783 * Make a method handle which adapts a target method handle,
784 * by guarding it with a test, a boolean-valued method handle.
785 * If the guard fails, a fallback handle is called instead.
786 * All three method handles must have the same corresponding
787 * argument and return types, except that the return type
788 * of the test must be boolean.
789 * <p> Here is pseudocode for the resulting adapter:
790 * <blockquote><pre>
791 * signature T(A...);
792 * boolean test(A...);
793 * T target(A...);
794 * T fallback(A...);
795 * T adapter(A... a) {
796 * if (test(a...))
797 * return target(a...);
798 * else
799 * return fallback(a...);
800 * }
801 * </pre></blockquote>
802 * @param test method handle used for test, must return boolean
803 * @param target method handle to call if test passes
804 * @param fallback method handle to call if test fails
805 * @return method handle which incorporates the specified if/then/else logic
806 * @throws IllegalArgumentException if {@code test} does not return boolean,
807 * or if all three method types do not match (with the return
808 * type of {@code test} changed to match that of {@code target}).
809 */
810 public static
811 MethodHandle guardWithTest(MethodHandle test,
812 MethodHandle target,
813 MethodHandle fallback) {
814 if (target.type() != fallback.type())
815 throw newIllegalArgumentException("target and fallback types do not match");
816 if (target.type().changeReturnType(boolean.class) != test.type())
817 throw newIllegalArgumentException("target and test types do not match");
818 /* {
819 MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) {
820 return z ? t : f;
821 }
822 MethodHandle choose = findVirtual(MethodHandles.class, "choose",
823 MethodType.make(boolean.class, MethodHandle.class, MethodHandle.class));
824 choose = appendArgument(choose, target);
825 choose = appendArgument(choose, fallback);
826 choose = combineArguments(choose, test);
827 MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type());
828 return checkArguments(invoke, choose, 0);
829 } */
830 return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
831 }
832
833 /**
834 * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
835 * Adapt a target method handle {@code target} by first checking its arguments,
836 * and then calling the target.
837 * The check is performed by a second method handle, the {@code checker}.
838 * After this, control passes to the target method handle, with the same
839 * arguments.
840 * <p>
841 * The return value of the checker is inserted into the argument list
842 * for {@code target} at the indicated position {@code pos}, if it is non-negative.
843 * Except for this inserted argument (if any), the argument types of
844 * the target {@code target} and the {@code checker} must be identical.
845 * <p>
846 * The checker handle must have the same argument types as the
847 * target handle, but must return {@link MethodHandle} instead of
848 * the ultimate return type. The returned method handle, in turn,
849 * is required to have exactly the given final method type.
850 * <p> Here is pseudocode for the resulting adapter:
851 * <blockquote><pre>
852 * signature V(A[pos]..., B...);
853 * signature T(A[pos]..., V, B...);
854 * T target(A... a, V, B... b);
855 * U checker(A..., B...);
856 * T adapter(A... a, B... b) {
857 * V v = checker(a..., b...);
858 * return target(a..., v, b...);
859 * }
860 * </pre></blockquote>
861 * @param target the method handle to invoke after arguments are checked
862 * @param checker method handle to call initially on the incoming arguments
863 * @param pos where the return value of {@code checker} is to
864 * be inserted as an argument to {@code target}
865 * @return method handle which incorporates the specified dispatch logic
866 * @throws IllegalArgumentException if {@code checker} does not itself
867 * return either void or the {@code pos}-th argument of {@code target},
868 * or does not have the same argument types as {@code target}
869 * (minus the inserted argument)
870 */
871 public static
872 MethodHandle checkArguments(MethodHandle target, MethodHandle checker, int pos) {
873 MethodType mhType = target.type();
874 Class<?> checkType = checker.type().returnType();
875 MethodType incomingArgs;
876 if (pos < 0) {
877 // No inserted argument; target & checker must have same argument types.
878 incomingArgs = mhType;
879 if (!incomingArgs.changeReturnType(checkType).equals(checker.type()))
880 throw newIllegalArgumentException("target and checker types do not match");
881 } else {
882 // Inserted argument.
883 if (pos >= mhType.parameterCount()
884 || mhType.parameterType(pos) != checkType)
885 throw newIllegalArgumentException("inserted checker argument does not match target");
886 incomingArgs = mhType.deleteParameterType(pos);
887 }
888 if (!incomingArgs.changeReturnType(checkType).equals(checker.type())) {
889 throw newIllegalArgumentException("target and checker types do not match");
890 }
891 return MethodHandleImpl.checkArguments(IMPL_TOKEN, target, checker, pos);
892 }
893
894 /// standard method handles
895
896 /**
897 * Identity function.
898 * @param x an arbitrary reference value
899 * @return the same value x
900 */
901 /*public*/ static <T>
902 T identity(T x) {
903 return x;
904 }
905
906 /**
907 * A method handle for {@link #identity}
908 */
909 /*public*/ static
910 MethodHandle identityMethod() {
911 if (IDENTITY == null)
912 IDENTITY = findStatic(MethodHandle.class, "identity", IDENTITY_TYPE);
913 return IDENTITY;
914 }
915 private static
916 MethodHandle IDENTITY;
917 private static final
918 MethodType IDENTITY_TYPE = MethodType.make(Object.class, Object.class);
919
920 /**
921 * Empty function.
922 */
923 /*public*/ static
924 void empty() {
925 }
926
927 /**
928 * A method handle for {@link #empty}
929 */
930 /*public*/ static
931 MethodHandle emptyMethod() {
932 if (EMPTY == null)
933 EMPTY = findStatic(MethodHandle.class, "empty", EMPTY_TYPE);
934 return EMPTY;
935 }
936 private static
937 MethodHandle EMPTY;
938 private static final
939 MethodType EMPTY_TYPE = MethodType.make(void.class);
940 }