jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
changeset 9646 5ebbe5ab084f
parent 8822 8145ab9f5f86
child 9730 e4b334d47f4b
equal deleted inserted replaced
9645:dabb5e4edc4c 9646:5ebbe5ab084f
   119             MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
   119             MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
   120             int nargs = rawConType.parameterCount() - 1;
   120             int nargs = rawConType.parameterCount() - 1;
   121             if (nargs < INVOKES.length) {
   121             if (nargs < INVOKES.length) {
   122                 MethodHandle invoke = INVOKES[nargs];
   122                 MethodHandle invoke = INVOKES[nargs];
   123                 MethodType conType = CON_TYPES[nargs];
   123                 MethodType conType = CON_TYPES[nargs];
   124                 MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, null);
   124                 MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, 0);
   125                 if (gcon == null)  return null;
   125                 if (gcon == null)  return null;
   126                 MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
   126                 MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
   127                 assert(galloc.type() == newType.generic());
   127                 assert(galloc.type() == newType.generic());
   128                 return convertArguments(galloc, newType, galloc.type(), null);
   128                 return convertArguments(galloc, newType, galloc.type(), 0);
   129             } else {
   129             } else {
   130                 MethodHandle invoke = VARARGS_INVOKE;
   130                 MethodHandle invoke = VARARGS_INVOKE;
   131                 MethodType conType = CON_TYPES[nargs];
   131                 MethodType conType = CON_TYPES[nargs];
   132                 MethodHandle gcon = spreadArguments(rawConstructor, conType, 1);
   132                 MethodHandle gcon = spreadArguments(rawConstructor, conType, 1);
   133                 if (gcon == null)  return null;
   133                 if (gcon == null)  return null;
   254             mhs = new MethodHandle[] {
   254             mhs = new MethodHandle[] {
   255                 FieldAccessor.ahandle(arrayClass, false),
   255                 FieldAccessor.ahandle(arrayClass, false),
   256                 FieldAccessor.ahandle(arrayClass, true)
   256                 FieldAccessor.ahandle(arrayClass, true)
   257             };
   257             };
   258             if (mhs[0].type().parameterType(0) == Class.class) {
   258             if (mhs[0].type().parameterType(0) == Class.class) {
   259                 mhs[0] = MethodHandles.insertArguments(mhs[0], 0, elemClass);
   259                 mhs[0] = mhs[0].bindTo(elemClass);
   260                 mhs[1] = MethodHandles.insertArguments(mhs[1], 0, elemClass);
   260                 mhs[1] = mhs[1].bindTo(elemClass);
   261             }
   261             }
   262             synchronized (FieldAccessor.ARRAY_CACHE) {}  // memory barrier
   262             synchronized (FieldAccessor.ARRAY_CACHE) {}  // memory barrier
   263             FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
   263             FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
   264         }
   264         }
   265         return mhs[isSetter ? 1 : 0];
   265         return mhs[isSetter ? 1 : 0];
   370                 throw uncaughtException(ex);
   370                 throw uncaughtException(ex);
   371             }
   371             }
   372             if (evclass != vclass || (!isStatic && ecclass != cclass)) {
   372             if (evclass != vclass || (!isStatic && ecclass != cclass)) {
   373                 MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
   373                 MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
   374                 strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
   374                 strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
   375                 mh = MethodHandles.convertArguments(mh, strongType);
   375                 mh = convertArguments(mh, strongType, 0);
   376             }
   376             }
   377             return mh;
   377             return mh;
   378         }
   378         }
   379 
   379 
   380         /// Support for array element access
   380         /// Support for array element access
   437             } catch (ReflectiveOperationException ex) {
   437             } catch (ReflectiveOperationException ex) {
   438                 throw uncaughtException(ex);
   438                 throw uncaughtException(ex);
   439             }
   439             }
   440             if (caclass != null) {
   440             if (caclass != null) {
   441                 MethodType strongType = FieldAccessor.atype(caclass, isSetter);
   441                 MethodType strongType = FieldAccessor.atype(caclass, isSetter);
   442                 mh = MethodHandles.insertArguments(mh, 0, caclass);
   442                 mh = mh.bindTo(caclass);
   443                 mh = MethodHandles.convertArguments(mh, strongType);
   443                 mh = convertArguments(mh, strongType, 0);
   444             }
   444             }
   445             return mh;
   445             return mh;
   446         }
   446         }
   447     }
   447     }
   448 
   448 
   463                 DirectMethodHandle dmh = (DirectMethodHandle) info;
   463                 DirectMethodHandle dmh = (DirectMethodHandle) info;
   464                 if (receiver == null ||
   464                 if (receiver == null ||
   465                     dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
   465                     dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
   466                     MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
   466                     MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
   467                     MethodType newType = target.type().dropParameterTypes(0, 1);
   467                     MethodType newType = target.type().dropParameterTypes(0, 1);
   468                     return convertArguments(bmh, newType, bmh.type(), null);
   468                     return convertArguments(bmh, newType, bmh.type(), 0);
   469                 }
   469                 }
   470             }
   470             }
   471         }
   471         }
   472         if (target instanceof DirectMethodHandle)
   472         if (target instanceof DirectMethodHandle)
   473             return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
   473             return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
   484     static
   484     static
   485     MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
   485     MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
   486         return new BoundMethodHandle(target, receiver, argnum);
   486         return new BoundMethodHandle(target, receiver, argnum);
   487     }
   487     }
   488 
   488 
   489     static MethodHandle convertArguments(MethodHandle target,
   489     static MethodHandle permuteArguments(MethodHandle target,
   490                                                 MethodType newType,
   490                                                 MethodType newType,
   491                                                 MethodType oldType,
   491                                                 MethodType oldType,
   492                                                 int[] permutationOrNull) {
   492                                                 int[] permutationOrNull) {
   493         assert(oldType.parameterCount() == target.type().parameterCount());
   493         assert(oldType.parameterCount() == target.type().parameterCount());
   494         if (permutationOrNull != null) {
   494         int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
   495             int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
   495         if (permutationOrNull.length != outargs)
   496             if (permutationOrNull.length != outargs)
   496             throw newIllegalArgumentException("wrong number of arguments in permutation");
   497                 throw newIllegalArgumentException("wrong number of arguments in permutation");
   497         // Make the individual outgoing argument types match up first.
   498             // Make the individual outgoing argument types match up first.
   498         Class<?>[] callTypeArgs = new Class<?>[outargs];
   499             Class<?>[] callTypeArgs = new Class<?>[outargs];
   499         for (int i = 0; i < outargs; i++)
   500             for (int i = 0; i < outargs; i++)
   500             callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
   501                 callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
   501         MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
   502             MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
   502         target = convertArguments(target, callType, oldType, 0);
   503             target = convertArguments(target, callType, oldType, null);
   503         assert(target != null);
   504             assert(target != null);
   504         oldType = target.type();
   505             oldType = target.type();
   505         List<Integer> goal = new ArrayList<Integer>();  // i*TOKEN
   506             List<Integer> goal = new ArrayList<Integer>();  // i*TOKEN
   506         List<Integer> state = new ArrayList<Integer>(); // i*TOKEN
   507             List<Integer> state = new ArrayList<Integer>(); // i*TOKEN
   507         List<Integer> drops = new ArrayList<Integer>(); // not tokens
   508             List<Integer> drops = new ArrayList<Integer>(); // not tokens
   508         List<Integer> dups = new ArrayList<Integer>();  // not tokens
   509             List<Integer> dups = new ArrayList<Integer>();  // not tokens
   509         final int TOKEN = 10; // to mark items which are symbolic only
   510             final int TOKEN = 10; // to mark items which are symbolic only
   510         // state represents the argument values coming into target
   511             // state represents the argument values coming into target
   511         for (int i = 0; i < outargs; i++) {
   512             for (int i = 0; i < outargs; i++) {
   512             state.add(permutationOrNull[i] * TOKEN);
   513                 state.add(permutationOrNull[i] * TOKEN);
   513         }
   514             }
   514         // goal represents the desired state
   515             // goal represents the desired state
   515         for (int i = 0; i < inargs; i++) {
   516             for (int i = 0; i < inargs; i++) {
   516             if (state.contains(i * TOKEN)) {
   517                 if (state.contains(i * TOKEN)) {
   517                 goal.add(i * TOKEN);
   518                     goal.add(i * TOKEN);
   518             } else {
       
   519                 // adapter must initially drop all unused arguments
       
   520                 drops.add(i);
       
   521             }
       
   522         }
       
   523         // detect duplications
       
   524         while (state.size() > goal.size()) {
       
   525             for (int i2 = 0; i2 < state.size(); i2++) {
       
   526                 int arg1 = state.get(i2);
       
   527                 int i1 = state.indexOf(arg1);
       
   528                 if (i1 != i2) {
       
   529                     // found duplicate occurrence at i2
       
   530                     int arg2 = (inargs++) * TOKEN;
       
   531                     state.set(i2, arg2);
       
   532                     dups.add(goal.indexOf(arg1));
       
   533                     goal.add(arg2);
       
   534                 }
       
   535             }
       
   536         }
       
   537         assert(state.size() == goal.size());
       
   538         int size = goal.size();
       
   539         while (!state.equals(goal)) {
       
   540             // Look for a maximal sequence of adjacent misplaced arguments,
       
   541             // and try to rotate them into place.
       
   542             int bestRotArg = -10 * TOKEN, bestRotLen = 0;
       
   543             int thisRotArg = -10 * TOKEN, thisRotLen = 0;
       
   544             for (int i = 0; i < size; i++) {
       
   545                 int arg = state.get(i);
       
   546                 // Does this argument match the current run?
       
   547                 if (arg == thisRotArg + TOKEN) {
       
   548                     thisRotArg = arg;
       
   549                     thisRotLen += 1;
       
   550                     if (bestRotLen < thisRotLen) {
       
   551                         bestRotLen = thisRotLen;
       
   552                         bestRotArg = thisRotArg;
       
   553                     }
   519                 } else {
   554                 } else {
   520                     // adapter must initially drop all unused arguments
   555                     // The old sequence (if any) stops here.
   521                     drops.add(i);
   556                     thisRotLen = 0;
   522                 }
   557                     thisRotArg = -10 * TOKEN;
   523             }
   558                     // But maybe a new one starts here also.
   524             // detect duplications
   559                     int wantArg = goal.get(i);
   525             while (state.size() > goal.size()) {
   560                     final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
   526                 for (int i2 = 0; i2 < state.size(); i2++) {
   561                     if (arg != wantArg &&
   527                     int arg1 = state.get(i2);
   562                         arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
   528                     int i1 = state.indexOf(arg1);
   563                         arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
   529                     if (i1 != i2) {
   564                         thisRotArg = arg;
   530                         // found duplicate occurrence at i2
   565                         thisRotLen = 1;
   531                         int arg2 = (inargs++) * TOKEN;
       
   532                         state.set(i2, arg2);
       
   533                         dups.add(goal.indexOf(arg1));
       
   534                         goal.add(arg2);
       
   535                     }
   566                     }
   536                 }
   567                 }
   537             }
   568             }
   538             assert(state.size() == goal.size());
   569             if (bestRotLen >= 2) {
   539             int size = goal.size();
   570                 // Do a rotation if it can improve argument positioning
   540             while (!state.equals(goal)) {
   571                 // by at least 2 arguments.  This is not always optimal,
   541                 // Look for a maximal sequence of adjacent misplaced arguments,
   572                 // but it seems to catch common cases.
   542                 // and try to rotate them into place.
   573                 int dstEnd = state.indexOf(bestRotArg);
   543                 int bestRotArg = -10 * TOKEN, bestRotLen = 0;
   574                 int srcEnd = goal.indexOf(bestRotArg);
   544                 int thisRotArg = -10 * TOKEN, thisRotLen = 0;
   575                 int rotBy = dstEnd - srcEnd;
   545                 for (int i = 0; i < size; i++) {
   576                 int dstBeg = dstEnd - (bestRotLen - 1);
   546                     int arg = state.get(i);
   577                 int srcBeg = srcEnd - (bestRotLen - 1);
   547                     // Does this argument match the current run?
   578                 assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
   548                     if (arg == thisRotArg + TOKEN) {
   579                 // Make a span which covers both source and destination.
   549                         thisRotArg = arg;
   580                 int rotBeg = Math.min(dstBeg, srcBeg);
   550                         thisRotLen += 1;
   581                 int rotEnd = Math.max(dstEnd, srcEnd);
   551                         if (bestRotLen < thisRotLen) {
   582                 int score = 0;
   552                             bestRotLen = thisRotLen;
   583                 for (int i = rotBeg; i <= rotEnd; i++) {
   553                             bestRotArg = thisRotArg;
   584                     if ((int)state.get(i) != (int)goal.get(i))
   554                         }
   585                         score += 1;
   555                     } else {
   586                 }
   556                         // The old sequence (if any) stops here.
   587                 List<Integer> rotSpan = state.subList(rotBeg, rotEnd+1);
   557                         thisRotLen = 0;
   588                 Collections.rotate(rotSpan, -rotBy);  // reverse direction
   558                         thisRotArg = -10 * TOKEN;
   589                 for (int i = rotBeg; i <= rotEnd; i++) {
   559                         // But maybe a new one starts here also.
   590                     if ((int)state.get(i) != (int)goal.get(i))
   560                         int wantArg = goal.get(i);
   591                         score -= 1;
   561                         final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
   592                 }
   562                         if (arg != wantArg &&
   593                 if (score >= 2) {
   563                             arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
   594                     // Improved at least two argument positions.  Do it.
   564                             arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
   595                     List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
   565                             thisRotArg = arg;
   596                     Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
   566                             thisRotLen = 1;
   597                     MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
   567                         }
   598                     MethodHandle nextTarget
       
   599                             = AdapterMethodHandle.makeRotateArguments(rotType, target,
       
   600                                     rotBeg, rotSpan.size(), rotBy);
       
   601                     if (nextTarget != null) {
       
   602                         //System.out.println("Rot: "+rotSpan+" by "+rotBy);
       
   603                         target = nextTarget;
       
   604                         oldType = rotType;
       
   605                         continue;
   568                     }
   606                     }
   569                 }
   607                 }
   570                 if (bestRotLen >= 2) {
   608                 // Else de-rotate, and drop through to the swap-fest.
   571                     // Do a rotation if it can improve argument positioning
   609                 Collections.rotate(rotSpan, rotBy);
   572                     // by at least 2 arguments.  This is not always optimal,
   610             }
   573                     // but it seems to catch common cases.
   611 
   574                     int dstEnd = state.indexOf(bestRotArg);
   612             // Now swap like the wind!
   575                     int srcEnd = goal.indexOf(bestRotArg);
   613             List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
   576                     int rotBy = dstEnd - srcEnd;
   614             for (int i = 0; i < size; i++) {
   577                     int dstBeg = dstEnd - (bestRotLen - 1);
   615                 // What argument do I want here?
   578                     int srcBeg = srcEnd - (bestRotLen - 1);
   616                 int arg = goal.get(i);
   579                     assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
   617                 if (arg != state.get(i)) {
   580                     // Make a span which covers both source and destination.
   618                     // Where is it now?
   581                     int rotBeg = Math.min(dstBeg, srcBeg);
   619                     int j = state.indexOf(arg);
   582                     int rotEnd = Math.max(dstEnd, srcEnd);
   620                     Collections.swap(ptypes, i, j);
   583                     int score = 0;
   621                     MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
   584                     for (int i = rotBeg; i <= rotEnd; i++) {
   622                     target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
   585                         if ((int)state.get(i) != (int)goal.get(i))
   623                     if (target == null)  throw newIllegalArgumentException("cannot swap");
   586                             score += 1;
   624                     assert(target.type() == swapType);
   587                     }
   625                     oldType = swapType;
   588                     List<Integer> rotSpan = state.subList(rotBeg, rotEnd+1);
   626                     Collections.swap(state, i, j);
   589                     Collections.rotate(rotSpan, -rotBy);  // reverse direction
       
   590                     for (int i = rotBeg; i <= rotEnd; i++) {
       
   591                         if ((int)state.get(i) != (int)goal.get(i))
       
   592                             score -= 1;
       
   593                     }
       
   594                     if (score >= 2) {
       
   595                         // Improved at least two argument positions.  Do it.
       
   596                         List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
       
   597                         Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
       
   598                         MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
       
   599                         MethodHandle nextTarget
       
   600                                 = AdapterMethodHandle.makeRotateArguments(rotType, target,
       
   601                                         rotBeg, rotSpan.size(), rotBy);
       
   602                         if (nextTarget != null) {
       
   603                             //System.out.println("Rot: "+rotSpan+" by "+rotBy);
       
   604                             target = nextTarget;
       
   605                             oldType = rotType;
       
   606                             continue;
       
   607                         }
       
   608                     }
       
   609                     // Else de-rotate, and drop through to the swap-fest.
       
   610                     Collections.rotate(rotSpan, rotBy);
       
   611                 }
   627                 }
   612 
   628             }
   613                 // Now swap like the wind!
   629             // One pass of swapping must finish the job.
   614                 List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
   630             assert(state.equals(goal));
   615                 for (int i = 0; i < size; i++) {
   631         }
   616                     // What argument do I want here?
   632         while (!dups.isEmpty()) {
   617                     int arg = goal.get(i);
   633             // Grab a contiguous trailing sequence of dups.
   618                     if (arg != state.get(i)) {
   634             int grab = dups.size() - 1;
   619                         // Where is it now?
   635             int dupArgPos = dups.get(grab), dupArgCount = 1;
   620                         int j = state.indexOf(arg);
   636             while (grab - 1 >= 0) {
   621                         Collections.swap(ptypes, i, j);
   637                 int dup0 = dups.get(grab - 1);
   622                         MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
   638                 if (dup0 != dupArgPos - 1)  break;
   623                         target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
   639                 dupArgPos -= 1;
   624                         if (target == null)  throw newIllegalArgumentException("cannot swap");
   640                 dupArgCount += 1;
   625                         assert(target.type() == swapType);
   641                 grab -= 1;
   626                         oldType = swapType;
   642             }
   627                         Collections.swap(state, i, j);
   643             //if (dupArgCount > 1)  System.out.println("Dup: "+dups.subList(grab, dups.size()));
   628                     }
   644             dups.subList(grab, dups.size()).clear();
   629                 }
   645             // In the new target type drop that many args from the tail:
   630                 // One pass of swapping must finish the job.
   646             List<Class<?>> ptypes = oldType.parameterList();
   631                 assert(state.equals(goal));
   647             ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
   632             }
   648             MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
   633             while (!dups.isEmpty()) {
   649             target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
   634                 // Grab a contiguous trailing sequence of dups.
   650             if (target == null)
   635                 int grab = dups.size() - 1;
   651                 throw newIllegalArgumentException("cannot dup");
   636                 int dupArgPos = dups.get(grab), dupArgCount = 1;
   652             oldType = target.type();
   637                 while (grab - 1 >= 0) {
   653         }
   638                     int dup0 = dups.get(grab - 1);
   654         while (!drops.isEmpty()) {
   639                     if (dup0 != dupArgPos - 1)  break;
   655             // Grab a contiguous initial sequence of drops.
   640                     dupArgPos -= 1;
   656             int dropArgPos = drops.get(0), dropArgCount = 1;
   641                     dupArgCount += 1;
   657             while (dropArgCount < drops.size()) {
   642                     grab -= 1;
   658                 int drop1 = drops.get(dropArgCount);
   643                 }
   659                 if (drop1 != dropArgPos + dropArgCount)  break;
   644                 //if (dupArgCount > 1)  System.out.println("Dup: "+dups.subList(grab, dups.size()));
   660                 dropArgCount += 1;
   645                 dups.subList(grab, dups.size()).clear();
   661             }
   646                 // In the new target type drop that many args from the tail:
   662             //if (dropArgCount > 1)  System.out.println("Drop: "+drops.subList(0, dropArgCount));
   647                 List<Class<?>> ptypes = oldType.parameterList();
   663             drops.subList(0, dropArgCount).clear();
   648                 ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
   664             List<Class<?>> dropTypes = newType.parameterList()
   649                 MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
   665                     .subList(dropArgPos, dropArgPos + dropArgCount);
   650                 target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
   666             MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
   651                 if (target == null)
   667             target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
   652                     throw newIllegalArgumentException("cannot dup");
   668             if (target == null)  throw newIllegalArgumentException("cannot drop");
   653                 oldType = target.type();
   669             oldType = target.type();
   654             }
   670         }
   655             while (!drops.isEmpty()) {
   671         return convertArguments(target, newType, oldType, 0);
   656                 // Grab a contiguous initial sequence of drops.
   672     }
   657                 int dropArgPos = drops.get(0), dropArgCount = 1;
   673 
   658                 while (dropArgCount < drops.size()) {
   674     /*non-public*/ static
   659                     int drop1 = drops.get(dropArgCount);
   675     MethodHandle convertArguments(MethodHandle target, MethodType newType, int level) {
   660                     if (drop1 != dropArgPos + dropArgCount)  break;
   676         MethodType oldType = target.type();
   661                     dropArgCount += 1;
   677         if (oldType.equals(newType))
   662                 }
   678             return target;
   663                 //if (dropArgCount > 1)  System.out.println("Drop: "+drops.subList(0, dropArgCount));
   679         assert(level > 1 || oldType.isConvertibleTo(newType));
   664                 drops.subList(0, dropArgCount).clear();
   680         MethodHandle retFilter = null;
   665                 List<Class<?>> dropTypes = newType.parameterList()
   681         Class<?> oldRT = oldType.returnType();
   666                         .subList(dropArgPos, dropArgPos + dropArgCount);
   682         Class<?> newRT = newType.returnType();
   667                 MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
   683         if (!VerifyType.isNullConversion(oldRT, newRT)) {
   668                 target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
   684             if (oldRT == void.class) {
   669                 if (target == null)  throw newIllegalArgumentException("cannot drop");
   685                 Wrapper wrap = newRT.isPrimitive() ? Wrapper.forPrimitiveType(newRT) : Wrapper.OBJECT;
   670                 oldType = target.type();
   686                 retFilter = ValueConversions.zeroConstantFunction(wrap);
   671             }
   687             } else {
   672         }
   688                 retFilter = MethodHandles.identity(newRT);
       
   689                 retFilter = convertArguments(retFilter, retFilter.type().changeParameterType(0, oldRT), level);
       
   690             }
       
   691             newType = newType.changeReturnType(oldRT);
       
   692         }
       
   693         MethodHandle res = null;
       
   694         Exception ex = null;
       
   695         try {
       
   696             res = convertArguments(target, newType, oldType, level);
       
   697         } catch (IllegalArgumentException ex1) {
       
   698             ex = ex1;
       
   699         }
       
   700         if (res == null) {
       
   701             WrongMethodTypeException wmt = new WrongMethodTypeException("cannot convert to "+newType+": "+target);
       
   702             wmt.initCause(ex);
       
   703             throw wmt;
       
   704         }
       
   705         if (retFilter != null)
       
   706             res = MethodHandles.filterReturnValue(res, retFilter);
       
   707         return res;
       
   708     }
       
   709 
       
   710     static MethodHandle convertArguments(MethodHandle target,
       
   711                                                 MethodType newType,
       
   712                                                 MethodType oldType,
       
   713                                                 int level) {
       
   714         assert(oldType.parameterCount() == target.type().parameterCount());
   673         if (newType == oldType)
   715         if (newType == oldType)
   674             return target;
   716             return target;
   675         if (oldType.parameterCount() != newType.parameterCount())
   717         if (oldType.parameterCount() != newType.parameterCount())
   676             throw newIllegalArgumentException("mismatched parameter count");
   718             throw newIllegalArgumentException("mismatched parameter count", oldType, newType);
   677         MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target);
   719         MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target, level);
   678         if (res != null)
   720         if (res != null)
   679             return res;
   721             return res;
       
   722         // We can come here in the case of target(int)void => (Object)void,
       
   723         // because the unboxing logic for Object => int is complex.
   680         int argc = oldType.parameterCount();
   724         int argc = oldType.parameterCount();
       
   725         assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
   681         // The JVM can't do it directly, so fill in the gap with a Java adapter.
   726         // The JVM can't do it directly, so fill in the gap with a Java adapter.
   682         // TO DO: figure out what to put here from case-by-case experience
   727         // TO DO: figure out what to put here from case-by-case experience
   683         // Use a heavier method:  Convert all the arguments to Object,
   728         // Use a heavier method:  Convert all the arguments to Object,
   684         // then back to the desired types.  We might have to use Java-based
   729         // then back to the desired types.  We might have to use Java-based
   685         // method handles to do this.
   730         // method handles to do this.
   686         MethodType objType = MethodType.genericMethodType(argc);
   731         MethodType objType = MethodType.genericMethodType(argc);
   687         MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target);
   732         MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target, level);
   688         if (objTarget == null)
   733         if (objTarget == null)
   689             objTarget = FromGeneric.make(target);
   734             objTarget = FromGeneric.make(target);
   690         res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget);
   735         res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget, level);
   691         if (res != null)
   736         if (res != null)
   692             return res;
   737             return res;
   693         return ToGeneric.make(newType, objTarget);
   738         return ToGeneric.make(newType, objTarget);
   694     }
   739     }
   695 
   740 
       
   741     static MethodHandle spreadArguments(MethodHandle target, Class<?> arrayType, int arrayLength) {
       
   742         MethodType oldType = target.type();
       
   743         int nargs = oldType.parameterCount();
       
   744         int keepPosArgs = nargs - arrayLength;
       
   745         MethodType newType = oldType
       
   746                 .dropParameterTypes(keepPosArgs, nargs)
       
   747                 .insertParameterTypes(keepPosArgs, arrayType);
       
   748         return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength);
       
   749     }
       
   750     static MethodHandle spreadArguments(MethodHandle target, MethodType newType, int spreadArgPos) {
       
   751         int arrayLength = target.type().parameterCount() - spreadArgPos;
       
   752         return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength);
       
   753     }
   696     static MethodHandle spreadArguments(MethodHandle target,
   754     static MethodHandle spreadArguments(MethodHandle target,
   697                                                MethodType newType,
   755                                                MethodType newType,
   698                                                int spreadArg) {
   756                                                int spreadArgPos,
       
   757                                                Class<?> arrayType,
       
   758                                                int arrayLength) {
   699         // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
   759         // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
   700         MethodType oldType = target.type();
   760         MethodType oldType = target.type();
   701         // spread the last argument of newType to oldType
   761         // spread the last argument of newType to oldType
   702         int spreadCount = oldType.parameterCount() - spreadArg;
   762         assert(arrayLength == oldType.parameterCount() - spreadArgPos);
   703         Class<Object[]> spreadArgType = Object[].class;
   763         assert(newType.parameterType(spreadArgPos) == arrayType);
   704         MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, spreadArgType, spreadArg, spreadCount);
   764         MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
   705         if (res != null)
   765         if (res == null)  throw new IllegalArgumentException("spread on "+target+" with "+arrayType.getSimpleName());
   706             return res;
       
   707         // try an intermediate adapter
       
   708         Class<?> spreadType = null;
       
   709         if (spreadArg < 0 || spreadArg >= newType.parameterCount()
       
   710             || !VerifyType.isSpreadArgType(spreadType = newType.parameterType(spreadArg)))
       
   711             throw newIllegalArgumentException("no restarg in "+newType);
       
   712         Class<?>[] ptypes = oldType.parameterArray();
       
   713         for (int i = 0; i < spreadCount; i++)
       
   714             ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
       
   715         MethodType midType = MethodType.methodType(newType.returnType(), ptypes);
       
   716         // after spreading, some arguments may need further conversion
       
   717         MethodHandle target2 = convertArguments(target, midType, oldType, null);
       
   718         if (target2 == null)
       
   719             throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType);
       
   720         res = AdapterMethodHandle.makeSpreadArguments(newType, target2, spreadArgType, spreadArg, spreadCount);
       
   721         if (res != null)
       
   722             return res;
       
   723         res = SpreadGeneric.make(target2, spreadCount);
       
   724         if (res != null)
       
   725             res = convertArguments(res, newType, res.type(), null);
       
   726         return res;
   766         return res;
   727     }
   767     }
   728 
   768 
       
   769     static MethodHandle collectArguments(MethodHandle target,
       
   770                                                 int collectArg,
       
   771                                                 MethodHandle collector) {
       
   772         MethodType type = target.type();
       
   773         Class<?> collectType = collector.type().returnType();
       
   774         if (collectType != type.parameterType(collectArg))
       
   775             target = target.asType(type.changeParameterType(collectArg, collectType));
       
   776         MethodType newType = type
       
   777                 .dropParameterTypes(collectArg, collectArg+1)
       
   778                 .insertParameterTypes(collectArg, collector.type().parameterArray());
       
   779         return collectArguments(target, newType, collectArg, collector);
       
   780     }
   729     static MethodHandle collectArguments(MethodHandle target,
   781     static MethodHandle collectArguments(MethodHandle target,
   730                                                 MethodType newType,
   782                                                 MethodType newType,
   731                                                 int collectArg,
   783                                                 int collectArg,
   732                                                 MethodHandle collector) {
   784                                                 MethodHandle collector) {
   733         MethodType oldType = target.type();     // (a...,c)=>r
   785         MethodType oldType = target.type();     // (a...,c)=>r
   734         if (collector == null) {
       
   735             int numCollect = newType.parameterCount() - oldType.parameterCount() + 1;
       
   736             collector = ValueConversions.varargsArray(numCollect);
       
   737         }
       
   738         //         newType                      // (a..., b...)=>r
   786         //         newType                      // (a..., b...)=>r
   739         MethodType colType = collector.type();  // (b...)=>c
   787         MethodType colType = collector.type();  // (b...)=>c
   740         //         oldType                      // (a..., b...)=>r
   788         //         oldType                      // (a..., b...)=>r
   741         assert(newType.parameterCount() == collectArg + colType.parameterCount());
   789         assert(newType.parameterCount() == collectArg + colType.parameterCount());
   742         assert(oldType.parameterCount() == collectArg + 1);
   790         assert(oldType.parameterCount() == collectArg + 1);
   743         MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
   791         MethodHandle result = null;
   744         MethodHandle gcollector = convertArguments(collector, colType.generic(), colType, null);
   792         if (AdapterMethodHandle.canCollectArguments(oldType, colType, collectArg, false)) {
   745         if (gtarget == null || gcollector == null)  return null;
   793             result = AdapterMethodHandle.makeCollectArguments(target, collector, collectArg, false);
   746         MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
   794         }
   747         MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
   795         if (result == null) {
       
   796             assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
       
   797             MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, 0);
       
   798             MethodHandle gcollector = convertArguments(collector, colType.generic(), colType, 0);
       
   799             if (gtarget == null || gcollector == null)  return null;
       
   800             MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
       
   801             result = convertArguments(gresult, newType, gresult.type(), 0);
       
   802         }
   748         return result;
   803         return result;
   749     }
   804     }
   750 
   805 
   751     static MethodHandle filterArgument(MethodHandle target,
   806     static MethodHandle filterArgument(MethodHandle target,
   752                                               int pos,
   807                                        int pos,
   753                                               MethodHandle filter) {
   808                                        MethodHandle filter) {
   754         MethodType ttype = target.type(), gttype = ttype.generic();
   809         MethodType ttype = target.type();
       
   810         MethodType ftype = filter.type();
       
   811         assert(ftype.parameterCount() == 1);
       
   812         MethodType rtype = ttype.changeParameterType(pos, ftype.parameterType(0));
       
   813         MethodType gttype = ttype.generic();
   755         if (ttype != gttype) {
   814         if (ttype != gttype) {
   756             target = convertArguments(target, gttype, ttype, null);
   815             target = convertArguments(target, gttype, ttype, 0);
   757             ttype = gttype;
   816             ttype = gttype;
   758         }
   817         }
   759         MethodType ftype = filter.type(), gftype = ftype.generic();
   818         MethodType gftype = ftype.generic();
   760         if (ftype.parameterCount() != 1)
       
   761             throw new InternalError();
       
   762         if (ftype != gftype) {
   819         if (ftype != gftype) {
   763             filter = convertArguments(filter, gftype, ftype, null);
   820             filter = convertArguments(filter, gftype, ftype, 0);
   764             ftype = gftype;
   821             ftype = gftype;
   765         }
   822         }
   766         if (ftype == ttype) {
   823         MethodHandle result = null;
       
   824         if (AdapterMethodHandle.canCollectArguments(ttype, ftype, pos, false)) {
       
   825             result = AdapterMethodHandle.makeCollectArguments(target, filter, pos, false);
       
   826         }
       
   827         if (result == null) {
       
   828             assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
       
   829             if (ftype == ttype) {
   767             // simple unary case
   830             // simple unary case
   768             return FilterOneArgument.make(filter, target);
   831                 result = FilterOneArgument.make(filter, target);
   769         }
   832             } else {
   770         return FilterGeneric.makeArgumentFilter(pos, filter, target);
   833                 result = FilterGeneric.makeArgumentFilter(pos, filter, target);
       
   834             }
       
   835         }
       
   836         if (result.type() != rtype)
       
   837             result = result.asType(rtype);
       
   838         return result;
   771     }
   839     }
   772 
   840 
   773     static MethodHandle foldArguments(MethodHandle target,
   841     static MethodHandle foldArguments(MethodHandle target,
   774                                              MethodType newType,
   842                                       MethodType newType,
   775                                              MethodHandle combiner) {
   843                                       int foldPos,
       
   844                                       MethodHandle combiner) {
   776         MethodType oldType = target.type();
   845         MethodType oldType = target.type();
   777         MethodType ctype = combiner.type();
   846         MethodType ctype = combiner.type();
   778         MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
   847         if (AdapterMethodHandle.canCollectArguments(oldType, ctype, foldPos, true)) {
   779         MethodHandle gcombiner = convertArguments(combiner, ctype.generic(), ctype, null);
   848             MethodHandle res = AdapterMethodHandle.makeCollectArguments(target, combiner, foldPos, true);
       
   849             if (res != null)  return res;
       
   850         }
       
   851         assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
       
   852         if (foldPos != 0)  return null;
       
   853         MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, 0);
       
   854         MethodHandle gcombiner = convertArguments(combiner, ctype.generic(), ctype, 0);
       
   855         if (ctype.returnType() == void.class) {
       
   856             gtarget = dropArguments(gtarget, oldType.generic().insertParameterTypes(foldPos, Object.class), foldPos);
       
   857         }
   780         if (gtarget == null || gcombiner == null)  return null;
   858         if (gtarget == null || gcombiner == null)  return null;
   781         MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget);
   859         MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget);
   782         MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
   860         return convertArguments(gresult, newType, gresult.type(), 0);
   783         return result;
       
   784     }
   861     }
   785 
   862 
   786     static
   863     static
   787     MethodHandle dropArguments(MethodHandle target,
   864     MethodHandle dropArguments(MethodHandle target,
   788                                MethodType newType, int argnum) {
   865                                MethodType newType, int argnum) {
   800             super(invoker);
   877             super(invoker);
   801             this.test = test;
   878             this.test = test;
   802             this.target = target;
   879             this.target = target;
   803             this.fallback = fallback;
   880             this.fallback = fallback;
   804         }
   881         }
       
   882         // FIXME: Build the control flow out of foldArguments.
   805         static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
   883         static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
   806             MethodType type = target.type();
   884             MethodType type = target.type();
   807             int nargs = type.parameterCount();
   885             int nargs = type.parameterCount();
   808             if (nargs < INVOKES.length) {
   886             if (nargs < INVOKES.length) {
   809                 MethodHandle invoke = INVOKES[nargs];
   887                 MethodHandle invoke = INVOKES[nargs];
   810                 MethodType gtype = type.generic();
   888                 MethodType gtype = type.generic();
   811                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
   889                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
   812                 MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), null);
   890                 MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), 0);
   813                 MethodHandle gtarget = convertArguments(target, gtype, type, null);
   891                 MethodHandle gtarget = convertArguments(target, gtype, type, 0);
   814                 MethodHandle gfallback = convertArguments(fallback, gtype, type, null);
   892                 MethodHandle gfallback = convertArguments(fallback, gtype, type, 0);
   815                 if (gtest == null || gtarget == null || gfallback == null)  return null;
   893                 if (gtest == null || gtarget == null || gfallback == null)  return null;
   816                 MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
   894                 MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
   817                 return convertArguments(gguard, type, gtype, null);
   895                 return convertArguments(gguard, type, gtype, 0);
   818             } else {
   896             } else {
   819                 MethodHandle invoke = VARARGS_INVOKE;
   897                 MethodHandle invoke = VARARGS_INVOKE;
   820                 MethodType gtype = MethodType.genericMethodType(1);
   898                 MethodType gtype = MethodType.genericMethodType(1);
   821                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
   899                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
   822                 MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0);
   900                 MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0);
   923         private final Class<? extends Throwable> exType;
  1001         private final Class<? extends Throwable> exType;
   924         private final MethodHandle catcher;
  1002         private final MethodHandle catcher;
   925         GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
  1003         GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
   926             this(INVOKES[target.type().parameterCount()], target, exType, catcher);
  1004             this(INVOKES[target.type().parameterCount()], target, exType, catcher);
   927         }
  1005         }
   928        GuardWithCatch(MethodHandle invoker,
  1006         // FIXME: Build the control flow out of foldArguments.
   929                       MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
  1007         GuardWithCatch(MethodHandle invoker,
       
  1008                        MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
   930             super(invoker);
  1009             super(invoker);
   931             this.target = target;
  1010             this.target = target;
   932             this.exType = exType;
  1011             this.exType = exType;
   933             this.catcher = catcher;
  1012             this.catcher = catcher;
   934         }
  1013         }
  1055         MethodType ctype = catcher.type();
  1134         MethodType ctype = catcher.type();
  1056         int nargs = type.parameterCount();
  1135         int nargs = type.parameterCount();
  1057         if (nargs < GuardWithCatch.INVOKES.length) {
  1136         if (nargs < GuardWithCatch.INVOKES.length) {
  1058             MethodType gtype = type.generic();
  1137             MethodType gtype = type.generic();
  1059             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
  1138             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
  1060             MethodHandle gtarget = convertArguments(target, gtype, type, null);
  1139             MethodHandle gtarget = convertArguments(target, gtype, type, 0);
  1061             MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, null);
  1140             MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, 0);
  1062             MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
  1141             MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
  1063             if (gtarget == null || gcatcher == null || gguard == null)  return null;
  1142             if (gtarget == null || gcatcher == null || gguard == null)  return null;
  1064             return convertArguments(gguard, type, gtype, null);
  1143             return convertArguments(gguard, type, gtype, 0);
  1065         } else {
  1144         } else {
  1066             MethodType gtype = MethodType.genericMethodType(0, true);
  1145             MethodType gtype = MethodType.genericMethodType(0, true);
  1067             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
  1146             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
  1068             MethodHandle gtarget = spreadArguments(target, gtype, 0);
  1147             MethodHandle gtarget = spreadArguments(target, gtype, 0);
  1069             MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1);
  1148             MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1);