src/share/classes/java/dyn/MethodHandles.java
author jrose
Tue May 12 13:54:22 2009 -0700 (6 months ago)
changeset 1202 29180ef374c8
parent 12012387e3b1994e
permissions -rw-r--r--
6839839: access checking logic is wrong at three points in MethodHandles
Summary: point fixes to access checking logic
Reviewed-by: mr
        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 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;
       44 
       45 /**
       46  * Fundamental operations and utilities for MethodHandle.
       47  * <p>
       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:
       50  * <ol>
       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>
       57  * </ol>
       58  * @author John Rose, JSR 292 EG
       59  */
       60 public class MethodHandles {
       61 
       62     private MethodHandles() { }  // do not instantiate
       63 
       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.
       68 
       69     //// Method handle creation from ordinary methods.
       70 
       71     public static Lookup lookup() {
       72         return new Lookup();
       73     }
       74 
       75     /**
       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
       87      * lookup class.
       88      * <p>
       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
       97      * privileges.
       98      * <p>
       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.
      103      * <p>
      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.
      116      */
      117     public static final
      118     class Lookup {
      119         private final Class<?> lookupClass;
      120 
      121         /** Which class is performing the lookup?  It is this class against
      122          *  which checks are performed for visibility and access permissions.
      123          *  <p>
      124          *  This value is null if and only if this lookup is {@link #PUBLIC_LOOKUP}.
      125          */
      126         public Class<?> lookupClass() {
      127             return lookupClass;
      128         }
      129 
      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.
      136          */
      137         Lookup() {
      138             Class caller = getCallerClassAtEntryPoint();
      139             // make sure we haven't accidentally picked up this class:
      140             checkUnprivilegedlookupClass(caller);
      141             this.lookupClass = caller;
      142         }
      143 
      144         private Lookup(Class<?> lookupClass) {
      145             this.lookupClass = lookupClass;
      146         }
      147 
      148         private static final Class<?> PUBLIC_ONLY = sun.dyn.empty.Empty.class;
      149 
      150         /** Version of lookup which is trusted minimally.
      151          *  It can only be used to create method handles to
      152          *  publicly accessible members.
      153          */
      154         public static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_ONLY);
      155 
      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); }
      159 
      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);
      164         }
      165 
      166         @Override
      167         public String toString() {
      168             if (lookupClass == PUBLIC_ONLY)
      169                 return "public";
      170             if (lookupClass == null)
      171                 return "privileged";
      172             return lookupClass.getName();
      173         }
      174 
      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);
      182         }
      183 
      184         /**
      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
      196          */
      197         public
      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);
      203         }
      204 
      205         /**
      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.
      210          * <p>
      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}.)
      217          * <p>
      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
      229          */
      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);
      234         }
      235 
      236         /**
      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
      243          * to the caller.
      244          * <p>
      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.)
      249          * <p>
      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
      259          */
      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);
      269             }
      270             return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
      271         }
      272 
      273         /**
      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.
      280          * <p>
      281          * Equivalent to the following expression:
      282          * <code>
      283          * {@link #insertArgument}({@link #findVirtual}(defc, name, type), receiver)
      284          * </code>
      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
      291          */
      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);
      299             if (bmh == null)
      300                 throw newNoAccessException(method, lookupClass);
      301             return bmh;
      302         }
      303 
      304         /**
      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
      317          */
      318         public MethodHandle unreflect(Method m) throws NoAccessException {
      319             return unreflectImpl(new MemberName(m), m.isAccessible(), true, lookupClass);
      320         }
      321 
      322         /**
      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
      334          */
      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);
      340         }
      341 
      342         /**
      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.
      348          * <p>
      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
      355          */
      356         public MethodHandle unreflectConstructor(Constructor ctor) throws NoAccessException {
      357             MemberName m = new MemberName(ctor);
      358             return unreflectImpl(m, ctor.isAccessible(), false, lookupClass);
      359         }
      360 
      361         /**
      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
      372          */
      373         public MethodHandle unreflectGetter(Field f) throws NoAccessException {
      374             return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), false, lookupClass);
      375         }
      376 
      377         /**
      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
      389          */
      390         public MethodHandle unreflectSetter(Field f) throws NoAccessException {
      391             return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), true, lookupClass);
      392         }
      393 
      394     }
      395 
      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);
      402     }
      403 
      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);
      408         }
      409     }
      410 
      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);
      417     }
      418 
      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();
      425         if (m.isStatic()) {
      426             if (!isAccessible &&
      427                     VerifyAccess.isAccessible(defc, mods, false, lookupClass) == null)
      428                 throw newNoAccessException(m, lookupClass);
      429         } else {
      430             Class<?> constraint;
      431             if (isAccessible) {
      432                 // abbreviated access check for "unlocked" method
      433                 constraint = doDispatch ? defc : lookupClass;
      434             } else {
      435                 constraint = VerifyAccess.isAccessible(defc, mods, doDispatch, lookupClass);
      436             }
      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);
      441             }
      442         }
      443         return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookupClass);
      444     }
      445 
      446     /**
      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
      455      */
      456     public static
      457     MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
      458         return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false);
      459     }
      460 
      461     /**
      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
      469      */
      470     public static
      471     MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
      472         return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true);
      473     }
      474 
      475 
      476     /// method handle invocation (reflective style)
      477 
      478     /**
      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.
      486      * <p>
      487      * In order to match the type of the target, the following argument
      488      * conversions are applied as necessary:
      489      * <ul>
      490      * <li>reference casting
      491      * <li>unboxing
      492      * </ul>
      493      * The following conversions are not applied:
      494      * <ul>
      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)
      498      * </ul>
      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.
      501      * <p>
      502      * This call is a convenience method for the following code:
      503      * <pre>
      504      *   MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
      505      *   Object result = invoker.invoke(arguments);
      506      * </pre>
      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
      510      */
      511     public static
      512     Object invoke(MethodHandle target, Object... arguments) {
      513         int argc = arguments == null ? 0 : arguments.length;
      514         MethodType type = target.type();
      515         if (argc <= 4) {
      516             MethodHandle invoker = invokers(type).genericInvoker();
      517             switch (argc) {
      518                 case 0:  return invoker.<Object>invoke(target);
      519                 case 1:  return invoker.<Object>invoke(target,
      520                                     arguments[0]);
      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]);
      527             }
      528         }
      529         MethodHandle invoker = invokers(type).varargsInvoker();
      530         return invoker.<Object>invoke(target, arguments);
      531     }
      532 
      533     public static
      534     Object invoke_0(MethodHandle target) {
      535         MethodHandle invoker = invokers(target.type()).genericInvoker();
      536         return invoker.<Object>invoke(target);
      537     }
      538     public static
      539     Object invoke_1(MethodHandle target, Object a0) {
      540         MethodHandle invoker = invokers(target.type()).genericInvoker();
      541         return invoker.<Object>invoke(target, a0);
      542     }
      543     public static
      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);
      547     }
      548     public static
      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);
      552     }
      553     public static
      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);
      557     }
      558 
      559     /**
      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
      564      * arguments:
      565      * <ul>
      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
      569      * </ul>
      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.
      575      * <p>
      576      * This is a convenience method equivalent to the following code:
      577      * <pre>
      578      * MethodHandle invoker = exactInvoker(type);
      579      * MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs);
      580      * genericType = genericType.insertParameterType(0, MethodHandle.class);
      581      * if (!varargs)
      582      *     return convertArguments(invoker, genericType);
      583      * else
      584      *     return spreadArguments(invoker, genericType);
      585      * </pre>
      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
      590      */
      591     static public
      592     MethodHandle genericInvoker(MethodType type, int objectArgCount, boolean varargs) {
      593         return invokers(type).genericInvoker();
      594     }
      595 
      596     /**
      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}.
      602      * <p>
      603      * This is a convenience method equivalent to the following code:
      604      * <pre>
      605      *     MethodHandles.lookup().findVirtual(MethodHandle.class, "invoke", type);
      606      * </pre>
      607      * @param type the desired target type
      608      * @return a method handle suitable for invoking any method handle of the given type
      609      */
      610     static public
      611     MethodHandle exactInvoker(MethodType type) {
      612         return invokers(type).exactInvoker();
      613     }
      614 
      615     static private Invokers invokers(MethodType type) {
      616         return MethodTypeImpl.invokers(IMPL_TOKEN, type);
      617     }
      618 
      619     /**
      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:
      625      * <ul>
      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.
      641      * </ul>
      642      * If the value is discarded, null will be returned.
      643      * @param valueType
      644      * @param value
      645      * @return the value, converted if necessary
      646      * @throws java.lang.ClassCastException if a cast fails
      647      */
      648     static
      649     <T0, T1> T1 checkValue(Class<T0> t0, Class<T1> t1, Object value)
      650        throws ClassCastException
      651     {
      652         if (t0 == t1) {
      653             // no conversion needed; just reassert the same type
      654             if (t0.isPrimitive())
      655                 return Wrapper.asPrimitiveType(t1).cast(value);
      656             else
      657                 return Wrapper.OBJECT.cast(value, t1);
      658         }
      659         boolean prim0 = t0.isPrimitive(), prim1 = t1.isPrimitive();
      660         if (!prim0) {
      661             // check contract with caller
      662             Wrapper.OBJECT.cast(value, t0);
      663             if (!prim1) {
      664                 return Wrapper.OBJECT.cast(value, t1);
      665             }
      666             // convert reference to primitive by unboxing
      667             Wrapper w1 = Wrapper.forPrimitiveType(t1);
      668             return w1.cast(value, t1);
      669         }
      670         // check contract with caller:
      671         Wrapper.asWrapperType(t0).cast(value);
      672         Wrapper w1 = Wrapper.forPrimitiveType(t1);
      673         return w1.cast(value, t1);
      674     }
      675 
      676     static
      677     Object checkValue(Class<?> T1, Object value)
      678        throws ClassCastException
      679     {
      680         Class<?> T0;
      681         if (value == null)
      682             T0 = Object.class;
      683         else
      684             T0 = value.getClass();
      685         return checkValue(T0, T1, value);
      686     }
      687 
      688     /// method handle modification (creation from other method handles)
      689 
      690     /**
      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.
      699      * <p>
      700      * If the original type and new type are equal, returns target.
      701      * <p>
      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.
      706      * <p>
      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.
      718      * <p>
      719      * Given those types T0, T1, one of the following conversions is applied
      720      * if possible:
      721      * <ul>
      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.
      751      * </ul>
      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
      758      */
      759     public static
      760     MethodHandle convertArguments(MethodHandle target, MethodType newType) {
      761         MethodType oldType = target.type();
      762         if (oldType.equals(newType))
      763             return target;
      764         MethodHandle res = MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
      765                                                  newType, oldType, null);
      766         if (res == null)
      767             throw newIllegalArgumentException("cannot convert to "+newType+": "+target);
      768         return res;
      769     }
      770 
      771     /**
      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.
      777      * <p>
      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]}.
      787      * <p>
      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.
      792      * <p>
      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
      801      */
      802     public static
      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,
      807                                                  newType, oldType,
      808                                                  reorder);
      809     }
      810 
      811     private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
      812         if (reorder.length == oldType.parameterCount()) {
      813             int limit = newType.parameterCount();
      814             boolean bad = false;
      815             for (int i : reorder) {
      816                 if (i < 0 || i >= limit) {
      817                     bad = true; break;
      818                 }
      819             }
      820             if (!bad)  return;
      821         }
      822         throw newIllegalArgumentException("bad reorder array");
      823     }
      824 
      825     /**
      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.
      831      * <p>
      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.
      835      * <p>
      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.
      843      * <p>
      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
      853      */
      854     public static
      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);
      864         }
      865         if (res == null) {
      866             throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType);
      867         }
      868         return res;
      869     }
      870 
      871     /**
      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.
      878      * <p>
      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.
      885      * <p>
      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
      893      */
      894     public static
      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);
      904     }
      905 
      906     /**
      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.
      912      * <p>
      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.
      916      * <p>
      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
      926      */
      927     public static
      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
      945         }
      946         return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value);
      947     }
      948 
      949     /**
      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.
      955      * <p>
      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
      965      */
      966     public static
      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);
      979     }
      980 
      981     /**
      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:
      990      * <blockquote><pre>
      991      * signature T(A...);
      992      * boolean test(A...);
      993      * T target(A...);
      994      * T fallback(A...);
      995      * T adapter(A... a) {
      996      *   if (test(a...))
      997      *     return target(a...);
      998      *   else
      999      *     return fallback(a...);
     1000      * }
     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}).
     1009      */
     1010     public static
     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");
     1018         /* {
     1019             MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type());
     1020             static MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) {
     1021                 return z ? t : f;
     1022             }
     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);
     1027             }
     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...))
     1037         } */
     1038         return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
     1039     }
     1040 
     1041     /**
     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.
     1047      * <p>
     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.
     1052      * <p>
     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.)
     1055      * <p>
     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:
     1061      * <blockquote><pre>
     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...);
     1069      * }
     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)
     1080      */
     1081     public static
     1082     MethodHandle combineArguments(MethodHandle target, int pos, MethodHandle combiner) {
     1083         MethodType mhType = target.type();
     1084         Class<?> combineType = combiner.type().returnType();
     1085         MethodType incomingArgs;
     1086         if (pos < 0) {
     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");
     1091         } else {
     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);
     1097         }
     1098         if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) {
     1099             throw newIllegalArgumentException("target and combiner types do not match");
     1100         }
     1101         return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos);
     1102     }
     1103 
     1104 }