8223454: Reduce String concatenation shapes by folding initialLengthCoder into last mixer
authorredestad
Thu, 09 May 2019 17:28:27 +0200
changeset 54791 04f603ebb6c2
parent 54790 b77bf7f216f4
child 54792 81607d4919c0
8223454: Reduce String concatenation shapes by folding initialLengthCoder into last mixer Reviewed-by: jlaskey
src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java
--- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Fri May 03 14:38:58 2019 +0200
+++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Thu May 09 17:28:27 2019 +0200
@@ -1666,25 +1666,33 @@
             // 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:
+            // The method handle shape before all mixers are combined in is:
             //   (long, <args>)String = ("indexCoder", <args>)
+            //
+            // We will bind the initialLengthCoder value to the last mixer (the one that will be
+            // executed first), then fold that in. This leaves the shape after all mixers are
+            // combined in as:
+            //   (<args>)String = (<args>)
 
+            int ac = -1;
+            MethodHandle mix = null;
             for (RecipeElement el : recipe.getElements()) {
                 switch (el.getTag()) {
                     case TAG_CONST:
                         // Constants already handled in the code above
                         break;
                     case TAG_ARG:
-                        int ac = el.getArgPos();
-
-                        Class<?> argClass = ptypes[ac];
-                        MethodHandle mix = mixer(argClass);
+                        if (ac >= 0) {
+                            // 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
+                            );
+                        }
 
-                        // 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
-                        );
+                        ac = el.getArgPos();
+                        Class<?> argClass = ptypes[ac];
+                        mix = mixer(argClass);
 
                         break;
                     default:
@@ -1692,9 +1700,19 @@
                 }
             }
 
-            // Insert initial length and coder value here.
+            // Insert the initialLengthCoder value into the final mixer, then
+            // fold that into the base method handle
+            if (ac >= 0) {
+                mix = MethodHandles.insertArguments(mix, 0, initialLengthCoder);
+                mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, mix,
+                        1 + ac // selected argument
+                );
+            } else {
+                // No mixer (constants only concat), insert initialLengthCoder directly
+                mh = MethodHandles.insertArguments(mh, 0, initialLengthCoder);
+            }
+
             // The method handle shape here is (<args>).
-            mh = MethodHandles.insertArguments(mh, 0, initialLengthCoder);
 
             // Apply filters, converting the arguments:
             if (filters != null) {