src/share/classes/java/lang/invoke/MethodHandleImpl.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File jdk Sdiff src/share/classes/java/lang/invoke

src/share/classes/java/lang/invoke/MethodHandleImpl.java

Print this page
rev 10271 : 8037209: Improvements and cleanups to bytecode assembly for lambda forms
Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
rev 10272 : 8038261: JSR292: cache and reuse typed array accessors
Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
rev 10273 : 8049555: Move varargsArray from sun.invoke.util package to java.lang.invoke
Reviewed-by: ?
rev 10274 : 8050052: Small cleanups in java.lang.invoke code
Reviewed-by: ?
rev 10276 : 8050166: Get rid of some package-private methods on arguments in j.l.i.MethodHandle
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10277 : 8050173: Add j.l.i.MethodHandle.copyWith(MethodType, LambdaForm)
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10278 : 8050174: Support overriding of isInvokeSpecial flag in WrappedMember
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10279 : 8050057: Improve caching of MethodHandle reinvokers
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10280 : 8050200: Make LambdaForm intrinsics detection more robust
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10281 : [mq]: 11.8050877.conv


 162         }
 163         static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
 164             String     name = name(arrayClass, isSetter);
 165             MethodType type = type(arrayClass, isSetter);
 166             try {
 167                 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
 168             } catch (ReflectiveOperationException ex) {
 169                 throw uncaughtException(ex);
 170             }
 171         }
 172     }
 173 
 174     /**
 175      * Create a JVM-level adapter method handle to conform the given method
 176      * handle to the similar newType, using only pairwise argument conversions.
 177      * For each argument, convert incoming argument to the exact type needed.
 178      * The argument conversions allowed are casting, boxing and unboxing,
 179      * integral widening or narrowing, and floating point widening or narrowing.
 180      * @param srcType required call type
 181      * @param target original method handle
 182      * @param level which strength of conversion is allowed

 183      * @return an adapter to the original handle with the desired new type,
 184      *          or the original target if the types are already identical
 185      *          or null if the adaptation cannot be made
 186      */
 187     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
 188         assert(level >= 0 && level <= 2);
 189         MethodType dstType = target.type();
 190         assert(dstType.parameterCount() == target.type().parameterCount());
 191         if (srcType == dstType)
 192             return target;


 193 
 194         // Calculate extra arguments (temporaries) required in the names array.
 195         // FIXME: Use an ArrayList<Name>.  Some arguments require more than one conversion step.
 196         final int INARG_COUNT = srcType.parameterCount();
 197         int conversions = 0;
 198         boolean[] needConv = new boolean[1+INARG_COUNT];
 199         for (int i = 0; i <= INARG_COUNT; i++) {
 200             Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
 201             Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
 202             if (!VerifyType.isNullConversion(src, dst, false) ||
 203                 level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
 204                 needConv[i] = true;
 205                 conversions++;
 206             }

 207         }
 208         boolean retConv = needConv[INARG_COUNT];
 209         if (retConv && srcType.returnType() == void.class) {









 210             retConv = false;
 211             conversions--;
 212         }
 213 
 214         final int IN_MH         = 0;
 215         final int INARG_BASE    = 1;
 216         final int INARG_LIMIT   = INARG_BASE + INARG_COUNT;
 217         final int NAME_LIMIT    = INARG_LIMIT + conversions + 1;
 218         final int RETURN_CONV   = (!retConv ? -1         : NAME_LIMIT - 1);
 219         final int OUT_CALL      = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
 220         final int RESULT        = (srcType.returnType() == void.class ? -1 : NAME_LIMIT - 1);
 221 
 222         // Now build a LambdaForm.
 223         MethodType lambdaType = srcType.basicType().invokerType();
 224         Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
 225 
 226         // Collect the arguments to the outgoing call, maybe with conversions:
 227         final int OUTARG_BASE = 0;  // target MH is Name.function, name Name.arguments[0]
 228         Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
 229 
 230         int nameCursor = INARG_LIMIT;
 231         for (int i = 0; i < INARG_COUNT; i++) {
 232             Class<?> src = srcType.parameterType(i);
 233             Class<?> dst = dstType.parameterType(i);
 234 
 235             if (!needConv[i]) {
 236                 // do nothing: difference is trivial
 237                 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
 238                 continue;
 239             }
 240 
 241             // Tricky case analysis follows.
 242             MethodHandle fn = null;
 243             if (src.isPrimitive()) {
 244                 if (dst.isPrimitive()) {
 245                     fn = ValueConversions.convertPrimitive(src, dst);
 246                 } else {
 247                     Wrapper w = Wrapper.forPrimitiveType(src);
 248                     MethodHandle boxMethod = ValueConversions.box(w);
 249                     if (dst == w.wrapperType())
 250                         fn = boxMethod;
 251                     else
 252                         fn = boxMethod.asType(MethodType.methodType(dst, src));
 253                 }
 254             } else {
 255                 if (dst.isPrimitive()) {
 256                     // Caller has boxed a primitive.  Unbox it for the target.
 257                     Wrapper w = Wrapper.forPrimitiveType(dst);
 258                     if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType(), false)) {
 259                         fn = ValueConversions.unbox(dst);
 260                     } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
 261                         // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
 262                         // must include additional conversions
 263                         // src must be examined at runtime, to detect Byte, Character, etc.
 264                         MethodHandle unboxMethod = (level == 1
 265                                                     ? ValueConversions.unbox(dst)
 266                                                     : ValueConversions.unboxCast(dst));
 267                         fn = unboxMethod;
 268                     } else {
 269                         // Example: Byte->int
 270                         // Do this by reformulating the problem to Byte->byte.
 271                         Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
 272                         MethodHandle unbox = ValueConversions.unbox(srcPrim);
 273                         // Compose the two conversions.  FIXME:  should make two Names for this job
 274                         fn = unbox.asType(MethodType.methodType(dst, src));
 275                     }
 276                 } else {
 277                     // Simple reference conversion.
 278                     // Note:  Do not check for a class hierarchy relation
 279                     // between src and dst.  In all cases a 'null' argument
 280                     // will pass the cast conversion.
 281                     fn = ValueConversions.cast(dst, Lazy.MH_castReference);
 282                 }
 283             }
 284             Name conv = new Name(fn, names[INARG_BASE + i]);
 285             assert(names[nameCursor] == null);
 286             names[nameCursor++] = conv;
 287             assert(outArgs[OUTARG_BASE + i] == null);
 288             outArgs[OUTARG_BASE + i] = conv;
 289         }
 290 
 291         // Build argument array for the call.
 292         assert(nameCursor == OUT_CALL);
 293         names[OUT_CALL] = new Name(target, outArgs);
 294 
 295         if (RETURN_CONV < 0) {

 296             assert(OUT_CALL == names.length-1);
 297         } else {
 298             Class<?> needReturn = srcType.returnType();
 299             Class<?> haveReturn = dstType.returnType();
 300             MethodHandle fn;
 301             Object[] arg = { names[OUT_CALL] };
 302             if (haveReturn == void.class) {
 303                 // synthesize a zero value for the given void
 304                 Object zero = Wrapper.forBasicType(needReturn).zero();
 305                 fn = MethodHandles.constant(needReturn, zero);
 306                 arg = new Object[0];  // don't pass names[OUT_CALL] to conversion
 307             } else {
 308                 MethodHandle identity = MethodHandles.identity(needReturn);
 309                 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
 310                 fn = makePairwiseConvert(identity, needConversion, level);


 311             }
 312             assert(names[RETURN_CONV] == null);
 313             names[RETURN_CONV] = new Name(fn, arg);
 314             assert(RETURN_CONV == names.length-1);
 315         }
 316 
 317         LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
 318         return SimpleMethodHandle.make(srcType, form);
 319     }
 320 
 321     /**
 322      * Identity function, with reference cast.
 323      * @param t an arbitrary reference type
 324      * @param x an arbitrary reference value
 325      * @return the same value x
 326      */
 327     @ForceInline
 328     @SuppressWarnings("unchecked")
 329     static <T,U> T castReference(Class<? extends T> t, U x) {
 330         // inlined Class.cast because we can't ForceInline it
 331         if (x != null && !t.isInstance(x))
 332             throw newClassCastException(t, x);
 333         return (T) x;
 334     }
 335 
 336     private static ClassCastException newClassCastException(Class<?> t, Object obj) {
 337         return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
 338     }
 339 
 340     static MethodHandle makeReferenceIdentity(Class<?> refType) {
 341         MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
 342         Name[] names = arguments(1, lambdaType);
 343         names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
 344         LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
 345         return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
 346     }
 347 













































































 348     static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
 349         MethodType type = target.type();
 350         int last = type.parameterCount() - 1;
 351         if (type.parameterType(last) != arrayType)
 352             target = target.asType(type.changeParameterType(last, arrayType));
 353         target = target.asFixedArity();  // make sure this attribute is turned off
 354         return new AsVarargsCollector(target, arrayType);
 355     }
 356 
 357     private static final class AsVarargsCollector extends DelegatingMethodHandle {
 358         private final MethodHandle target;
 359         private final Class<?> arrayType;
 360         private @Stable MethodHandle asCollectorCache;
 361 
 362         AsVarargsCollector(MethodHandle target, Class<?> arrayType) {
 363             this(target.type(), target, arrayType);
 364         }
 365         AsVarargsCollector(MethodType type, MethodHandle target, Class<?> arrayType) {
 366             super(type, target);
 367             this.target = target;


 703         names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs);
 704 
 705         lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
 706 
 707         return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform);
 708     }
 709 
 710     static
 711     MethodHandle makeGuardWithCatch(MethodHandle target,
 712                                     Class<? extends Throwable> exType,
 713                                     MethodHandle catcher) {
 714         MethodType type = target.type();
 715         LambdaForm form = makeGuardWithCatchForm(type.basicType());
 716 
 717         // Prepare auxiliary method handles used during LambdaForm interpreation.
 718         // Box arguments and wrap them into Object[]: ValueConversions.array().
 719         MethodType varargsType = type.changeReturnType(Object[].class);
 720         MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType);
 721         // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
 722         MethodHandle unboxResult;
 723         if (type.returnType().isPrimitive()) {
 724             unboxResult = ValueConversions.unbox(type.returnType());






 725         } else {
 726             unboxResult = ValueConversions.identity();
 727         }
 728 
 729         BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
 730         BoundMethodHandle mh;
 731         try {
 732             mh = (BoundMethodHandle)
 733                     data.constructor().invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher,
 734                                                    (Object) collectArgs, (Object) unboxResult);
 735         } catch (Throwable ex) {
 736             throw uncaughtException(ex);
 737         }
 738         assert(mh.type() == type);
 739         return mh;
 740     }
 741 
 742     /**
 743      * Intrinsified during LambdaForm compilation
 744      * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}).
 745      */
 746     @LambdaForm.Hidden


 756     }
 757 
 758     /** Prepend an element {@code elem} to an {@code array}. */
 759     @LambdaForm.Hidden
 760     private static Object[] prepend(Object elem, Object[] array) {
 761         Object[] newArray = new Object[array.length+1];
 762         newArray[0] = elem;
 763         System.arraycopy(array, 0, newArray, 1, array.length);
 764         return newArray;
 765     }
 766 
 767     static
 768     MethodHandle throwException(MethodType type) {
 769         assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
 770         int arity = type.parameterCount();
 771         if (arity > 1) {
 772             MethodHandle mh = throwException(type.dropParameterTypes(1, arity));
 773             mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
 774             return mh;
 775         }
 776         return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2);
 777     }
 778 
 779     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
 780 
 781     static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
 782     static MethodHandle fakeMethodHandleInvoke(MemberName method) {
 783         int idx;
 784         assert(method.isMethodHandleInvoke());
 785         switch (method.getName()) {
 786         case "invoke":       idx = 0; break;
 787         case "invokeExact":  idx = 1; break;
 788         default:             throw new InternalError(method.getName());
 789         }
 790         MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
 791         if (mh != null)  return mh;
 792         MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
 793                                                 MethodHandle.class, Object[].class);
 794         mh = throwException(type);
 795         mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
 796         if (!method.getInvocationType().equals(mh.type()))




 162         }
 163         static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
 164             String     name = name(arrayClass, isSetter);
 165             MethodType type = type(arrayClass, isSetter);
 166             try {
 167                 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
 168             } catch (ReflectiveOperationException ex) {
 169                 throw uncaughtException(ex);
 170             }
 171         }
 172     }
 173 
 174     /**
 175      * Create a JVM-level adapter method handle to conform the given method
 176      * handle to the similar newType, using only pairwise argument conversions.
 177      * For each argument, convert incoming argument to the exact type needed.
 178      * The argument conversions allowed are casting, boxing and unboxing,
 179      * integral widening or narrowing, and floating point widening or narrowing.
 180      * @param srcType required call type
 181      * @param target original method handle
 182      * @param strict if true, only asType conversions are allowed; if false, explicitCastArguments conversions allowed
 183      * @param monobox if true, unboxing conversions are assumed to be exactly typed (Integer to int only, not long or double)
 184      * @return an adapter to the original handle with the desired new type,
 185      *          or the original target if the types are already identical
 186      *          or null if the adaptation cannot be made
 187      */
 188     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
 189                                             boolean strict, boolean monobox) {
 190         MethodType dstType = target.type();
 191         assert(dstType.parameterCount() == target.type().parameterCount());
 192         if (srcType == dstType)
 193             return target;
 194         return makePairwiseConvertIndirect(target, srcType, strict, monobox);
 195     }
 196 
 197     private static int countNonNull(Object[] array) {
 198         int count = 0;
 199         for (Object x : array) {
 200             if (x != null)  ++count;








 201         }
 202         return count;
 203     }
 204 
 205     static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType,
 206                                                     boolean strict, boolean monobox) {
 207         // Calculate extra arguments (temporaries) required in the names array.
 208         Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
 209         final int INARG_COUNT = srcType.parameterCount();
 210         int convCount = countNonNull(convSpecs);
 211         boolean retConv = (convSpecs[INARG_COUNT] != null);
 212         boolean retVoid = srcType.returnType() == void.class;
 213         if (retConv && retVoid) {
 214             convCount -= 1;
 215             retConv = false;

 216         }
 217 
 218         final int IN_MH         = 0;
 219         final int INARG_BASE    = 1;
 220         final int INARG_LIMIT   = INARG_BASE + INARG_COUNT;
 221         final int NAME_LIMIT    = INARG_LIMIT + convCount + 1;
 222         final int RETURN_CONV   = (!retConv ? -1         : NAME_LIMIT - 1);
 223         final int OUT_CALL      = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
 224         final int RESULT        = (retVoid ? -1 : NAME_LIMIT - 1);
 225 
 226         // Now build a LambdaForm.
 227         MethodType lambdaType = srcType.basicType().invokerType();
 228         Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
 229 
 230         // Collect the arguments to the outgoing call, maybe with conversions:
 231         final int OUTARG_BASE = 0;  // target MH is Name.function, name Name.arguments[0]
 232         Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
 233 
 234         int nameCursor = INARG_LIMIT;
 235         for (int i = 0; i < INARG_COUNT; i++) {
 236             Object convSpec = convSpecs[i];
 237             if (convSpec == null) {


 238                 // do nothing: difference is trivial
 239                 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
 240                 continue;
 241             }
 242 
 243             Name conv;
 244             if (convSpec instanceof Class) {
 245                 Class<?> convClass = (Class<?>) convSpec;
 246                 conv = new Name(Lazy.MH_castReference, convClass, names[INARG_BASE + i]);























 247             } else {
 248                 MethodHandle fn = (MethodHandle) convSpec;
 249                 conv = new Name(fn, names[INARG_BASE + i]);




 250             }









 251             assert(names[nameCursor] == null);
 252             names[nameCursor++] = conv;
 253             assert(outArgs[OUTARG_BASE + i] == null);
 254             outArgs[OUTARG_BASE + i] = conv;
 255         }
 256 
 257         // Build argument array for the call.
 258         assert(nameCursor == OUT_CALL);
 259         names[OUT_CALL] = new Name(target, outArgs);
 260 
 261         Object convSpec = convSpecs[INARG_COUNT];
 262         if (!retConv) {
 263             assert(OUT_CALL == names.length-1);
 264         } else {
 265             Name conv;
 266             if (convSpec == void.class) {
 267                 conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
 268             } else if (convSpec instanceof Class) {
 269                 Class<?> convClass = (Class<?>) convSpec;
 270                 conv = new Name(Lazy.MH_castReference, convClass, names[OUT_CALL]);



 271             } else {
 272                 MethodHandle fn = (MethodHandle) convSpec;
 273                 if (fn.type().parameterCount() == 0)
 274                     conv = new Name(fn);  // don't pass retval to void conversion
 275                 else
 276                     conv = new Name(fn, names[OUT_CALL]);
 277             }
 278             assert(names[RETURN_CONV] == null);
 279             names[RETURN_CONV] = conv;
 280             assert(RETURN_CONV == names.length-1);
 281         }
 282 
 283         LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
 284         return SimpleMethodHandle.make(srcType, form);
 285     }
 286 
 287     /**
 288      * Identity function, with reference cast.
 289      * @param t an arbitrary reference type
 290      * @param x an arbitrary reference value
 291      * @return the same value x
 292      */
 293     @ForceInline
 294     @SuppressWarnings("unchecked")
 295     static <T,U> T castReference(Class<? extends T> t, U x) {
 296         // inlined Class.cast because we can't ForceInline it
 297         if (x != null && !t.isInstance(x))
 298             throw newClassCastException(t, x);
 299         return (T) x;
 300     }
 301 
 302     private static ClassCastException newClassCastException(Class<?> t, Object obj) {
 303         return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
 304     }
 305 
 306     static MethodHandle makeReferenceIdentity(Class<?> refType) {
 307         MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
 308         Name[] names = arguments(1, lambdaType);
 309         names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
 310         LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
 311         return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
 312     }
 313 
 314     static Object[] computeValueConversions(MethodType srcType, MethodType dstType,
 315                                             boolean strict, boolean monobox) {
 316         final int INARG_COUNT = srcType.parameterCount();
 317         Object[] convSpecs = new Object[INARG_COUNT+1];
 318         for (int i = 0; i <= INARG_COUNT; i++) {
 319             boolean isRet = (i == INARG_COUNT);
 320             Class<?> src = isRet ? dstType.returnType() : srcType.parameterType(i);
 321             Class<?> dst = isRet ? srcType.returnType() : dstType.parameterType(i);
 322             if (!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)) {
 323                 convSpecs[i] = valueConversion(src, dst, strict, monobox);
 324             }
 325         }
 326         return convSpecs;
 327     }
 328     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
 329                                             boolean strict) {
 330         return makePairwiseConvert(target, srcType, strict, /*monobox=*/ false);
 331     }
 332 
 333     /**
 334      * Find a conversion function from the given source to the given destination.
 335      * This conversion function will be used as a LF NamedFunction.
 336      * Return a Class object if a simple cast is needed.
 337      * Return void.class if void is involved.
 338      */
 339     static Object valueConversion(Class<?> src, Class<?> dst, boolean strict, boolean monobox) {
 340         assert(!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict));  // caller responsibility
 341         if (dst == void.class)
 342             return dst;
 343         MethodHandle fn;
 344         if (src.isPrimitive()) {
 345             if (src == void.class) {
 346                 return void.class;  // caller must recognize this specially
 347             } else if (dst.isPrimitive()) {
 348                 // Examples: int->byte, byte->int, boolean->int (!strict)
 349                 fn = ValueConversions.convertPrimitive(src, dst);
 350             } else {
 351                 // Examples: int->Integer, boolean->Object, float->Number
 352                 Wrapper wsrc = Wrapper.forPrimitiveType(src);
 353                 fn = ValueConversions.boxExact(wsrc);
 354                 assert(fn.type().parameterType(0) == wsrc.primitiveType());
 355                 assert(fn.type().returnType() == wsrc.wrapperType());
 356                 if (!VerifyType.isNullConversion(wsrc.wrapperType(), dst, strict)) {
 357                     // Corner case, such as int->Long, which will probably fail.
 358                     MethodType mt = MethodType.methodType(dst, src);
 359                     if (strict)
 360                         fn = fn.asType(mt);
 361                     else
 362                         fn = MethodHandleImpl.makePairwiseConvert(fn, mt, /*strict=*/ false);
 363                 }
 364             }
 365         } else {
 366             if (dst.isPrimitive()) {
 367                 Wrapper wdst = Wrapper.forPrimitiveType(dst);
 368                 if (monobox || src == wdst.wrapperType()) {
 369                     // Use a strongly-typed unboxer, if possible.
 370                     fn = ValueConversions.unboxExact(wdst, strict);
 371                 } else {
 372                     // Examples:  Object->int, Number->int, Comparable->int, Byte->int
 373                     // must include additional conversions
 374                     // src must be examined at runtime, to detect Byte, Character, etc.
 375                     fn = (strict
 376                           ? ValueConversions.unboxWiden(wdst)
 377                           : ValueConversions.unboxCast(wdst));
 378                 }
 379             } else {
 380                 // Simple reference conversion.
 381                 // Note:  Do not check for a class hierarchy relation
 382                 // between src and dst.  In all cases a 'null' argument
 383                 // will pass the cast conversion.
 384                 return dst;
 385             }
 386         }
 387         assert(fn.type().parameterCount() <= 1) : "pc"+Arrays.asList(src.getSimpleName(), dst.getSimpleName(), fn);
 388         return fn;
 389     }
 390 
 391     static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
 392         MethodType type = target.type();
 393         int last = type.parameterCount() - 1;
 394         if (type.parameterType(last) != arrayType)
 395             target = target.asType(type.changeParameterType(last, arrayType));
 396         target = target.asFixedArity();  // make sure this attribute is turned off
 397         return new AsVarargsCollector(target, arrayType);
 398     }
 399 
 400     private static final class AsVarargsCollector extends DelegatingMethodHandle {
 401         private final MethodHandle target;
 402         private final Class<?> arrayType;
 403         private @Stable MethodHandle asCollectorCache;
 404 
 405         AsVarargsCollector(MethodHandle target, Class<?> arrayType) {
 406             this(target.type(), target, arrayType);
 407         }
 408         AsVarargsCollector(MethodType type, MethodHandle target, Class<?> arrayType) {
 409             super(type, target);
 410             this.target = target;


 746         names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs);
 747 
 748         lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
 749 
 750         return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform);
 751     }
 752 
 753     static
 754     MethodHandle makeGuardWithCatch(MethodHandle target,
 755                                     Class<? extends Throwable> exType,
 756                                     MethodHandle catcher) {
 757         MethodType type = target.type();
 758         LambdaForm form = makeGuardWithCatchForm(type.basicType());
 759 
 760         // Prepare auxiliary method handles used during LambdaForm interpreation.
 761         // Box arguments and wrap them into Object[]: ValueConversions.array().
 762         MethodType varargsType = type.changeReturnType(Object[].class);
 763         MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType);
 764         // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
 765         MethodHandle unboxResult;
 766         Class<?> rtype = type.returnType();
 767         if (rtype.isPrimitive()) {
 768             if (rtype == void.class) {
 769                 unboxResult = ValueConversions.ignore();
 770             } else {
 771                 Wrapper w = Wrapper.forPrimitiveType(type.returnType());
 772                 unboxResult = ValueConversions.unboxExact(w);
 773             }
 774         } else {
 775             unboxResult = MethodHandles.identity(Object.class);
 776         }
 777 
 778         BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
 779         BoundMethodHandle mh;
 780         try {
 781             mh = (BoundMethodHandle)
 782                     data.constructor().invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher,
 783                                                    (Object) collectArgs, (Object) unboxResult);
 784         } catch (Throwable ex) {
 785             throw uncaughtException(ex);
 786         }
 787         assert(mh.type() == type);
 788         return mh;
 789     }
 790 
 791     /**
 792      * Intrinsified during LambdaForm compilation
 793      * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}).
 794      */
 795     @LambdaForm.Hidden


 805     }
 806 
 807     /** Prepend an element {@code elem} to an {@code array}. */
 808     @LambdaForm.Hidden
 809     private static Object[] prepend(Object elem, Object[] array) {
 810         Object[] newArray = new Object[array.length+1];
 811         newArray[0] = elem;
 812         System.arraycopy(array, 0, newArray, 1, array.length);
 813         return newArray;
 814     }
 815 
 816     static
 817     MethodHandle throwException(MethodType type) {
 818         assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
 819         int arity = type.parameterCount();
 820         if (arity > 1) {
 821             MethodHandle mh = throwException(type.dropParameterTypes(1, arity));
 822             mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
 823             return mh;
 824         }
 825         return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true);
 826     }
 827 
 828     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
 829 
 830     static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
 831     static MethodHandle fakeMethodHandleInvoke(MemberName method) {
 832         int idx;
 833         assert(method.isMethodHandleInvoke());
 834         switch (method.getName()) {
 835         case "invoke":       idx = 0; break;
 836         case "invokeExact":  idx = 1; break;
 837         default:             throw new InternalError(method.getName());
 838         }
 839         MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
 840         if (mh != null)  return mh;
 841         MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
 842                                                 MethodHandle.class, Object[].class);
 843         mh = throwException(type);
 844         mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
 845         if (!method.getInvocationType().equals(mh.type()))


src/share/classes/java/lang/invoke/MethodHandleImpl.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File