jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
changeset 26474 655d08549e43
parent 26473 0abc9399a1a6
child 26475 acf0c98309d3
equal deleted inserted replaced
26473:0abc9399a1a6 26474:655d08549e43
   177      * For each argument, convert incoming argument to the exact type needed.
   177      * For each argument, convert incoming argument to the exact type needed.
   178      * The argument conversions allowed are casting, boxing and unboxing,
   178      * The argument conversions allowed are casting, boxing and unboxing,
   179      * integral widening or narrowing, and floating point widening or narrowing.
   179      * integral widening or narrowing, and floating point widening or narrowing.
   180      * @param srcType required call type
   180      * @param srcType required call type
   181      * @param target original method handle
   181      * @param target original method handle
   182      * @param level which strength of conversion is allowed
   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)
   183      * @return an adapter to the original handle with the desired new type,
   184      * @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 the original target if the types are already identical
   185      *          or null if the adaptation cannot be made
   186      *          or null if the adaptation cannot be made
   186      */
   187      */
   187     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
   188     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
   188         assert(level >= 0 && level <= 2);
   189                                             boolean strict, boolean monobox) {
   189         MethodType dstType = target.type();
   190         MethodType dstType = target.type();
   190         assert(dstType.parameterCount() == target.type().parameterCount());
   191         assert(dstType.parameterCount() == target.type().parameterCount());
   191         if (srcType == dstType)
   192         if (srcType == dstType)
   192             return target;
   193             return target;
   193 
   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) {
   194         // Calculate extra arguments (temporaries) required in the names array.
   207         // Calculate extra arguments (temporaries) required in the names array.
   195         // FIXME: Use an ArrayList<Name>.  Some arguments require more than one conversion step.
   208         Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
   196         final int INARG_COUNT = srcType.parameterCount();
   209         final int INARG_COUNT = srcType.parameterCount();
   197         int conversions = 0;
   210         int convCount = countNonNull(convSpecs);
   198         boolean[] needConv = new boolean[1+INARG_COUNT];
   211         boolean retConv = (convSpecs[INARG_COUNT] != null);
   199         for (int i = 0; i <= INARG_COUNT; i++) {
   212         boolean retVoid = srcType.returnType() == void.class;
   200             Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
   213         if (retConv && retVoid) {
   201             Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
   214             convCount -= 1;
   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;
   215             retConv = false;
   211             conversions--;
       
   212         }
   216         }
   213 
   217 
   214         final int IN_MH         = 0;
   218         final int IN_MH         = 0;
   215         final int INARG_BASE    = 1;
   219         final int INARG_BASE    = 1;
   216         final int INARG_LIMIT   = INARG_BASE + INARG_COUNT;
   220         final int INARG_LIMIT   = INARG_BASE + INARG_COUNT;
   217         final int NAME_LIMIT    = INARG_LIMIT + conversions + 1;
   221         final int NAME_LIMIT    = INARG_LIMIT + convCount + 1;
   218         final int RETURN_CONV   = (!retConv ? -1         : NAME_LIMIT - 1);
   222         final int RETURN_CONV   = (!retConv ? -1         : NAME_LIMIT - 1);
   219         final int OUT_CALL      = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
   223         final int OUT_CALL      = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
   220         final int RESULT        = (srcType.returnType() == void.class ? -1 : NAME_LIMIT - 1);
   224         final int RESULT        = (retVoid ? -1 : NAME_LIMIT - 1);
   221 
   225 
   222         // Now build a LambdaForm.
   226         // Now build a LambdaForm.
   223         MethodType lambdaType = srcType.basicType().invokerType();
   227         MethodType lambdaType = srcType.basicType().invokerType();
   224         Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
   228         Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
   225 
   229 
   227         final int OUTARG_BASE = 0;  // target MH is Name.function, name Name.arguments[0]
   231         final int OUTARG_BASE = 0;  // target MH is Name.function, name Name.arguments[0]
   228         Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
   232         Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
   229 
   233 
   230         int nameCursor = INARG_LIMIT;
   234         int nameCursor = INARG_LIMIT;
   231         for (int i = 0; i < INARG_COUNT; i++) {
   235         for (int i = 0; i < INARG_COUNT; i++) {
   232             Class<?> src = srcType.parameterType(i);
   236             Object convSpec = convSpecs[i];
   233             Class<?> dst = dstType.parameterType(i);
   237             if (convSpec == null) {
   234 
       
   235             if (!needConv[i]) {
       
   236                 // do nothing: difference is trivial
   238                 // do nothing: difference is trivial
   237                 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
   239                 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
   238                 continue;
   240                 continue;
   239             }
   241             }
   240 
   242 
   241             // Tricky case analysis follows.
   243             Name conv;
   242             MethodHandle fn = null;
   244             if (convSpec instanceof Class) {
   243             if (src.isPrimitive()) {
   245                 Class<?> convClass = (Class<?>) convSpec;
   244                 if (dst.isPrimitive()) {
   246                 conv = new Name(Lazy.MH_castReference, convClass, names[INARG_BASE + i]);
   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 {
   247             } else {
   255                 if (dst.isPrimitive()) {
   248                 MethodHandle fn = (MethodHandle) convSpec;
   256                     // Caller has boxed a primitive.  Unbox it for the target.
   249                 conv = new Name(fn, names[INARG_BASE + i]);
   257                     Wrapper w = Wrapper.forPrimitiveType(dst);
   250             }
   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);
   251             assert(names[nameCursor] == null);
   286             names[nameCursor++] = conv;
   252             names[nameCursor++] = conv;
   287             assert(outArgs[OUTARG_BASE + i] == null);
   253             assert(outArgs[OUTARG_BASE + i] == null);
   288             outArgs[OUTARG_BASE + i] = conv;
   254             outArgs[OUTARG_BASE + i] = conv;
   289         }
   255         }
   290 
   256 
   291         // Build argument array for the call.
   257         // Build argument array for the call.
   292         assert(nameCursor == OUT_CALL);
   258         assert(nameCursor == OUT_CALL);
   293         names[OUT_CALL] = new Name(target, outArgs);
   259         names[OUT_CALL] = new Name(target, outArgs);
   294 
   260 
   295         if (RETURN_CONV < 0) {
   261         Object convSpec = convSpecs[INARG_COUNT];
       
   262         if (!retConv) {
   296             assert(OUT_CALL == names.length-1);
   263             assert(OUT_CALL == names.length-1);
   297         } else {
   264         } else {
   298             Class<?> needReturn = srcType.returnType();
   265             Name conv;
   299             Class<?> haveReturn = dstType.returnType();
   266             if (convSpec == void.class) {
   300             MethodHandle fn;
   267                 conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
   301             Object[] arg = { names[OUT_CALL] };
   268             } else if (convSpec instanceof Class) {
   302             if (haveReturn == void.class) {
   269                 Class<?> convClass = (Class<?>) convSpec;
   303                 // synthesize a zero value for the given void
   270                 conv = new Name(Lazy.MH_castReference, convClass, names[OUT_CALL]);
   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 {
   271             } else {
   308                 MethodHandle identity = MethodHandles.identity(needReturn);
   272                 MethodHandle fn = (MethodHandle) convSpec;
   309                 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
   273                 if (fn.type().parameterCount() == 0)
   310                 fn = makePairwiseConvert(identity, needConversion, level);
   274                     conv = new Name(fn);  // don't pass retval to void conversion
       
   275                 else
       
   276                     conv = new Name(fn, names[OUT_CALL]);
   311             }
   277             }
   312             assert(names[RETURN_CONV] == null);
   278             assert(names[RETURN_CONV] == null);
   313             names[RETURN_CONV] = new Name(fn, arg);
   279             names[RETURN_CONV] = conv;
   314             assert(RETURN_CONV == names.length-1);
   280             assert(RETURN_CONV == names.length-1);
   315         }
   281         }
   316 
   282 
   317         LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
   283         LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
   318         return SimpleMethodHandle.make(srcType, form);
   284         return SimpleMethodHandle.make(srcType, form);
   341         MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
   307         MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
   342         Name[] names = arguments(1, lambdaType);
   308         Name[] names = arguments(1, lambdaType);
   343         names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
   309         names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
   344         LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
   310         LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
   345         return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
   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 if (dst.isPrimitive()) {
       
   366             Wrapper wdst = Wrapper.forPrimitiveType(dst);
       
   367             if (monobox || src == wdst.wrapperType()) {
       
   368                 // Use a strongly-typed unboxer, if possible.
       
   369                 fn = ValueConversions.unboxExact(wdst, strict);
       
   370             } else {
       
   371                 // Examples:  Object->int, Number->int, Comparable->int, Byte->int
       
   372                 // must include additional conversions
       
   373                 // src must be examined at runtime, to detect Byte, Character, etc.
       
   374                 fn = (strict
       
   375                         ? ValueConversions.unboxWiden(wdst)
       
   376                         : ValueConversions.unboxCast(wdst));
       
   377             }
       
   378         } else {
       
   379             // Simple reference conversion.
       
   380             // Note:  Do not check for a class hierarchy relation
       
   381             // between src and dst.  In all cases a 'null' argument
       
   382             // will pass the cast conversion.
       
   383             return dst;
       
   384         }
       
   385         assert(fn.type().parameterCount() <= 1) : "pc"+Arrays.asList(src.getSimpleName(), dst.getSimpleName(), fn);
       
   386         return fn;
   346     }
   387     }
   347 
   388 
   348     static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
   389     static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
   349         MethodType type = target.type();
   390         MethodType type = target.type();
   350         int last = type.parameterCount() - 1;
   391         int last = type.parameterCount() - 1;
   718         // Box arguments and wrap them into Object[]: ValueConversions.array().
   759         // Box arguments and wrap them into Object[]: ValueConversions.array().
   719         MethodType varargsType = type.changeReturnType(Object[].class);
   760         MethodType varargsType = type.changeReturnType(Object[].class);
   720         MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType);
   761         MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType);
   721         // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
   762         // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
   722         MethodHandle unboxResult;
   763         MethodHandle unboxResult;
   723         if (type.returnType().isPrimitive()) {
   764         Class<?> rtype = type.returnType();
   724             unboxResult = ValueConversions.unbox(type.returnType());
   765         if (rtype.isPrimitive()) {
       
   766             if (rtype == void.class) {
       
   767                 unboxResult = ValueConversions.ignore();
       
   768             } else {
       
   769                 Wrapper w = Wrapper.forPrimitiveType(type.returnType());
       
   770                 unboxResult = ValueConversions.unboxExact(w);
       
   771             }
   725         } else {
   772         } else {
   726             unboxResult = ValueConversions.identity();
   773             unboxResult = MethodHandles.identity(Object.class);
   727         }
   774         }
   728 
   775 
   729         BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
   776         BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
   730         BoundMethodHandle mh;
   777         BoundMethodHandle mh;
   731         try {
   778         try {
   771         if (arity > 1) {
   818         if (arity > 1) {
   772             MethodHandle mh = throwException(type.dropParameterTypes(1, arity));
   819             MethodHandle mh = throwException(type.dropParameterTypes(1, arity));
   773             mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
   820             mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
   774             return mh;
   821             return mh;
   775         }
   822         }
   776         return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2);
   823         return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true);
   777     }
   824     }
   778 
   825 
   779     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
   826     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
   780 
   827 
   781     static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
   828     static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];