jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java
changeset 9752 88ab34b6da6d
parent 9731 d0f7a3e441c4
child 9859 47e26ad535c4
equal deleted inserted replaced
9731:d0f7a3e441c4 9752:88ab34b6da6d
    27 
    27 
    28 import sun.invoke.util.VerifyType;
    28 import sun.invoke.util.VerifyType;
    29 import sun.invoke.util.Wrapper;
    29 import sun.invoke.util.Wrapper;
    30 import sun.invoke.util.ValueConversions;
    30 import sun.invoke.util.ValueConversions;
    31 import java.util.Arrays;
    31 import java.util.Arrays;
       
    32 import java.util.ArrayList;
       
    33 import java.util.Collections;
    32 import static java.lang.invoke.MethodHandleNatives.Constants.*;
    34 import static java.lang.invoke.MethodHandleNatives.Constants.*;
    33 import static java.lang.invoke.MethodHandleStatics.*;
    35 import static java.lang.invoke.MethodHandleStatics.*;
    34 
    36 
    35 /**
    37 /**
    36  * This method handle performs simple conversion or checking of a single argument.
    38  * This method handle performs simple conversion or checking of a single argument.
    60 
    62 
    61     // TO DO:  When adapting another MH with a null conversion, clone
    63     // TO DO:  When adapting another MH with a null conversion, clone
    62     // the target and change its type, instead of adding another layer.
    64     // the target and change its type, instead of adding another layer.
    63 
    65 
    64     /** Can a JVM-level adapter directly implement the proposed
    66     /** Can a JVM-level adapter directly implement the proposed
    65      *  argument conversions, as if by MethodHandles.convertArguments?
    67      *  argument conversions, as if by fixed-arity MethodHandle.asType?
    66      */
    68      */
    67     static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) {
    69     static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) {
    68         // same number of args, of course
    70         // same number of args, of course
    69         int len = newType.parameterCount();
    71         int len = newType.parameterCount();
    70         if (len != oldType.parameterCount())
    72         if (len != oldType.parameterCount())
    90 
    92 
    91         return true;
    93         return true;
    92     }
    94     }
    93 
    95 
    94     /** Can a JVM-level adapter directly implement the proposed
    96     /** Can a JVM-level adapter directly implement the proposed
    95      *  argument conversion, as if by MethodHandles.convertArguments?
    97      *  argument conversion, as if by fixed-arity MethodHandle.asType?
    96      */
    98      */
    97     static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) {
    99     static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) {
    98         // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
   100         // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
    99         // so we don't need to repeat so much decision making.
   101         // so we don't need to repeat so much decision making.
   100         if (VerifyType.isNullConversion(src, dst)) {
   102         if (VerifyType.isNullConversion(src, dst)) {
   548     static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
   550     static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
   549         MethodType type = target.type();
   551         MethodType type = target.type();
   550         int last = type.parameterCount() - 1;
   552         int last = type.parameterCount() - 1;
   551         if (type.parameterType(last) != arrayType)
   553         if (type.parameterType(last) != arrayType)
   552             target = target.asType(type.changeParameterType(last, arrayType));
   554             target = target.asType(type.changeParameterType(last, arrayType));
       
   555         target = target.asFixedArity();  // make sure this attribute is turned off
   553         return new AsVarargsCollector(target, arrayType);
   556         return new AsVarargsCollector(target, arrayType);
   554     }
   557     }
   555 
   558 
   556     static class AsVarargsCollector extends AdapterMethodHandle {
   559     static class AsVarargsCollector extends AdapterMethodHandle {
   557         final MethodHandle target;
   560         final MethodHandle target;
   566         }
   569         }
   567 
   570 
   568         @Override
   571         @Override
   569         public boolean isVarargsCollector() {
   572         public boolean isVarargsCollector() {
   570             return true;
   573             return true;
       
   574         }
       
   575 
       
   576         @Override
       
   577         public MethodHandle asFixedArity() {
       
   578             return target;
   571         }
   579         }
   572 
   580 
   573         @Override
   581         @Override
   574         public MethodHandle asType(MethodType newType) {
   582         public MethodHandle asType(MethodType newType) {
   575             MethodType type = this.type();
   583             MethodType type = this.type();
   592                 throw new WrongMethodTypeException("cannot build collector");
   600                 throw new WrongMethodTypeException("cannot build collector");
   593             }
   601             }
   594             cache = collector;
   602             cache = collector;
   595             return collector.asType(newType);
   603             return collector.asType(newType);
   596         }
   604         }
   597 
       
   598         @Override
       
   599         public MethodHandle asVarargsCollector(Class<?> arrayType) {
       
   600             MethodType type = this.type();
       
   601             if (type.parameterType(type.parameterCount()-1) == arrayType)
       
   602                 return this;
       
   603             return super.asVarargsCollector(arrayType);
       
   604         }
       
   605     }
   605     }
   606 
   606 
   607     /** Can a checkcast adapter validly convert the target to newType?
   607     /** Can a checkcast adapter validly convert the target to newType?
   608      *  The JVM supports all kind of reference casts, even silly ones.
   608      *  The JVM supports all kind of reference casts, even silly ones.
   609      */
   609      */
   745         Class<?> boxType = Wrapper.asWrapperType(convType);
   745         Class<?> boxType = Wrapper.asWrapperType(convType);
   746         Class<?> primType = Wrapper.asPrimitiveType(convType);
   746         Class<?> primType = Wrapper.asPrimitiveType(convType);
   747         if (!canUnboxArgument(newType, oldType, arg, convType, level))
   747         if (!canUnboxArgument(newType, oldType, arg, convType, level))
   748             return null;
   748             return null;
   749         MethodType castDone = newType;
   749         MethodType castDone = newType;
   750         if (!VerifyType.isNullConversion(src, boxType))
   750         if (!VerifyType.isNullConversion(src, boxType)) {
       
   751             // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
       
   752             if (level != 0) {
       
   753                 // must include additional conversions
       
   754                 if (src == Object.class || !Wrapper.isWrapperType(src)) {
       
   755                     // src must be examined at runtime, to detect Byte, Character, etc.
       
   756                     MethodHandle unboxMethod = (level == 1
       
   757                                                 ? ValueConversions.unbox(dst)
       
   758                                                 : ValueConversions.unboxCast(dst));
       
   759                     long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst));
       
   760                     return new AdapterMethodHandle(target, newType, conv, unboxMethod);
       
   761                 }
       
   762                 // Example: Byte->int
       
   763                 // Do this by reformulating the problem to Byte->byte.
       
   764                 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
       
   765                 MethodType midType = newType.changeParameterType(arg, srcPrim);
       
   766                 MethodHandle fixPrim; // makePairwiseConvert(midType, target, 0);
       
   767                 if (canPrimCast(midType, oldType, arg, dst))
       
   768                     fixPrim = makePrimCast(midType, target, arg, dst);
       
   769                 else
       
   770                     fixPrim = target;
       
   771                 return makeUnboxArgument(newType, fixPrim, arg, srcPrim, 0);
       
   772             }
   751             castDone = newType.changeParameterType(arg, boxType);
   773             castDone = newType.changeParameterType(arg, boxType);
       
   774         }
   752         long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
   775         long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
   753         MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
   776         MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
   754         if (castDone == newType)
   777         if (castDone == newType)
   755             return adapter;
   778             return adapter;
   756         return makeCheckCast(newType, adapter, arg, boxType);
   779         return makeCheckCast(newType, adapter, arg, boxType);
   915     static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target,
   938     static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target,
   916                 int swapArg1, int swapArg2) {
   939                 int swapArg1, int swapArg2) {
   917         if (swapArg1 == swapArg2)
   940         if (swapArg1 == swapArg2)
   918             return target;
   941             return target;
   919         if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
   942         if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
       
   943         if (type2size(newType.parameterType(swapArg1)) !=
       
   944             type2size(newType.parameterType(swapArg2))) {
       
   945             // turn a swap into a pair of rotates:
       
   946             // [x a b c y] => [a b c y x] => [y a b c x]
       
   947             int argc = swapArg2 - swapArg1 + 1;
       
   948             final int ROT = 1;
       
   949             ArrayList<Class<?>> rot1Params = new ArrayList<Class<?>>(target.type().parameterList());
       
   950             Collections.rotate(rot1Params.subList(swapArg1, swapArg1 + argc), -ROT);
       
   951             MethodType rot1Type = MethodType.methodType(target.type().returnType(), rot1Params);
       
   952             MethodHandle rot1 = makeRotateArguments(rot1Type, target, swapArg1, argc, +ROT);
       
   953             if (argc == 2)  return rot1;
       
   954             MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT);
       
   955             return rot2;
       
   956         }
   920         if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
   957         if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
   921             return null;
   958             return null;
   922         Class<?> swapType = newType.parameterType(swapArg1);
   959         Class<?> swapType = newType.parameterType(swapArg1);
   923         // in  arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ]
   960         // in  arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ]
   924         // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ]
   961         // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ]
   944 
   981 
   945     /** Can an adapter rotate arguments to convert the target to newType? */
   982     /** Can an adapter rotate arguments to convert the target to newType? */
   946     static boolean canRotateArguments(MethodType newType, MethodType targetType,
   983     static boolean canRotateArguments(MethodType newType, MethodType targetType,
   947                 int firstArg, int argCount, int rotateBy) {
   984                 int firstArg, int argCount, int rotateBy) {
   948         if (!convOpSupported(OP_ROT_ARGS))  return false;
   985         if (!convOpSupported(OP_ROT_ARGS))  return false;
   949         if (argCount <= 2)  return false;  // must be a swap, not a rotate
       
   950         rotateBy = positiveRotation(argCount, rotateBy);
   986         rotateBy = positiveRotation(argCount, rotateBy);
   951         if (rotateBy == 0)  return false;  // no rotation
   987         if (rotateBy == 0)  return false;  // no rotation
   952         if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
   988         if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
   953             return false;  // too many argument positions
   989             return false;  // too many argument positions
   954         // Rotate incoming args right N to the out args, N in 1..(argCouunt-1).
   990         // Rotate incoming args right N to the out args, N in 1..(argCouunt-1).
   990         int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0);
  1026         int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0);
   991         int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0);
  1027         int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0);
   992         // From here on out, it assumes a single-argument shift.
  1028         // From here on out, it assumes a single-argument shift.
   993         assert(MAX_ARG_ROTATION == 1);
  1029         assert(MAX_ARG_ROTATION == 1);
   994         int srcArg, dstArg;
  1030         int srcArg, dstArg;
       
  1031         int dstSlot;
   995         byte basicType;
  1032         byte basicType;
   996         if (chunk2Slots <= chunk1Slots) {
  1033         if (chunk2Slots <= chunk1Slots) {
   997             // Rotate right/down N (rotateBy = +N, N small, c2 small):
  1034             // Rotate right/down N (rotateBy = +N, N small, c2 small):
   998             // in  arglist: [0: ...keep1 | arg1: c1...  | limit-N: c2 | limit: keep2... ]
  1035             // in  arglist: [0: ...keep1 | arg1: c1...  | limit-N: c2 | limit: keep2... ]
   999             // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1...   | limit: keep2... ]
  1036             // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1...   | limit: keep2... ]
  1000             srcArg = limit-1;
  1037             srcArg = limit-1;
  1001             dstArg = firstArg;
  1038             dstArg = firstArg;
       
  1039             dstSlot = depth0 - chunk2Slots;
  1002             basicType = basicType(newType.parameterType(srcArg));
  1040             basicType = basicType(newType.parameterType(srcArg));
  1003             assert(chunk2Slots == type2size(basicType));
  1041             assert(chunk2Slots == type2size(basicType));
  1004         } else {
  1042         } else {
  1005             // Rotate left/up N (rotateBy = -N, N small, c1 small):
  1043             // Rotate left/up N (rotateBy = -N, N small, c1 small):
  1006             // in  arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2...   | limit: keep2... ]
  1044             // in  arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2...   | limit: keep2... ]
  1007             // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
  1045             // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
  1008             srcArg = firstArg;
  1046             srcArg = firstArg;
  1009             dstArg = limit-1;
  1047             dstArg = limit-1;
       
  1048             dstSlot = depth2;
  1010             basicType = basicType(newType.parameterType(srcArg));
  1049             basicType = basicType(newType.parameterType(srcArg));
  1011             assert(chunk1Slots == type2size(basicType));
  1050             assert(chunk1Slots == type2size(basicType));
  1012         }
  1051         }
  1013         int dstSlot = newType.parameterSlotDepth(dstArg + 1);
       
  1014         long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot);
  1052         long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot);
  1015         return new AdapterMethodHandle(target, newType, conv);
  1053         return new AdapterMethodHandle(target, newType, conv);
  1016     }
  1054     }
  1017 
  1055 
  1018     /** Can an adapter spread an argument to convert the target to newType? */
  1056     /** Can an adapter spread an argument to convert the target to newType? */