< prev index next >
src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java
Print this page
rev 54588 : imported patch constant_prepend
*** 1577,1602 ****
// Drop all remaining parameter types, leave only helper arguments:
MethodHandle mh;
mh = MethodHandles.dropArguments(NEW_STRING, 2, ptypes);
// Mix in prependers. This happens when (byte[], long) = (storage, indexCoder) is already
// known from the combinators below. We are assembling the string backwards, so the index coded
// into indexCoder is the *ending* index.
for (RecipeElement el : recipe.getElements()) {
// Do the prepend, and put "new" index at index 1
switch (el.getTag()) {
case TAG_CONST: {
! MethodHandle prepender = MethodHandles.insertArguments(prepender(String.class), 2, el.getValue());
! mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
! 1, 0 // indexCoder, storage
! );
break;
}
case TAG_ARG: {
int pos = el.getArgPos();
! MethodHandle prepender = prepender(ptypes[pos]);
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
1, 0, // indexCoder, storage
2 + pos // selected argument
);
break;
--- 1577,1615 ----
// Drop all remaining parameter types, leave only helper arguments:
MethodHandle mh;
mh = MethodHandles.dropArguments(NEW_STRING, 2, ptypes);
+ long initialLengthCoder = INITIAL_CODER;
+
// Mix in prependers. This happens when (byte[], long) = (storage, indexCoder) is already
// known from the combinators below. We are assembling the string backwards, so the index coded
// into indexCoder is the *ending* index.
+ String constant = null;
for (RecipeElement el : recipe.getElements()) {
// Do the prepend, and put "new" index at index 1
switch (el.getTag()) {
case TAG_CONST: {
! String constantValue = el.getValue();
! initialLengthCoder = (long)mixer(String.class).invoke(initialLengthCoder, constantValue);
! if (constant != null) {
! // fold sequential constants into one
! constant = constant + constantValue;
! } else {
! constant = constantValue;
! }
break;
}
case TAG_ARG: {
int pos = el.getArgPos();
! MethodHandle prepender;
! if (constant != null) {
! prepender = prepender(constant, ptypes[pos]);
! constant = null;
! } else {
! prepender = prepender(ptypes[pos]);
! }
mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
1, 0, // indexCoder, storage
2 + pos // selected argument
);
break;
*** 1604,1613 ****
--- 1617,1634 ----
default:
throw new StringConcatException("Unhandled tag: " + el.getTag());
}
}
+ // Insert any trailing constant
+ if (constant != null) {
+ MethodHandle prepender = MethodHandles.insertArguments(prepender(String.class), 2, constant);
+ mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,
+ 1, 0 // indexCoder, storage
+ );
+ }
+
// Fold in byte[] instantiation at argument 0
mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, NEW_ARRAY,
1 // index
);
*** 1622,1653 ****
// and deduce the coder from there. Arguments would be either converted to Strings
// during the initial filtering, or handled by specializations in MIXERS.
//
// The method handle shape before and after all mixers are combined in is:
// (long, <args>)String = ("indexCoder", <args>)
! long initialLengthCoder = INITIAL_CODER;
for (RecipeElement el : recipe.getElements()) {
! switch (el.getTag()) {
! case TAG_CONST:
! String constant = el.getValue();
! initialLengthCoder = (long)mixer(String.class).invoke(initialLengthCoder, constant);
! break;
! case TAG_ARG:
int ac = el.getArgPos();
Class<?> argClass = ptypes[ac];
MethodHandle mix = mixer(argClass);
// Compute new "index" in-place using old value plus the appropriate argument.
mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, mix,
0, // old-index
1 + ac // selected argument
);
-
- break;
- default:
- throw new StringConcatException("Unhandled tag: " + el.getTag());
}
}
// Insert initial length and coder value here.
// The method handle shape here is (<args>).
--- 1643,1665 ----
// and deduce the coder from there. Arguments would be either converted to Strings
// during the initial filtering, or handled by specializations in MIXERS.
//
// The method handle shape before and after all mixers are combined in is:
// (long, <args>)String = ("indexCoder", <args>)
!
for (RecipeElement el : recipe.getElements()) {
! if (el.getTag() == TAG_ARG) {
int ac = el.getArgPos();
Class<?> argClass = ptypes[ac];
MethodHandle mix = mixer(argClass);
// Compute new "index" in-place using old value plus the appropriate argument.
mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, mix,
0, // old-index
1 + ac // selected argument
);
}
}
// Insert initial length and coder value here.
// The method handle shape here is (<args>).
*** 1663,1672 ****
--- 1675,1690 ----
private static MethodHandle prepender(Class<?> cl) {
return PREPENDERS.computeIfAbsent(cl, PREPEND);
}
+ private static MethodHandle prepender(String constant, Class<?> cl) {
+ return MethodHandles.insertArguments(
+ CONSTANT_PREPENDERS.computeIfAbsent(cl, CONSTANT_PREPEND),
+ 2, constant);
+ }
+
private static MethodHandle mixer(Class<?> cl) {
return MIXERS.computeIfAbsent(cl, MIX);
}
// This one is deliberately non-lambdified to optimize startup time:
*** 1677,1686 ****
--- 1695,1713 ----
Wrapper.asPrimitiveType(c));
}
};
// This one is deliberately non-lambdified to optimize startup time:
+ private static final Function<Class<?>, MethodHandle> CONSTANT_PREPEND = new Function<Class<?>, MethodHandle>() {
+ @Override
+ public MethodHandle apply(Class<?> c) {
+ return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", long.class, long.class, byte[].class,
+ String.class, Wrapper.asPrimitiveType(c));
+ }
+ };
+
+ // This one is deliberately non-lambdified to optimize startup time:
private static final Function<Class<?>, MethodHandle> MIX = new Function<Class<?>, MethodHandle>() {
@Override
public MethodHandle apply(Class<?> c) {
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mix", long.class, long.class,
Wrapper.asPrimitiveType(c));
*** 1689,1698 ****
--- 1716,1726 ----
private static final MethodHandle SIMPLE;
private static final MethodHandle NEW_STRING;
private static final MethodHandle NEW_ARRAY;
private static final ConcurrentMap<Class<?>, MethodHandle> PREPENDERS;
+ private static final ConcurrentMap<Class<?>, MethodHandle> CONSTANT_PREPENDERS;
private static final ConcurrentMap<Class<?>, MethodHandle> MIXERS;
private static final long INITIAL_CODER;
static {
try {
*** 1700,1709 ****
--- 1728,1738 ----
INITIAL_CODER = (long) initCoder.invoke();
} catch (Throwable e) {
throw new AssertionError(e);
}
+ CONSTANT_PREPENDERS = new ConcurrentHashMap<>();
PREPENDERS = new ConcurrentHashMap<>();
MIXERS = new ConcurrentHashMap<>();
SIMPLE = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "simpleConcat", String.class, Object.class, Object.class);
NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, long.class);
< prev index next >