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 9490 : 8037210: Get rid of char-based descriptions 'J' of basic types
Reviewed-by: jrose, ?
rev 9491 : imported patch meth-asm.enum


  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 ?


 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


 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     /**
 297      * Identity function, with reference cast.
 298      * @param t an arbitrary reference type
 299      * @param x an arbitrary reference value
 300      * @return the same value x
 301      */
 302     @ForceInline
 303     @SuppressWarnings("unchecked")
 304     static <T,U> T castReference(Class<? extends T> t, U x) {
 305         // inlined Class.cast because we can't ForceInline it
 306         if (x != null && !t.isInstance(x))
 307             throw newClassCastException(t, x);
 308         return (T) x;
 309     }
 310 
 311     private static ClassCastException newClassCastException(Class<?> t, Object obj) {
 312         return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());




  80         static double  getElementD(double[]  a, int i)            { return              a[i]; }
  81         static boolean getElementZ(boolean[] a, int i)            { return              a[i]; }
  82         static byte    getElementB(byte[]    a, int i)            { return              a[i]; }
  83         static short   getElementS(short[]   a, int i)            { return              a[i]; }
  84         static char    getElementC(char[]    a, int i)            { return              a[i]; }
  85         static Object  getElementL(Object[]  a, int i)            { return              a[i]; }
  86 
  87         static void    setElementI(int[]     a, int i, int     x) {              a[i] = x; }
  88         static void    setElementJ(long[]    a, int i, long    x) {              a[i] = x; }
  89         static void    setElementF(float[]   a, int i, float   x) {              a[i] = x; }
  90         static void    setElementD(double[]  a, int i, double  x) {              a[i] = x; }
  91         static void    setElementZ(boolean[] a, int i, boolean x) {              a[i] = x; }
  92         static void    setElementB(byte[]    a, int i, byte    x) {              a[i] = x; }
  93         static void    setElementS(short[]   a, int i, short   x) {              a[i] = x; }
  94         static void    setElementC(char[]    a, int i, char    x) {              a[i] = x; }
  95         static void    setElementL(Object[]  a, int i, Object  x) {              a[i] = x; }
  96 
  97         static Object  getElementL(Class<?> arrayClass, Object[] a, int i)           { arrayClass.cast(a); return a[i]; }
  98         static void    setElementL(Class<?> arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; }
  99 






 100         static boolean needCast(Class<?> arrayClass) {
 101             Class<?> elemClass = arrayClass.getComponentType();
 102             return !elemClass.isPrimitive() && elemClass != Object.class;
 103         }
 104         static String name(Class<?> arrayClass, boolean isSetter) {
 105             Class<?> elemClass = arrayClass.getComponentType();
 106             if (elemClass == null)  throw newIllegalArgumentException("not an array", arrayClass);
 107             return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
 108         }
 109         static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false;  // FIXME: decide
 110         static MethodType type(Class<?> arrayClass, boolean isSetter) {
 111             Class<?> elemClass = arrayClass.getComponentType();
 112             Class<?> arrayArgClass = arrayClass;
 113             if (!elemClass.isPrimitive()) {
 114                 arrayArgClass = Object[].class;
 115                 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
 116                     arrayArgClass = Object.class;
 117             }
 118             if (!needCast(arrayClass)) {
 119                 return !isSetter ?
 120                     MethodType.methodType(elemClass,  arrayArgClass, int.class) :
 121                     MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
 122             } else {
 123                 Class<?> classArgClass = Class.class;
 124                 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
 125                     classArgClass = Object.class;
 126                 return !isSetter ?


 156      * @param level which strength of conversion is allowed
 157      * @return an adapter to the original handle with the desired new type,
 158      *          or the original target if the types are already identical
 159      *          or null if the adaptation cannot be made
 160      */
 161     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
 162         assert(level >= 0 && level <= 2);
 163         MethodType dstType = target.type();
 164         assert(dstType.parameterCount() == target.type().parameterCount());
 165         if (srcType == dstType)
 166             return target;
 167 
 168         // Calculate extra arguments (temporaries) required in the names array.
 169         // FIXME: Use an ArrayList<Name>.  Some arguments require more than one conversion step.
 170         final int INARG_COUNT = srcType.parameterCount();
 171         int conversions = 0;
 172         boolean[] needConv = new boolean[1+INARG_COUNT];
 173         for (int i = 0; i <= INARG_COUNT; i++) {
 174             Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
 175             Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
 176             if (!VerifyType.isNullConversion(src, dst, false) ||
 177                 level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
 178                 needConv[i] = true;
 179                 conversions++;
 180             }
 181         }
 182         boolean retConv = needConv[INARG_COUNT];
 183         if (retConv && srcType.returnType() == void.class) {
 184             retConv = false;
 185             conversions--;
 186         }
 187 
 188         final int IN_MH         = 0;
 189         final int INARG_BASE    = 1;
 190         final int INARG_LIMIT   = INARG_BASE + INARG_COUNT;
 191         final int NAME_LIMIT    = INARG_LIMIT + conversions + 1;
 192         final int RETURN_CONV   = (!retConv ? -1         : NAME_LIMIT - 1);
 193         final int OUT_CALL      = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
 194         final int RESULT        = (srcType.returnType() == void.class ? -1 : NAME_LIMIT - 1);
 195 
 196         // Now build a LambdaForm.
 197         MethodType lambdaType = srcType.basicType().invokerType();
 198         Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
 199 
 200         // Collect the arguments to the outgoing call, maybe with conversions:
 201         final int OUTARG_BASE = 0;  // target MH is Name.function, name Name.arguments[0]
 202         Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
 203 
 204         int nameCursor = INARG_LIMIT;
 205         for (int i = 0; i < INARG_COUNT; i++) {
 206             Class<?> src = srcType.parameterType(i);
 207             Class<?> dst = dstType.parameterType(i);
 208 
 209             if (!needConv[i]) {
 210                 // do nothing: difference is trivial
 211                 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
 212                 continue;
 213             }
 214 
 215             // Tricky case analysis follows.
 216             MethodHandle fn = null;
 217             if (src.isPrimitive()) {
 218                 if (dst.isPrimitive()) {
 219                     fn = ValueConversions.convertPrimitive(src, dst);
 220                 } else {
 221                     Wrapper w = Wrapper.forPrimitiveType(src);
 222                     MethodHandle boxMethod = ValueConversions.box(w);
 223                     if (dst == w.wrapperType())
 224                         fn = boxMethod;
 225                     else
 226                         fn = boxMethod.asType(MethodType.methodType(dst, src));
 227                 }
 228             } else {
 229                 if (dst.isPrimitive()) {
 230                     // Caller has boxed a primitive.  Unbox it for the target.
 231                     Wrapper w = Wrapper.forPrimitiveType(dst);
 232                     if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType(), false)) {
 233                         fn = ValueConversions.unbox(dst);
 234                     } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
 235                         // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
 236                         // must include additional conversions
 237                         // src must be examined at runtime, to detect Byte, Character, etc.
 238                         MethodHandle unboxMethod = (level == 1
 239                                                     ? ValueConversions.unbox(dst)
 240                                                     : ValueConversions.unboxCast(dst));
 241                         fn = unboxMethod;
 242                     } else {
 243                         // Example: Byte->int
 244                         // Do this by reformulating the problem to Byte->byte.
 245                         Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
 246                         MethodHandle unbox = ValueConversions.unbox(srcPrim);
 247                         // Compose the two conversions.  FIXME:  should make two Names for this job
 248                         fn = unbox.asType(MethodType.methodType(dst, src));
 249                     }
 250                 } else {
 251                     // Simple reference conversion.
 252                     // Note:  Do not check for a class hierarchy relation


 271         } else {
 272             Class<?> needReturn = srcType.returnType();
 273             Class<?> haveReturn = dstType.returnType();
 274             MethodHandle fn;
 275             Object[] arg = { names[OUT_CALL] };
 276             if (haveReturn == void.class) {
 277                 // synthesize a zero value for the given void
 278                 Object zero = Wrapper.forBasicType(needReturn).zero();
 279                 fn = MethodHandles.constant(needReturn, zero);
 280                 arg = new Object[0];  // don't pass names[OUT_CALL] to conversion
 281             } else {
 282                 MethodHandle identity = MethodHandles.identity(needReturn);
 283                 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
 284                 fn = makePairwiseConvert(identity, needConversion, level);
 285             }
 286             assert(names[RETURN_CONV] == null);
 287             names[RETURN_CONV] = new Name(fn, arg);
 288             assert(RETURN_CONV == names.length-1);
 289         }
 290 
 291         LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
 292         return SimpleMethodHandle.make(srcType, form);
 293     }
 294 
 295     /**
 296      * Identity function, with reference cast.
 297      * @param t an arbitrary reference type
 298      * @param x an arbitrary reference value
 299      * @return the same value x
 300      */
 301     @ForceInline
 302     @SuppressWarnings("unchecked")
 303     static <T,U> T castReference(Class<? extends T> t, U x) {
 304         // inlined Class.cast because we can't ForceInline it
 305         if (x != null && !t.isInstance(x))
 306             throw newClassCastException(t, x);
 307         return (T) x;
 308     }
 309 
 310     private static ClassCastException newClassCastException(Class<?> t, Object obj) {
 311         return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());


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