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