< prev index next >

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

Print this page
rev 12327 : 8062543: Replace uses of MethodHandleImpl.castReference with Class.cast
   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


 201         }
 202         return count;
 203     }
 204 
 205     static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType srcType,
 206                                                     boolean strict, boolean monobox) {
 207         Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
 208         int convCount = countNonNull(convSpecs);
 209         if (convCount == 0)
 210             return target.viewAsType(srcType, strict);
 211         MethodType basicSrcType = srcType.basicType();
 212         MethodType midType = target.type().basicType();
 213         BoundMethodHandle mh = target.rebind();
 214         // FIXME: Reduce number of bindings when there is more than one Class conversion.
 215         // FIXME: Reduce number of bindings when there are repeated conversions.
 216         for (int i = 0; i < convSpecs.length-1; i++) {
 217             Object convSpec = convSpecs[i];
 218             if (convSpec == null)  continue;
 219             MethodHandle fn;
 220             if (convSpec instanceof Class) {
 221                 fn = Lazy.MH_castReference.bindTo(convSpec);
 222             } else {
 223                 fn = (MethodHandle) convSpec;
 224             }
 225             Class<?> newType = basicSrcType.parameterType(i);
 226             if (--convCount == 0)
 227                 midType = srcType;
 228             else
 229                 midType = midType.changeParameterType(i, newType);
 230             LambdaForm form2 = mh.editor().filterArgumentForm(1+i, BasicType.basicType(newType));
 231             mh = mh.copyWithExtendL(midType, form2, fn);
 232             mh = mh.rebind();
 233         }
 234         Object convSpec = convSpecs[convSpecs.length-1];
 235         if (convSpec != null) {
 236             MethodHandle fn;
 237             if (convSpec instanceof Class) {
 238                 if (convSpec == void.class)
 239                     fn = null;
 240                 else
 241                     fn = Lazy.MH_castReference.bindTo(convSpec);
 242             } else {
 243                 fn = (MethodHandle) convSpec;
 244             }
 245             Class<?> newType = basicSrcType.returnType();
 246             assert(--convCount == 0);
 247             midType = srcType;
 248             if (fn != null) {
 249                 mh = mh.rebind();  // rebind if too complex
 250                 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), false);
 251                 mh = mh.copyWithExtendL(midType, form2, fn);
 252             } else {
 253                 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), true);
 254                 mh = mh.copyWith(midType, form2);
 255             }
 256         }
 257         assert(convCount == 0);
 258         assert(mh.type().equals(srcType));
 259         return mh;
 260     }
 261 


 284         // Now build a LambdaForm.
 285         MethodType lambdaType = srcType.basicType().invokerType();
 286         Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
 287 
 288         // Collect the arguments to the outgoing call, maybe with conversions:
 289         final int OUTARG_BASE = 0;  // target MH is Name.function, name Name.arguments[0]
 290         Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
 291 
 292         int nameCursor = INARG_LIMIT;
 293         for (int i = 0; i < INARG_COUNT; i++) {
 294             Object convSpec = convSpecs[i];
 295             if (convSpec == null) {
 296                 // do nothing: difference is trivial
 297                 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
 298                 continue;
 299             }
 300 
 301             Name conv;
 302             if (convSpec instanceof Class) {
 303                 Class<?> convClass = (Class<?>) convSpec;
 304                 conv = new Name(Lazy.MH_castReference, convClass, names[INARG_BASE + i]);
 305             } else {
 306                 MethodHandle fn = (MethodHandle) convSpec;
 307                 conv = new Name(fn, names[INARG_BASE + i]);
 308             }
 309             assert(names[nameCursor] == null);
 310             names[nameCursor++] = conv;
 311             assert(outArgs[OUTARG_BASE + i] == null);
 312             outArgs[OUTARG_BASE + i] = conv;
 313         }
 314 
 315         // Build argument array for the call.
 316         assert(nameCursor == OUT_CALL);
 317         names[OUT_CALL] = new Name(target, outArgs);
 318 
 319         Object convSpec = convSpecs[INARG_COUNT];
 320         if (!retConv) {
 321             assert(OUT_CALL == names.length-1);
 322         } else {
 323             Name conv;
 324             if (convSpec == void.class) {
 325                 conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
 326             } else if (convSpec instanceof Class) {
 327                 Class<?> convClass = (Class<?>) convSpec;
 328                 conv = new Name(Lazy.MH_castReference, convClass, names[OUT_CALL]);
 329             } else {
 330                 MethodHandle fn = (MethodHandle) convSpec;
 331                 if (fn.type().parameterCount() == 0)
 332                     conv = new Name(fn);  // don't pass retval to void conversion
 333                 else
 334                     conv = new Name(fn, names[OUT_CALL]);
 335             }
 336             assert(names[RETURN_CONV] == null);
 337             names[RETURN_CONV] = conv;
 338             assert(RETURN_CONV == names.length-1);
 339         }
 340 
 341         LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
 342         return SimpleMethodHandle.make(srcType, form);
 343     }
 344 
 345     /**
 346      * Identity function, with reference cast.
 347      * @param t an arbitrary reference type
 348      * @param x an arbitrary reference value
 349      * @return the same value x
 350      */
 351     @ForceInline
 352     @SuppressWarnings("unchecked")
 353     static <T,U> T castReference(Class<? extends T> t, U x) {
 354         // inlined Class.cast because we can't ForceInline it
 355         if (x != null && !t.isInstance(x))
 356             throw newClassCastException(t, x);
 357         return (T) x;
 358     }
 359 
 360     private static ClassCastException newClassCastException(Class<?> t, Object obj) {
 361         return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
 362     }
 363 
 364     static Object[] computeValueConversions(MethodType srcType, MethodType dstType,
 365                                             boolean strict, boolean monobox) {
 366         final int INARG_COUNT = srcType.parameterCount();
 367         Object[] convSpecs = new Object[INARG_COUNT+1];
 368         for (int i = 0; i <= INARG_COUNT; i++) {
 369             boolean isRet = (i == INARG_COUNT);
 370             Class<?> src = isRet ? dstType.returnType() : srcType.parameterType(i);
 371             Class<?> dst = isRet ? srcType.returnType() : dstType.parameterType(i);
 372             if (!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)) {
 373                 convSpecs[i] = valueConversion(src, dst, strict, monobox);
 374             }
 375         }
 376         return convSpecs;
 377     }
 378     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
 379                                             boolean strict) {
 380         return makePairwiseConvert(target, srcType, strict, /*monobox=*/ false);
 381     }
 382 
 383     /**


 573     static void checkSpreadArgument(Object av, int n) {
 574         if (av == null) {
 575             if (n == 0)  return;
 576         } else if (av instanceof Object[]) {
 577             int len = ((Object[])av).length;
 578             if (len == n)  return;
 579         } else {
 580             int len = java.lang.reflect.Array.getLength(av);
 581             if (len == n)  return;
 582         }
 583         // fall through to error:
 584         throw newIllegalArgumentException("array is not of length "+n);
 585     }
 586 
 587     /**
 588      * Pre-initialized NamedFunctions for bootstrapping purposes.
 589      * Factored in an inner class to delay initialization until first usage.
 590      */
 591     static class Lazy {
 592         private static final Class<?> MHI = MethodHandleImpl.class;

 593 
 594         private static final MethodHandle[] ARRAYS;
 595         private static final MethodHandle[] FILL_ARRAYS;
 596 
 597         static final NamedFunction NF_checkSpreadArgument;
 598         static final NamedFunction NF_guardWithCatch;
 599         static final NamedFunction NF_throwException;
 600         static final NamedFunction NF_profileBoolean;
 601 
 602         static final MethodHandle MH_castReference;
 603         static final MethodHandle MH_selectAlternative;
 604         static final MethodHandle MH_copyAsPrimitiveArray;
 605         static final MethodHandle MH_fillNewTypedArray;
 606         static final MethodHandle MH_fillNewArray;
 607         static final MethodHandle MH_arrayIdentity;
 608 
 609         static {
 610             ARRAYS      = makeArrays();
 611             FILL_ARRAYS = makeFillArrays();
 612 
 613             try {
 614                 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
 615                 NF_guardWithCatch      = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
 616                                                                                  MethodHandle.class, Object[].class));
 617                 NF_throwException      = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
 618                 NF_profileBoolean      = new NamedFunction(MHI.getDeclaredMethod("profileBoolean", boolean.class, int[].class));
 619 
 620                 NF_checkSpreadArgument.resolve();
 621                 NF_guardWithCatch.resolve();
 622                 NF_throwException.resolve();
 623                 NF_profileBoolean.resolve();
 624 
 625                 MH_castReference        = IMPL_LOOKUP.findStatic(MHI, "castReference",
 626                                             MethodType.methodType(Object.class, Class.class, Object.class));
 627                 MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
 628                                             MethodType.methodType(Object.class, Wrapper.class, Object[].class));
 629                 MH_arrayIdentity        = IMPL_LOOKUP.findStatic(MHI, "identity",
 630                                             MethodType.methodType(Object[].class, Object[].class));
 631                 MH_fillNewArray         = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
 632                                             MethodType.methodType(Object[].class, Integer.class, Object[].class));
 633                 MH_fillNewTypedArray    = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
 634                                             MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
 635 
 636                 MH_selectAlternative    = makeIntrinsic(
 637                         IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
 638                                 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
 639                         Intrinsic.SELECT_ALTERNATIVE);
 640             } catch (ReflectiveOperationException ex) {
 641                 throw newInternalError(ex);
 642             }
 643         }
 644     }
 645 
 646     /** Factory method:  Collect or filter selected argument(s). */


   1 /*
   2  * Copyright (c) 2008, 2015, 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


 201         }
 202         return count;
 203     }
 204 
 205     static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType srcType,
 206                                                     boolean strict, boolean monobox) {
 207         Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
 208         int convCount = countNonNull(convSpecs);
 209         if (convCount == 0)
 210             return target.viewAsType(srcType, strict);
 211         MethodType basicSrcType = srcType.basicType();
 212         MethodType midType = target.type().basicType();
 213         BoundMethodHandle mh = target.rebind();
 214         // FIXME: Reduce number of bindings when there is more than one Class conversion.
 215         // FIXME: Reduce number of bindings when there are repeated conversions.
 216         for (int i = 0; i < convSpecs.length-1; i++) {
 217             Object convSpec = convSpecs[i];
 218             if (convSpec == null)  continue;
 219             MethodHandle fn;
 220             if (convSpec instanceof Class) {
 221                 fn = Lazy.MH_cast.bindTo(convSpec);
 222             } else {
 223                 fn = (MethodHandle) convSpec;
 224             }
 225             Class<?> newType = basicSrcType.parameterType(i);
 226             if (--convCount == 0)
 227                 midType = srcType;
 228             else
 229                 midType = midType.changeParameterType(i, newType);
 230             LambdaForm form2 = mh.editor().filterArgumentForm(1+i, BasicType.basicType(newType));
 231             mh = mh.copyWithExtendL(midType, form2, fn);
 232             mh = mh.rebind();
 233         }
 234         Object convSpec = convSpecs[convSpecs.length-1];
 235         if (convSpec != null) {
 236             MethodHandle fn;
 237             if (convSpec instanceof Class) {
 238                 if (convSpec == void.class)
 239                     fn = null;
 240                 else
 241                     fn = Lazy.MH_cast.bindTo(convSpec);
 242             } else {
 243                 fn = (MethodHandle) convSpec;
 244             }
 245             Class<?> newType = basicSrcType.returnType();
 246             assert(--convCount == 0);
 247             midType = srcType;
 248             if (fn != null) {
 249                 mh = mh.rebind();  // rebind if too complex
 250                 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), false);
 251                 mh = mh.copyWithExtendL(midType, form2, fn);
 252             } else {
 253                 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), true);
 254                 mh = mh.copyWith(midType, form2);
 255             }
 256         }
 257         assert(convCount == 0);
 258         assert(mh.type().equals(srcType));
 259         return mh;
 260     }
 261 


 284         // Now build a LambdaForm.
 285         MethodType lambdaType = srcType.basicType().invokerType();
 286         Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
 287 
 288         // Collect the arguments to the outgoing call, maybe with conversions:
 289         final int OUTARG_BASE = 0;  // target MH is Name.function, name Name.arguments[0]
 290         Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
 291 
 292         int nameCursor = INARG_LIMIT;
 293         for (int i = 0; i < INARG_COUNT; i++) {
 294             Object convSpec = convSpecs[i];
 295             if (convSpec == null) {
 296                 // do nothing: difference is trivial
 297                 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
 298                 continue;
 299             }
 300 
 301             Name conv;
 302             if (convSpec instanceof Class) {
 303                 Class<?> convClass = (Class<?>) convSpec;
 304                 conv = new Name(Lazy.MH_cast, convClass, names[INARG_BASE + i]);
 305             } else {
 306                 MethodHandle fn = (MethodHandle) convSpec;
 307                 conv = new Name(fn, names[INARG_BASE + i]);
 308             }
 309             assert(names[nameCursor] == null);
 310             names[nameCursor++] = conv;
 311             assert(outArgs[OUTARG_BASE + i] == null);
 312             outArgs[OUTARG_BASE + i] = conv;
 313         }
 314 
 315         // Build argument array for the call.
 316         assert(nameCursor == OUT_CALL);
 317         names[OUT_CALL] = new Name(target, outArgs);
 318 
 319         Object convSpec = convSpecs[INARG_COUNT];
 320         if (!retConv) {
 321             assert(OUT_CALL == names.length-1);
 322         } else {
 323             Name conv;
 324             if (convSpec == void.class) {
 325                 conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
 326             } else if (convSpec instanceof Class) {
 327                 Class<?> convClass = (Class<?>) convSpec;
 328                 conv = new Name(Lazy.MH_cast, convClass, names[OUT_CALL]);
 329             } else {
 330                 MethodHandle fn = (MethodHandle) convSpec;
 331                 if (fn.type().parameterCount() == 0)
 332                     conv = new Name(fn);  // don't pass retval to void conversion
 333                 else
 334                     conv = new Name(fn, names[OUT_CALL]);
 335             }
 336             assert(names[RETURN_CONV] == null);
 337             names[RETURN_CONV] = conv;
 338             assert(RETURN_CONV == names.length-1);
 339         }
 340 
 341         LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
 342         return SimpleMethodHandle.make(srcType, form);
 343     }
 344 



















 345     static Object[] computeValueConversions(MethodType srcType, MethodType dstType,
 346                                             boolean strict, boolean monobox) {
 347         final int INARG_COUNT = srcType.parameterCount();
 348         Object[] convSpecs = new Object[INARG_COUNT+1];
 349         for (int i = 0; i <= INARG_COUNT; i++) {
 350             boolean isRet = (i == INARG_COUNT);
 351             Class<?> src = isRet ? dstType.returnType() : srcType.parameterType(i);
 352             Class<?> dst = isRet ? srcType.returnType() : dstType.parameterType(i);
 353             if (!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)) {
 354                 convSpecs[i] = valueConversion(src, dst, strict, monobox);
 355             }
 356         }
 357         return convSpecs;
 358     }
 359     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
 360                                             boolean strict) {
 361         return makePairwiseConvert(target, srcType, strict, /*monobox=*/ false);
 362     }
 363 
 364     /**


 554     static void checkSpreadArgument(Object av, int n) {
 555         if (av == null) {
 556             if (n == 0)  return;
 557         } else if (av instanceof Object[]) {
 558             int len = ((Object[])av).length;
 559             if (len == n)  return;
 560         } else {
 561             int len = java.lang.reflect.Array.getLength(av);
 562             if (len == n)  return;
 563         }
 564         // fall through to error:
 565         throw newIllegalArgumentException("array is not of length "+n);
 566     }
 567 
 568     /**
 569      * Pre-initialized NamedFunctions for bootstrapping purposes.
 570      * Factored in an inner class to delay initialization until first usage.
 571      */
 572     static class Lazy {
 573         private static final Class<?> MHI = MethodHandleImpl.class;
 574         private static final Class<?> CLS = Class.class;
 575 
 576         private static final MethodHandle[] ARRAYS;
 577         private static final MethodHandle[] FILL_ARRAYS;
 578 
 579         static final NamedFunction NF_checkSpreadArgument;
 580         static final NamedFunction NF_guardWithCatch;
 581         static final NamedFunction NF_throwException;
 582         static final NamedFunction NF_profileBoolean;
 583 
 584         static final MethodHandle MH_cast;
 585         static final MethodHandle MH_selectAlternative;
 586         static final MethodHandle MH_copyAsPrimitiveArray;
 587         static final MethodHandle MH_fillNewTypedArray;
 588         static final MethodHandle MH_fillNewArray;
 589         static final MethodHandle MH_arrayIdentity;
 590 
 591         static {
 592             ARRAYS      = makeArrays();
 593             FILL_ARRAYS = makeFillArrays();
 594 
 595             try {
 596                 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
 597                 NF_guardWithCatch      = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
 598                                                                                  MethodHandle.class, Object[].class));
 599                 NF_throwException      = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
 600                 NF_profileBoolean      = new NamedFunction(MHI.getDeclaredMethod("profileBoolean", boolean.class, int[].class));
 601 
 602                 NF_checkSpreadArgument.resolve();
 603                 NF_guardWithCatch.resolve();
 604                 NF_throwException.resolve();
 605                 NF_profileBoolean.resolve();
 606 
 607                 MH_cast                 = IMPL_LOOKUP.findVirtual(CLS, "cast",
 608                                             MethodType.methodType(Object.class, Object.class));
 609                 MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
 610                                             MethodType.methodType(Object.class, Wrapper.class, Object[].class));
 611                 MH_arrayIdentity        = IMPL_LOOKUP.findStatic(MHI, "identity",
 612                                             MethodType.methodType(Object[].class, Object[].class));
 613                 MH_fillNewArray         = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
 614                                             MethodType.methodType(Object[].class, Integer.class, Object[].class));
 615                 MH_fillNewTypedArray    = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
 616                                             MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
 617 
 618                 MH_selectAlternative    = makeIntrinsic(
 619                         IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
 620                                 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
 621                         Intrinsic.SELECT_ALTERNATIVE);
 622             } catch (ReflectiveOperationException ex) {
 623                 throw newInternalError(ex);
 624             }
 625         }
 626     }
 627 
 628     /** Factory method:  Collect or filter selected argument(s). */


< prev index next >