< prev index next >

src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java

Print this page
rev 15544 : imported patch fold_select
rev 15545 : imported patch noperm

*** 561,573 **** for (Object o : constants) { Objects.requireNonNull(o, "Cannot accept null constants"); } if ((lookup.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) { ! throw new StringConcatException(String.format( ! "Invalid caller: %s", ! lookup.lookupClass().getName())); } int cCount = 0; int oCount = 0; if (generateRecipe) { --- 561,572 ---- for (Object o : constants) { Objects.requireNonNull(o, "Cannot accept null constants"); } if ((lookup.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) { ! throw new StringConcatException("Invalid caller: " + ! lookup.lookupClass().getName()); } int cCount = 0; int oCount = 0; if (generateRecipe) {
*** 1493,1546 **** // Drop all remaining parameter types, leave only helper arguments: MethodHandle mh; mh = MethodHandles.dropArguments(NEW_STRING, 2, ptypes); ! mh = MethodHandles.dropArguments(mh, 0, int.class); // Safety: check that remaining index is zero -- that would mean the storage is completely // overwritten, and no leakage of uninitialized data occurred. ! mh = MethodHandles.filterArgument(mh, 0, CHECK_INDEX); ! // Mix in prependers. This happens when (int, byte[], byte) = (index, storage, coder) is already // known from the combinators below. We are assembling the string backwards, so "index" is the // *ending* index. for (RecipeElement el : recipe.getElements()) { ! MethodHandle prepender; switch (el.getTag()) { ! case TAG_CONST: Object cnst = el.getValue(); ! prepender = MethodHandles.insertArguments(prepender(cnst.getClass()), 3, cnst); break; ! case TAG_ARG: int pos = el.getArgPos(); ! prepender = selectArgument(prepender(ptypes[pos]), 3, ptypes, pos); break; default: throw new StringConcatException("Unhandled tag: " + el.getTag()); } - - // Remove "old" index from arguments - mh = MethodHandles.dropArguments(mh, 1, int.class); - - // Do the prepend, and put "new" index at index 0 - mh = MethodHandles.foldArguments(mh, prepender); - } - - // Prepare the argument list for prepending. The tree below would instantiate - // the storage byte[] into argument 0, so we need to swap "storage" and "index". - // The index at this point equals to "size", and resides at argument 1. - { - MethodType nmt = mh.type() - .changeParameterType(0, byte[].class) - .changeParameterType(1, int.class); - mh = MethodHandles.permuteArguments(mh, nmt, swap10(nmt.parameterCount())); } ! // Fold in byte[] instantiation at argument 0. ! MethodHandle combiner = MethodHandles.dropArguments(NEW_ARRAY, 2, ptypes); ! mh = MethodHandles.foldArguments(mh, combiner); // Start combining length and coder mixers. // // Length is easy: constant lengths can be computed on the spot, and all non-constant // shapes have been either converted to Strings, or explicit methods for getting the --- 1492,1540 ---- // Drop all remaining parameter types, leave only helper arguments: MethodHandle mh; mh = MethodHandles.dropArguments(NEW_STRING, 2, ptypes); ! mh = MethodHandles.dropArguments(mh, 1, int.class); // Safety: check that remaining index is zero -- that would mean the storage is completely // overwritten, and no leakage of uninitialized data occurred. ! mh = MethodHandles.filterArgument(mh, 1, CHECK_INDEX); ! // Mix in prependers. This happens when (byte[], int, byte) = (storage, index, coder) is already // known from the combinators below. We are assembling the string backwards, so "index" is the // *ending* index. for (RecipeElement el : recipe.getElements()) { ! // Do the prepend, and put "new" index at index 1 ! mh = MethodHandles.dropArguments(mh, 2, int.class); switch (el.getTag()) { ! case TAG_CONST: { Object cnst = el.getValue(); ! MethodHandle prepender = MethodHandles.insertArguments(prepender(cnst.getClass()), 3, cnst); ! mh = MethodHandles.foldArguments(mh, 1, prepender, ! 2, 0, 3 // index, storage, coder ! ); break; ! } ! case TAG_ARG: { int pos = el.getArgPos(); ! MethodHandle prepender = prepender(ptypes[pos]); ! mh = MethodHandles.foldArguments(mh, 1, prepender, ! 2, 0, 3, // index, storage, coder ! 4 + pos // selected argument ! ); break; + } default: throw new StringConcatException("Unhandled tag: " + el.getTag()); } } ! // Fold in byte[] instantiation at argument 0 ! mh = MethodHandles.foldArguments(mh, 0, NEW_ARRAY, ! 1, 2 // index, coder ! ); // Start combining length and coder mixers. // // Length is easy: constant lengths can be computed on the spot, and all non-constant // shapes have been either converted to Strings, or explicit methods for getting the
*** 1565,1593 **** break; case TAG_ARG: int ac = el.getArgPos(); Class<?> argClass = ptypes[ac]; ! MethodHandle lm = selectArgument(lengthMixer(argClass), 1, ptypes, ac); ! lm = MethodHandles.dropArguments(lm, 0, byte.class); // (*) ! lm = MethodHandles.dropArguments(lm, 2, byte.class); ! ! MethodHandle cm = selectArgument(coderMixer(argClass), 1, ptypes, ac); ! cm = MethodHandles.dropArguments(cm, 0, int.class); // (**) // Read this bottom up: // 4. Drop old index and coder, producing ("new-index", "new-coder", <args>) mh = MethodHandles.dropArguments(mh, 2, int.class, byte.class); // 3. Compute "new-index", producing ("new-index", "new-coder", "old-index", "old-coder", <args>) ! // Length mixer ignores both "new-coder" and "old-coder" due to dropArguments above (*) ! mh = MethodHandles.foldArguments(mh, lm); // 2. Compute "new-coder", producing ("new-coder", "old-index", "old-coder", <args>) ! // Coder mixer ignores the "old-index" arg due to dropArguments above (**) ! mh = MethodHandles.foldArguments(mh, cm); // 1. The mh shape here is ("old-index", "old-coder", <args>) break; default: throw new StringConcatException("Unhandled tag: " + el.getTag()); --- 1559,1589 ---- break; case TAG_ARG: int ac = el.getArgPos(); Class<?> argClass = ptypes[ac]; ! MethodHandle lm = lengthMixer(argClass); ! MethodHandle cm = coderMixer(argClass); // Read this bottom up: // 4. Drop old index and coder, producing ("new-index", "new-coder", <args>) mh = MethodHandles.dropArguments(mh, 2, int.class, byte.class); // 3. Compute "new-index", producing ("new-index", "new-coder", "old-index", "old-coder", <args>) ! // Length mixer needs old index, plus the appropriate argument ! mh = MethodHandles.foldArguments(mh, 0, lm, ! 2, // old-index ! 4 + ac // selected argument ! ); // 2. Compute "new-coder", producing ("new-coder", "old-index", "old-coder", <args>) ! // Coder mixer needs old coder, plus the appropriate argument. ! mh = MethodHandles.foldArguments(mh, 0, cm, ! 2, // old-coder ! 3 + ac // selected argument ! ); // 1. The mh shape here is ("old-index", "old-coder", <args>) break; default: throw new StringConcatException("Unhandled tag: " + el.getTag());
*** 1604,1635 **** } return mh; } - private static int[] swap10(int count) { - int[] perm = new int[count]; - perm[0] = 1; - perm[1] = 0; - for (int i = 2; i < count; i++) { - perm[i] = i; - } - return perm; - } - - // Adapts: (...prefix..., parameter[pos])R -> (...prefix..., ...parameters...)R - private static MethodHandle selectArgument(MethodHandle mh, int prefix, Class<?>[] ptypes, int pos) { - if (pos == 0) { - return MethodHandles.dropArguments(mh, prefix + 1, Arrays.copyOfRange(ptypes, 1, ptypes.length)); - } else if (pos == ptypes.length - 1) { - return MethodHandles.dropArguments(mh, prefix, Arrays.copyOf(ptypes, ptypes.length - 1)); - } else { // 0 < pos < ptypes.size() - 1 - MethodHandle t = MethodHandles.dropArguments(mh, prefix, Arrays.copyOf(ptypes, pos)); - return MethodHandles.dropArguments(t, prefix + 1 + pos, Arrays.copyOfRange(ptypes, pos + 1, ptypes.length)); - } - } - @ForceInline private static byte[] newArray(int length, byte coder) { return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, length << coder); } --- 1600,1609 ----
< prev index next >