1 /*
   2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import java.security.AccessController;
  29 import java.security.PrivilegedAction;
  30 import java.util.ArrayList;
  31 import java.util.Arrays;
  32 import java.util.HashMap;
  33 import sun.invoke.empty.Empty;
  34 import sun.invoke.util.ValueConversions;
  35 import sun.invoke.util.VerifyType;
  36 import sun.invoke.util.Wrapper;
  37 import sun.reflect.CallerSensitive;
  38 import sun.reflect.Reflection;
  39 import static java.lang.invoke.LambdaForm.*;
  40 import static java.lang.invoke.MethodHandleStatics.*;
  41 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
  42 
  43 /**
  44  * Trusted implementation code for MethodHandle.
  45  * @author jrose
  46  */
  47 /*non-public*/ abstract class MethodHandleImpl {
  48     /// Factory methods to create method handles:
  49 
  50     static void initStatics() {
  51         // Trigger selected static initializations.
  52         MemberName.Factory.INSTANCE.getClass();
  53     }
  54 
  55     static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
  56         if (!arrayClass.isArray())
  57             throw newIllegalArgumentException("not an array: "+arrayClass);
  58         MethodHandle accessor = ArrayAccessor.getAccessor(arrayClass, isSetter);
  59         MethodType srcType = accessor.type().erase();
  60         MethodType lambdaType = srcType.invokerType();
  61         Name[] names = arguments(1, lambdaType);
  62         Name[] args  = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount());
  63         names[names.length - 1] = new Name(accessor.asType(srcType), (Object[]) args);
  64         LambdaForm form = new LambdaForm("getElement", lambdaType.parameterCount(), names);
  65         MethodHandle mh = SimpleMethodHandle.make(srcType, form);
  66         if (ArrayAccessor.needCast(arrayClass)) {
  67             mh = mh.bindTo(arrayClass);
  68         }
  69         mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter));
  70         return mh;
  71     }
  72 
  73     static final class ArrayAccessor {
  74         /// Support for array element access
  75         static final HashMap<Class<?>, MethodHandle> GETTER_CACHE = new HashMap<>();  // TODO use it
  76         static final HashMap<Class<?>, MethodHandle> SETTER_CACHE = new HashMap<>();  // TODO use it
  77 
  78         static int     getElementI(int[]     a, int i)            { return              a[i]; }
  79         static long    getElementJ(long[]    a, int i)            { return              a[i]; }
  80         static float   getElementF(float[]   a, int i)            { return              a[i]; }
  81         static double  getElementD(double[]  a, int i)            { return              a[i]; }
  82         static boolean getElementZ(boolean[] a, int i)            { return              a[i]; }
  83         static byte    getElementB(byte[]    a, int i)            { return              a[i]; }
  84         static short   getElementS(short[]   a, int i)            { return              a[i]; }
  85         static char    getElementC(char[]    a, int i)            { return              a[i]; }
  86         static Object  getElementL(Object[]  a, int i)            { return              a[i]; }
  87 
  88         static void    setElementI(int[]     a, int i, int     x) {              a[i] = x; }
  89         static void    setElementJ(long[]    a, int i, long    x) {              a[i] = x; }
  90         static void    setElementF(float[]   a, int i, float   x) {              a[i] = x; }
  91         static void    setElementD(double[]  a, int i, double  x) {              a[i] = x; }
  92         static void    setElementZ(boolean[] a, int i, boolean x) {              a[i] = x; }
  93         static void    setElementB(byte[]    a, int i, byte    x) {              a[i] = x; }
  94         static void    setElementS(short[]   a, int i, short   x) {              a[i] = x; }
  95         static void    setElementC(char[]    a, int i, char    x) {              a[i] = x; }
  96         static void    setElementL(Object[]  a, int i, Object  x) {              a[i] = x; }
  97 
  98         static Object  getElementL(Class<?> arrayClass, Object[] a, int i)           { arrayClass.cast(a); return a[i]; }
  99         static void    setElementL(Class<?> arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; }
 100 
 101         // Weakly typed wrappers of Object[] accessors:
 102         static Object  getElementL(Object    a, int i)            { return getElementL((Object[])a, i); }
 103         static void    setElementL(Object    a, int i, Object  x) {        setElementL((Object[]) a, i, x); }
 104         static Object  getElementL(Object   arrayClass, Object a, int i)             { return getElementL((Class<?>) arrayClass, (Object[])a, i); }
 105         static void    setElementL(Object   arrayClass, Object a, int i, Object x)   {        setElementL((Class<?>) arrayClass, (Object[])a, i, x); }
 106 
 107         static boolean needCast(Class<?> arrayClass) {
 108             Class<?> elemClass = arrayClass.getComponentType();
 109             return !elemClass.isPrimitive() && elemClass != Object.class;
 110         }
 111         static String name(Class<?> arrayClass, boolean isSetter) {
 112             Class<?> elemClass = arrayClass.getComponentType();
 113             if (elemClass == null)  throw new IllegalArgumentException();
 114             return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
 115         }
 116         static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false;  // FIXME: decide
 117         static MethodType type(Class<?> arrayClass, boolean isSetter) {
 118             Class<?> elemClass = arrayClass.getComponentType();
 119             Class<?> arrayArgClass = arrayClass;
 120             if (!elemClass.isPrimitive()) {
 121                 arrayArgClass = Object[].class;
 122                 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
 123                     arrayArgClass = Object.class;
 124             }
 125             if (!needCast(arrayClass)) {
 126                 return !isSetter ?
 127                     MethodType.methodType(elemClass,  arrayArgClass, int.class) :
 128                     MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
 129             } else {
 130                 Class<?> classArgClass = Class.class;
 131                 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
 132                     classArgClass = Object.class;
 133                 return !isSetter ?
 134                     MethodType.methodType(Object.class, classArgClass, arrayArgClass, int.class) :
 135                     MethodType.methodType(void.class,   classArgClass, arrayArgClass, int.class, Object.class);
 136             }
 137         }
 138         static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
 139             Class<?> elemClass = arrayClass.getComponentType();
 140             return !isSetter ?
 141                     MethodType.methodType(elemClass,  arrayClass, int.class) :
 142                     MethodType.methodType(void.class, arrayClass, int.class, elemClass);
 143         }
 144         static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
 145             String     name = name(arrayClass, isSetter);
 146             MethodType type = type(arrayClass, isSetter);
 147             try {
 148                 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
 149             } catch (ReflectiveOperationException ex) {
 150                 throw uncaughtException(ex);
 151             }
 152         }
 153     }
 154 
 155     /**
 156      * Create a JVM-level adapter method handle to conform the given method
 157      * handle to the similar newType, using only pairwise argument conversions.
 158      * For each argument, convert incoming argument to the exact type needed.
 159      * The argument conversions allowed are casting, boxing and unboxing,
 160      * integral widening or narrowing, and floating point widening or narrowing.
 161      * @param srcType required call type
 162      * @param target original method handle
 163      * @param level which strength of conversion is allowed
 164      * @return an adapter to the original handle with the desired new type,
 165      *          or the original target if the types are already identical
 166      *          or null if the adaptation cannot be made
 167      */
 168     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
 169         assert(level >= 0 && level <= 2);
 170         MethodType dstType = target.type();
 171         assert(dstType.parameterCount() == target.type().parameterCount());
 172         if (srcType == dstType)
 173             return target;
 174 
 175         // Calculate extra arguments (temporaries) required in the names array.
 176         // FIXME: Use an ArrayList<Name>.  Some arguments require more than one conversion step.
 177         final int INARG_COUNT = srcType.parameterCount();
 178         int conversions = 0;
 179         boolean[] needConv = new boolean[1+INARG_COUNT];
 180         for (int i = 0; i <= INARG_COUNT; i++) {
 181             Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
 182             Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
 183             if (!VerifyType.isNullConversion(src, dst) ||
 184                 level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
 185                 needConv[i] = true;
 186                 conversions++;
 187             }
 188         }
 189         boolean retConv = needConv[INARG_COUNT];
 190 
 191         final int IN_MH         = 0;
 192         final int INARG_BASE    = 1;
 193         final int INARG_LIMIT   = INARG_BASE + INARG_COUNT;
 194         final int NAME_LIMIT    = INARG_LIMIT + conversions + 1;
 195         final int RETURN_CONV   = (!retConv ? -1         : NAME_LIMIT - 1);
 196         final int OUT_CALL      = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
 197 
 198         // Now build a LambdaForm.
 199         MethodType lambdaType = srcType.basicType().invokerType();
 200         Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
 201 
 202         // Collect the arguments to the outgoing call, maybe with conversions:
 203         final int OUTARG_BASE = 0;  // target MH is Name.function, name Name.arguments[0]
 204         Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
 205 
 206         int nameCursor = INARG_LIMIT;
 207         for (int i = 0; i < INARG_COUNT; i++) {
 208             Class<?> src = srcType.parameterType(i);
 209             Class<?> dst = dstType.parameterType(i);
 210 
 211             if (!needConv[i]) {
 212                 // do nothing: difference is trivial
 213                 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
 214                 continue;
 215             }
 216 
 217             // Tricky case analysis follows.
 218             MethodHandle fn = null;
 219             if (src.isPrimitive()) {
 220                 if (dst.isPrimitive()) {
 221                     fn = ValueConversions.convertPrimitive(src, dst);
 222                 } else {
 223                     Wrapper w = Wrapper.forPrimitiveType(src);
 224                     MethodHandle boxMethod = ValueConversions.box(w);
 225                     if (dst == w.wrapperType())
 226                         fn = boxMethod;
 227                     else
 228                         fn = boxMethod.asType(MethodType.methodType(dst, src));
 229                 }
 230             } else {
 231                 if (dst.isPrimitive()) {
 232                     // Caller has boxed a primitive.  Unbox it for the target.
 233                     Wrapper w = Wrapper.forPrimitiveType(dst);
 234                     if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType())) {
 235                         fn = ValueConversions.unbox(dst);
 236                     } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
 237                         // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
 238                         // must include additional conversions
 239                         // src must be examined at runtime, to detect Byte, Character, etc.
 240                         MethodHandle unboxMethod = (level == 1
 241                                                     ? ValueConversions.unbox(dst)
 242                                                     : ValueConversions.unboxCast(dst));
 243                         fn = unboxMethod;
 244                     } else {
 245                         // Example: Byte->int
 246                         // Do this by reformulating the problem to Byte->byte.
 247                         Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
 248                         MethodHandle unbox = ValueConversions.unbox(srcPrim);
 249                         // Compose the two conversions.  FIXME:  should make two Names for this job
 250                         fn = unbox.asType(MethodType.methodType(dst, src));
 251                     }
 252                 } else {
 253                     // Simple reference conversion.
 254                     // Note:  Do not check for a class hierarchy relation
 255                     // between src and dst.  In all cases a 'null' argument
 256                     // will pass the cast conversion.
 257                     fn = ValueConversions.cast(dst);
 258                 }
 259             }
 260             Name conv = new Name(fn, names[INARG_BASE + i]);
 261             assert(names[nameCursor] == null);
 262             names[nameCursor++] = conv;
 263             assert(outArgs[OUTARG_BASE + i] == null);
 264             outArgs[OUTARG_BASE + i] = conv;
 265         }
 266 
 267         // Build argument array for the call.
 268         assert(nameCursor == OUT_CALL);
 269         names[OUT_CALL] = new Name(target, outArgs);
 270 
 271         if (RETURN_CONV < 0) {
 272             assert(OUT_CALL == names.length-1);
 273         } else {
 274             Class<?> needReturn = srcType.returnType();
 275             Class<?> haveReturn = dstType.returnType();
 276             MethodHandle fn;
 277             Object[] arg = { names[OUT_CALL] };
 278             if (haveReturn == void.class) {
 279                 // synthesize a zero value for the given void
 280                 Object zero = Wrapper.forBasicType(needReturn).zero();
 281                 fn = MethodHandles.constant(needReturn, zero);
 282                 arg = new Object[0];  // don't pass names[OUT_CALL] to conversion
 283             } else {
 284                 MethodHandle identity = MethodHandles.identity(needReturn);
 285                 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
 286                 fn = makePairwiseConvert(identity, needConversion, level);
 287             }
 288             assert(names[RETURN_CONV] == null);
 289             names[RETURN_CONV] = new Name(fn, arg);
 290             assert(RETURN_CONV == names.length-1);
 291         }
 292 
 293         LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
 294         return SimpleMethodHandle.make(srcType, form);
 295     }
 296 
 297     static MethodHandle makeReferenceIdentity(Class<?> refType) {
 298         MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
 299         Name[] names = arguments(1, lambdaType);
 300         names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
 301         LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
 302         return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
 303     }
 304 
 305     static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
 306         MethodType type = target.type();
 307         int last = type.parameterCount() - 1;
 308         if (type.parameterType(last) != arrayType)
 309             target = target.asType(type.changeParameterType(last, arrayType));
 310         target = target.asFixedArity();  // make sure this attribute is turned off
 311         return new AsVarargsCollector(target, target.type(), arrayType);
 312     }
 313 
 314     static class AsVarargsCollector extends MethodHandle {
 315         private final MethodHandle target;
 316         private final Class<?> arrayType;
 317         private /*@Stable*/ MethodHandle asCollectorCache;
 318 
 319         AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
 320             super(type, reinvokerForm(target));
 321             this.target = target;
 322             this.arrayType = arrayType;
 323             this.asCollectorCache = target.asCollector(arrayType, 0);
 324         }
 325 
 326         @Override MethodHandle reinvokerTarget() { return target; }
 327 
 328         @Override
 329         public boolean isVarargsCollector() {
 330             return true;
 331         }
 332 
 333         @Override
 334         public MethodHandle asFixedArity() {
 335             return target;
 336         }
 337 
 338         @Override
 339         public MethodHandle asTypeUncached(MethodType newType) {
 340             MethodType type = this.type();
 341             int collectArg = type.parameterCount() - 1;
 342             int newArity = newType.parameterCount();
 343             if (newArity == collectArg+1 &&
 344                 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
 345                 // if arity and trailing parameter are compatible, do normal thing
 346                 return asTypeCache = asFixedArity().asType(newType);
 347             }
 348             // check cache
 349             MethodHandle acc = asCollectorCache;
 350             if (acc != null && acc.type().parameterCount() == newArity)
 351                 return asTypeCache = acc.asType(newType);
 352             // build and cache a collector
 353             int arrayLength = newArity - collectArg;
 354             MethodHandle collector;
 355             try {
 356                 collector = asFixedArity().asCollector(arrayType, arrayLength);
 357                 assert(collector.type().parameterCount() == newArity) : "newArity="+newArity+" but collector="+collector;
 358             } catch (IllegalArgumentException ex) {
 359                 throw new WrongMethodTypeException("cannot build collector", ex);
 360             }
 361             asCollectorCache = collector;
 362             return asTypeCache = collector.asType(newType);
 363         }
 364 
 365         @Override
 366         MethodHandle setVarargs(MemberName member) {
 367             if (member.isVarargs())  return this;
 368             return asFixedArity();
 369         }
 370 
 371         @Override
 372         MethodHandle viewAsType(MethodType newType) {
 373             if (newType.lastParameterType() != type().lastParameterType())
 374                 throw new InternalError();
 375             MethodHandle newTarget = asFixedArity().viewAsType(newType);
 376             // put back the varargs bit:
 377             return new AsVarargsCollector(newTarget, newType, arrayType);
 378         }
 379 
 380         @Override
 381         MemberName internalMemberName() {
 382             return asFixedArity().internalMemberName();
 383         }
 384         @Override
 385         Class<?> internalCallerClass() {
 386             return asFixedArity().internalCallerClass();
 387         }
 388 
 389         /*non-public*/
 390         @Override
 391         boolean isInvokeSpecial() {
 392             return asFixedArity().isInvokeSpecial();
 393         }
 394 
 395 
 396         @Override
 397         MethodHandle bindArgument(int pos, char basicType, Object value) {
 398             return asFixedArity().bindArgument(pos, basicType, value);
 399         }
 400 
 401         @Override
 402         MethodHandle bindReceiver(Object receiver) {
 403             return asFixedArity().bindReceiver(receiver);
 404         }
 405 
 406         @Override
 407         MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
 408             return asFixedArity().dropArguments(srcType, pos, drops);
 409         }
 410 
 411         @Override
 412         MethodHandle permuteArguments(MethodType newType, int[] reorder) {
 413             return asFixedArity().permuteArguments(newType, reorder);
 414         }
 415     }
 416 
 417     /** Factory method:  Spread selected argument. */
 418     static MethodHandle makeSpreadArguments(MethodHandle target,
 419                                             Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
 420         MethodType targetType = target.type();
 421 
 422         for (int i = 0; i < spreadArgCount; i++) {
 423             Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
 424             if (arg == null)  arg = Object.class;
 425             targetType = targetType.changeParameterType(spreadArgPos + i, arg);
 426         }
 427         target = target.asType(targetType);
 428 
 429         MethodType srcType = targetType
 430                 .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType);
 431         // Now build a LambdaForm.
 432         MethodType lambdaType = srcType.invokerType();
 433         Name[] names = arguments(spreadArgCount + 2, lambdaType);
 434         int nameCursor = lambdaType.parameterCount();
 435         int[] indexes = new int[targetType.parameterCount()];
 436 
 437         for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) {
 438             Class<?> src = lambdaType.parameterType(i);
 439             if (i == spreadArgPos) {
 440                 // Spread the array.
 441                 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
 442                 Name array = names[argIndex];
 443                 names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
 444                 for (int j = 0; j < spreadArgCount; i++, j++) {
 445                     indexes[i] = nameCursor;
 446                     names[nameCursor++] = new Name(aload, array, j);
 447                 }
 448             } else if (i < indexes.length) {
 449                 indexes[i] = argIndex;
 450             }
 451         }
 452         assert(nameCursor == names.length-1);  // leave room for the final call
 453 
 454         // Build argument array for the call.
 455         Name[] targetArgs = new Name[targetType.parameterCount()];
 456         for (int i = 0; i < targetType.parameterCount(); i++) {
 457             int idx = indexes[i];
 458             targetArgs[i] = names[idx];
 459         }
 460         names[names.length - 1] = new Name(target, (Object[]) targetArgs);
 461 
 462         LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names);
 463         return SimpleMethodHandle.make(srcType, form);
 464     }
 465 
 466     static void checkSpreadArgument(Object av, int n) {
 467         if (av == null) {
 468             if (n == 0)  return;
 469         } else if (av instanceof Object[]) {
 470             int len = ((Object[])av).length;
 471             if (len == n)  return;
 472         } else {
 473             int len = java.lang.reflect.Array.getLength(av);
 474             if (len == n)  return;
 475         }
 476         // fall through to error:
 477         throw newIllegalArgumentException("array is not of length "+n);
 478     }
 479 
 480     /**
 481      * Pre-initialized NamedFunctions for bootstrapping purposes.
 482      * Factored in an inner class to delay initialization until first usage.
 483      */
 484     private static class Lazy {
 485         static final NamedFunction NF_checkSpreadArgument;
 486         static {
 487             try {
 488                 NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
 489                         .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
 490                 NF_checkSpreadArgument.resolve();
 491             } catch (ReflectiveOperationException ex) {
 492                 throw newInternalError(ex);
 493             }
 494         }
 495     }
 496 
 497     /** Factory method:  Collect or filter selected argument(s). */
 498     static MethodHandle makeCollectArguments(MethodHandle target,
 499                 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
 500         MethodType targetType = target.type();          // (a..., c, [b...])=>r
 501         MethodType collectorType = collector.type();    // (b...)=>c
 502         int collectArgCount = collectorType.parameterCount();
 503         Class<?> collectValType = collectorType.returnType();
 504         int collectValCount = (collectValType == void.class ? 0 : 1);
 505         MethodType srcType = targetType                 // (a..., [b...])=>r
 506                 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
 507         if (!retainOriginalArgs) {                      // (a..., b...)=>r
 508             srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
 509         }
 510         // in  arglist: [0: ...keep1 | cpos: collect...  | cpos+cacount: keep2... ]
 511         // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
 512         // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
 513 
 514         // Now build a LambdaForm.
 515         MethodType lambdaType = srcType.invokerType();
 516         Name[] names = arguments(2, lambdaType);
 517         final int collectNamePos = names.length - 2;
 518         final int targetNamePos  = names.length - 1;
 519 
 520         Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount);
 521         names[collectNamePos] = new Name(collector, (Object[]) collectorArgs);
 522 
 523         // Build argument array for the target.
 524         // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ].
 525         // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ].
 526         Name[] targetArgs = new Name[targetType.parameterCount()];
 527         int inputArgPos  = 1;  // incoming LF args to copy to target
 528         int targetArgPos = 0;  // fill pointer for targetArgs
 529         int chunk = collectArgPos;  // |headArgs|
 530         System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
 531         inputArgPos  += chunk;
 532         targetArgPos += chunk;
 533         if (collectValType != void.class) {
 534             targetArgs[targetArgPos++] = names[collectNamePos];
 535         }
 536         chunk = collectArgCount;
 537         if (retainOriginalArgs) {
 538             System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
 539             targetArgPos += chunk;   // optionally pass on the collected chunk
 540         }
 541         inputArgPos += chunk;
 542         chunk = targetArgs.length - targetArgPos;  // all the rest
 543         System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
 544         assert(inputArgPos + chunk == collectNamePos);  // use of rest of input args also
 545         names[targetNamePos] = new Name(target, (Object[]) targetArgs);
 546 
 547         LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
 548         return SimpleMethodHandle.make(srcType, form);
 549     }
 550 
 551     static
 552     MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
 553         return testResult ? target : fallback;
 554     }
 555 
 556     static MethodHandle SELECT_ALTERNATIVE;
 557     static MethodHandle selectAlternative() {
 558         if (SELECT_ALTERNATIVE != null)  return SELECT_ALTERNATIVE;
 559         try {
 560             SELECT_ALTERNATIVE
 561             = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
 562                     MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
 563         } catch (ReflectiveOperationException ex) {
 564             throw new RuntimeException(ex);
 565         }
 566         return SELECT_ALTERNATIVE;
 567     }
 568 
 569     static
 570     MethodHandle makeGuardWithTest(MethodHandle test,
 571                                    MethodHandle target,
 572                                    MethodHandle fallback) {
 573         MethodType basicType = target.type().basicType();
 574         MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
 575         int arity = basicType.parameterCount();
 576         int extraNames = 3;
 577         MethodType lambdaType = basicType.invokerType();
 578         Name[] names = arguments(extraNames, lambdaType);
 579 
 580         Object[] testArgs   = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
 581         Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class);
 582 
 583         // call test
 584         names[arity + 1] = new Name(test, testArgs);
 585 
 586         // call selectAlternative
 587         Object[] selectArgs = { names[arity + 1], target, fallback };
 588         names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs);
 589         targetArgs[0] = names[arity + 2];
 590 
 591         // call target or fallback
 592         names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
 593 
 594         LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
 595         return SimpleMethodHandle.make(target.type(), form);
 596     }
 597 
 598     private static class GuardWithCatch {
 599         private final MethodHandle target;
 600         private final Class<? extends Throwable> exType;
 601         private final MethodHandle catcher;
 602         // FIXME: Build the control flow out of foldArguments.
 603         GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
 604             this.target = target;
 605             this.exType = exType;
 606             this.catcher = catcher;
 607         }
 608         @LambdaForm.Hidden
 609         private Object invoke_V(Object... av) throws Throwable {
 610             try {
 611                 return target.invokeExact(av);
 612             } catch (Throwable t) {
 613                 if (!exType.isInstance(t))  throw t;
 614                 return catcher.invokeExact(t, av);
 615             }
 616         }
 617         @LambdaForm.Hidden
 618         private Object invoke_L0() throws Throwable {
 619             try {
 620                 return target.invokeExact();
 621             } catch (Throwable t) {
 622                 if (!exType.isInstance(t))  throw t;
 623                 return catcher.invokeExact(t);
 624             }
 625         }
 626         @LambdaForm.Hidden
 627         private Object invoke_L1(Object a0) throws Throwable {
 628             try {
 629                 return target.invokeExact(a0);
 630             } catch (Throwable t) {
 631                 if (!exType.isInstance(t))  throw t;
 632                 return catcher.invokeExact(t, a0);
 633             }
 634         }
 635         @LambdaForm.Hidden
 636         private Object invoke_L2(Object a0, Object a1) throws Throwable {
 637             try {
 638                 return target.invokeExact(a0, a1);
 639             } catch (Throwable t) {
 640                 if (!exType.isInstance(t))  throw t;
 641                 return catcher.invokeExact(t, a0, a1);
 642             }
 643         }
 644         @LambdaForm.Hidden
 645         private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
 646             try {
 647                 return target.invokeExact(a0, a1, a2);
 648             } catch (Throwable t) {
 649                 if (!exType.isInstance(t))  throw t;
 650                 return catcher.invokeExact(t, a0, a1, a2);
 651             }
 652         }
 653         @LambdaForm.Hidden
 654         private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
 655             try {
 656                 return target.invokeExact(a0, a1, a2, a3);
 657             } catch (Throwable t) {
 658                 if (!exType.isInstance(t))  throw t;
 659                 return catcher.invokeExact(t, a0, a1, a2, a3);
 660             }
 661         }
 662         @LambdaForm.Hidden
 663         private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
 664             try {
 665                 return target.invokeExact(a0, a1, a2, a3, a4);
 666             } catch (Throwable t) {
 667                 if (!exType.isInstance(t))  throw t;
 668                 return catcher.invokeExact(t, a0, a1, a2, a3, a4);
 669             }
 670         }
 671         @LambdaForm.Hidden
 672         private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
 673             try {
 674                 return target.invokeExact(a0, a1, a2, a3, a4, a5);
 675             } catch (Throwable t) {
 676                 if (!exType.isInstance(t))  throw t;
 677                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
 678             }
 679         }
 680         @LambdaForm.Hidden
 681         private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
 682             try {
 683                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
 684             } catch (Throwable t) {
 685                 if (!exType.isInstance(t))  throw t;
 686                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
 687             }
 688         }
 689         @LambdaForm.Hidden
 690         private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
 691             try {
 692                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
 693             } catch (Throwable t) {
 694                 if (!exType.isInstance(t))  throw t;
 695                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
 696             }
 697         }
 698         static MethodHandle[] makeInvokes() {
 699             ArrayList<MethodHandle> invokes = new ArrayList<>();
 700             MethodHandles.Lookup lookup = IMPL_LOOKUP;
 701             for (;;) {
 702                 int nargs = invokes.size();
 703                 String name = "invoke_L"+nargs;
 704                 MethodHandle invoke = null;
 705                 try {
 706                     invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
 707                 } catch (ReflectiveOperationException ex) {
 708                 }
 709                 if (invoke == null)  break;
 710                 invokes.add(invoke);
 711             }
 712             assert(invokes.size() == 9);  // current number of methods
 713             return invokes.toArray(new MethodHandle[0]);
 714         };
 715         static final MethodHandle[] INVOKES = makeInvokes();
 716         // For testing use this:
 717         //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
 718         static final MethodHandle VARARGS_INVOKE;
 719         static {
 720             try {
 721                 VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
 722             } catch (ReflectiveOperationException ex) {
 723                 throw uncaughtException(ex);
 724             }
 725         }
 726     }
 727 
 728 
 729     static
 730     MethodHandle makeGuardWithCatch(MethodHandle target,
 731                                     Class<? extends Throwable> exType,
 732                                     MethodHandle catcher) {
 733         MethodType type = target.type();
 734         MethodType ctype = catcher.type();
 735         int nargs = type.parameterCount();
 736         if (nargs < GuardWithCatch.INVOKES.length) {
 737             MethodType gtype = type.generic();
 738             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
 739             // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
 740             MethodHandle gtarget = makePairwiseConvert(target, gtype, 2);
 741             MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2);
 742             GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
 743             if (gtarget == null || gcatcher == null)  throw new InternalError();
 744             MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard);
 745             return makePairwiseConvert(ginvoker, type, 2);
 746         } else {
 747             target = target.asType(type.changeReturnType(Object.class));
 748             MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs);
 749             MethodType catcherType = ctype.changeParameterType(0, Throwable.class)
 750                                           .changeReturnType(Object.class);
 751             catcher = catcher.asType(catcherType);
 752             MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs);
 753             GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
 754             if (gtarget == null || gcatcher == null)  throw new InternalError();
 755             MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard);
 756             MethodHandle gcollect = makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false);
 757             return makePairwiseConvert(gcollect, type, 2);
 758         }
 759     }
 760 
 761     static
 762     MethodHandle throwException(MethodType type) {
 763         assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
 764         int arity = type.parameterCount();
 765         if (arity > 1) {
 766             return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
 767         }
 768         return makePairwiseConvert(throwException(), type, 2);
 769     }
 770 
 771     static MethodHandle THROW_EXCEPTION;
 772     static MethodHandle throwException() {
 773         MethodHandle mh = THROW_EXCEPTION;
 774         if (mh != null)  return mh;
 775         try {
 776             mh
 777             = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
 778                     MethodType.methodType(Empty.class, Throwable.class));
 779         } catch (ReflectiveOperationException ex) {
 780             throw new RuntimeException(ex);
 781         }
 782         THROW_EXCEPTION = mh;
 783         return mh;
 784     }
 785     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
 786 
 787     static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
 788     static MethodHandle fakeMethodHandleInvoke(MemberName method) {
 789         int idx;
 790         assert(method.isMethodHandleInvoke());
 791         switch (method.getName()) {
 792         case "invoke":       idx = 0; break;
 793         case "invokeExact":  idx = 1; break;
 794         default:             throw new InternalError(method.getName());
 795         }
 796         MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
 797         if (mh != null)  return mh;
 798         MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
 799                                                 MethodHandle.class, Object[].class);
 800         mh = throwException(type);
 801         mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
 802         if (!method.getInvocationType().equals(mh.type()))
 803             throw new InternalError(method.toString());
 804         mh = mh.withInternalMemberName(method);
 805         mh = mh.asVarargsCollector(Object[].class);
 806         assert(method.isVarargs());
 807         FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
 808         return mh;
 809     }
 810 
 811     /**
 812      * Create an alias for the method handle which, when called,
 813      * appears to be called from the same class loader and protection domain
 814      * as hostClass.
 815      * This is an expensive no-op unless the method which is called
 816      * is sensitive to its caller.  A small number of system methods
 817      * are in this category, including Class.forName and Method.invoke.
 818      */
 819     static
 820     MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
 821         return BindCaller.bindCaller(mh, hostClass);
 822     }
 823 
 824     // Put the whole mess into its own nested class.
 825     // That way we can lazily load the code and set up the constants.
 826     private static class BindCaller {
 827         static
 828         MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
 829             // Do not use this function to inject calls into system classes.
 830             if (hostClass == null
 831                 ||    (hostClass.isArray() ||
 832                        hostClass.isPrimitive() ||
 833                        hostClass.getName().startsWith("java.") ||
 834                        hostClass.getName().startsWith("sun."))) {
 835                 throw new InternalError();  // does not happen, and should not anyway
 836             }
 837             // For simplicity, convert mh to a varargs-like method.
 838             MethodHandle vamh = prepareForInvoker(mh);
 839             // Cache the result of makeInjectedInvoker once per argument class.
 840             MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
 841             return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
 842         }
 843 
 844         private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
 845             Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null);
 846             if (hostClass.getClassLoader() != bcc.getClassLoader())
 847                 throw new InternalError(hostClass.getName()+" (CL)");
 848             try {
 849                 if (hostClass.getProtectionDomain() != bcc.getProtectionDomain())
 850                     throw new InternalError(hostClass.getName()+" (PD)");
 851             } catch (SecurityException ex) {
 852                 // Self-check was blocked by security manager.  This is OK.
 853                 // In fact the whole try body could be turned into an assertion.
 854             }
 855             try {
 856                 MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class));
 857                 init.invokeExact();  // force initialization of the class
 858             } catch (Throwable ex) {
 859                 throw uncaughtException(ex);
 860             }
 861             MethodHandle bccInvoker;
 862             try {
 863                 MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
 864                 bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT);
 865             } catch (ReflectiveOperationException ex) {
 866                 throw uncaughtException(ex);
 867             }
 868             // Test the invoker, to ensure that it really injects into the right place.
 869             try {
 870                 MethodHandle vamh = prepareForInvoker(MH_checkCallerClass);
 871                 Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc});
 872             } catch (Throwable ex) {
 873                 throw new InternalError(ex);
 874             }
 875             return bccInvoker;
 876         }
 877         private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() {
 878             @Override protected MethodHandle computeValue(Class<?> hostClass) {
 879                 return makeInjectedInvoker(hostClass);
 880             }
 881         };
 882 
 883         // Adapt mh so that it can be called directly from an injected invoker:
 884         private static MethodHandle prepareForInvoker(MethodHandle mh) {
 885             mh = mh.asFixedArity();
 886             MethodType mt = mh.type();
 887             int arity = mt.parameterCount();
 888             MethodHandle vamh = mh.asType(mt.generic());
 889             vamh.internalForm().compileToBytecode();  // eliminate LFI stack frames
 890             vamh = vamh.asSpreader(Object[].class, arity);
 891             vamh.internalForm().compileToBytecode();  // eliminate LFI stack frames
 892             return vamh;
 893         }
 894 
 895         // Undo the adapter effect of prepareForInvoker:
 896         private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
 897                                                   MemberName member,
 898                                                   Class<?> hostClass) {
 899             MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
 900             mh = mh.asType(type);
 901             mh = new WrappedMember(mh, type, member, hostClass);
 902             return mh;
 903         }
 904 
 905         private static final MethodHandle MH_checkCallerClass;
 906         static {
 907             final Class<?> THIS_CLASS = BindCaller.class;
 908             assert(checkCallerClass(THIS_CLASS, THIS_CLASS));
 909             try {
 910                 MH_checkCallerClass = IMPL_LOOKUP
 911                     .findStatic(THIS_CLASS, "checkCallerClass",
 912                                 MethodType.methodType(boolean.class, Class.class, Class.class));
 913                 assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS));
 914             } catch (Throwable ex) {
 915                 throw new InternalError(ex);
 916             }
 917         }
 918 
 919         @CallerSensitive
 920         private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) {
 921             // This method is called via MH_checkCallerClass and so it's
 922             // correct to ask for the immediate caller here.
 923             Class<?> actual = Reflection.getCallerClass();
 924             if (actual != expected && actual != expected2)
 925                 throw new InternalError("found "+actual.getName()+", expected "+expected.getName()
 926                                         +(expected == expected2 ? "" : ", or else "+expected2.getName()));
 927             return true;
 928         }
 929 
 930         private static final byte[] T_BYTES;
 931         static {
 932             final Object[] values = {null};
 933             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 934                     public Void run() {
 935                         try {
 936                             Class<T> tClass = T.class;
 937                             String tName = tClass.getName();
 938                             String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class";
 939                             java.net.URLConnection uconn = tClass.getResource(tResource).openConnection();
 940                             int len = uconn.getContentLength();
 941                             byte[] bytes = new byte[len];
 942                             try (java.io.InputStream str = uconn.getInputStream()) {
 943                                 int nr = str.read(bytes);
 944                                 if (nr != len)  throw new java.io.IOException(tResource);
 945                             }
 946                             values[0] = bytes;
 947                         } catch (java.io.IOException ex) {
 948                             throw new InternalError(ex);
 949                         }
 950                         return null;
 951                     }
 952                 });
 953             T_BYTES = (byte[]) values[0];
 954         }
 955 
 956         // The following class is used as a template for Unsafe.defineAnonymousClass:
 957         private static class T {
 958             static void init() { }  // side effect: initializes this class
 959             static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable {
 960                 return vamh.invokeExact(args);
 961             }
 962         }
 963     }
 964 
 965 
 966     /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
 967     static class WrappedMember extends MethodHandle {
 968         private final MethodHandle target;
 969         private final MemberName member;
 970         private final Class<?> callerClass;
 971 
 972         private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) {
 973             super(type, reinvokerForm(target));
 974             this.target = target;
 975             this.member = member;
 976             this.callerClass = callerClass;
 977         }
 978 
 979         @Override
 980         MethodHandle reinvokerTarget() {
 981             return target;
 982         }
 983         @Override
 984         public MethodHandle asTypeUncached(MethodType newType) {
 985             // This MH is an alias for target, except for the MemberName
 986             // Drop the MemberName if there is any conversion.
 987             return asTypeCache = target.asType(newType);
 988         }
 989         @Override
 990         MemberName internalMemberName() {
 991             return member;
 992         }
 993         @Override
 994         Class<?> internalCallerClass() {
 995             return callerClass;
 996         }
 997         @Override
 998         boolean isInvokeSpecial() {
 999             return target.isInvokeSpecial();
1000         }
1001         @Override
1002         MethodHandle viewAsType(MethodType newType) {
1003             return new WrappedMember(target, newType, member, callerClass);
1004         }
1005     }
1006 
1007     static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
1008         if (member.equals(target.internalMemberName()))
1009             return target;
1010         return new WrappedMember(target, target.type(), member, null);
1011     }
1012 
1013 }