1664 // Coders are more interesting. Only Object, String and char arguments (and constants) |
1664 // Coders are more interesting. Only Object, String and char arguments (and constants) |
1665 // can have non-Latin1 encoding. It is easier to blindly convert constants to String, |
1665 // can have non-Latin1 encoding. It is easier to blindly convert constants to String, |
1666 // and deduce the coder from there. Arguments would be either converted to Strings |
1666 // and deduce the coder from there. Arguments would be either converted to Strings |
1667 // during the initial filtering, or handled by specializations in MIXERS. |
1667 // during the initial filtering, or handled by specializations in MIXERS. |
1668 // |
1668 // |
1669 // The method handle shape before and after all mixers are combined in is: |
1669 // The method handle shape before all mixers are combined in is: |
1670 // (long, <args>)String = ("indexCoder", <args>) |
1670 // (long, <args>)String = ("indexCoder", <args>) |
1671 |
1671 // |
|
1672 // We will bind the initialLengthCoder value to the last mixer (the one that will be |
|
1673 // executed first), then fold that in. This leaves the shape after all mixers are |
|
1674 // combined in as: |
|
1675 // (<args>)String = (<args>) |
|
1676 |
|
1677 int ac = -1; |
|
1678 MethodHandle mix = null; |
1672 for (RecipeElement el : recipe.getElements()) { |
1679 for (RecipeElement el : recipe.getElements()) { |
1673 switch (el.getTag()) { |
1680 switch (el.getTag()) { |
1674 case TAG_CONST: |
1681 case TAG_CONST: |
1675 // Constants already handled in the code above |
1682 // Constants already handled in the code above |
1676 break; |
1683 break; |
1677 case TAG_ARG: |
1684 case TAG_ARG: |
1678 int ac = el.getArgPos(); |
1685 if (ac >= 0) { |
1679 |
1686 // Compute new "index" in-place using old value plus the appropriate argument. |
|
1687 mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, mix, |
|
1688 0, // old-index |
|
1689 1 + ac // selected argument |
|
1690 ); |
|
1691 } |
|
1692 |
|
1693 ac = el.getArgPos(); |
1680 Class<?> argClass = ptypes[ac]; |
1694 Class<?> argClass = ptypes[ac]; |
1681 MethodHandle mix = mixer(argClass); |
1695 mix = mixer(argClass); |
1682 |
|
1683 // Compute new "index" in-place using old value plus the appropriate argument. |
|
1684 mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, mix, |
|
1685 0, // old-index |
|
1686 1 + ac // selected argument |
|
1687 ); |
|
1688 |
1696 |
1689 break; |
1697 break; |
1690 default: |
1698 default: |
1691 throw new StringConcatException("Unhandled tag: " + el.getTag()); |
1699 throw new StringConcatException("Unhandled tag: " + el.getTag()); |
1692 } |
1700 } |
1693 } |
1701 } |
1694 |
1702 |
1695 // Insert initial length and coder value here. |
1703 // Insert the initialLengthCoder value into the final mixer, then |
|
1704 // fold that into the base method handle |
|
1705 if (ac >= 0) { |
|
1706 mix = MethodHandles.insertArguments(mix, 0, initialLengthCoder); |
|
1707 mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, mix, |
|
1708 1 + ac // selected argument |
|
1709 ); |
|
1710 } else { |
|
1711 // No mixer (constants only concat), insert initialLengthCoder directly |
|
1712 mh = MethodHandles.insertArguments(mh, 0, initialLengthCoder); |
|
1713 } |
|
1714 |
1696 // The method handle shape here is (<args>). |
1715 // The method handle shape here is (<args>). |
1697 mh = MethodHandles.insertArguments(mh, 0, initialLengthCoder); |
|
1698 |
1716 |
1699 // Apply filters, converting the arguments: |
1717 // Apply filters, converting the arguments: |
1700 if (filters != null) { |
1718 if (filters != null) { |
1701 mh = MethodHandles.filterArguments(mh, 0, filters); |
1719 mh = MethodHandles.filterArguments(mh, 0, filters); |
1702 } |
1720 } |