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