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