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