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