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