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) { |