8212597: Optimize String concatenation setup when using primitive operands
authorredestad
Wed, 17 Oct 2018 17:35:26 +0200
changeset 52177 430e6421d503
parent 52176 cba34f27d9ce
child 52178 199658d1ef86
8212597: Optimize String concatenation setup when using primitive operands Reviewed-by: shade
make/jdk/src/classes/build/tools/classlist/HelloClasslist.java
src/java.base/share/classes/java/lang/StringConcatHelper.java
src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java
--- a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java	Wed Oct 17 22:06:55 2018 +0800
+++ b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java	Wed Oct 17 17:35:26 2018 +0200
@@ -66,6 +66,15 @@
         Stream.of(helloWorld.split(","))
               .forEach(System.out::println);
 
+        // Common concatenation patterns
+        String const_I = "string" + args.length;
+        String const_S = "string" + String.valueOf(args.length);
+        String S_const = String.valueOf(args.length) + "string";
+        String S_S     = String.valueOf(args.length) + String.valueOf(args.length);
+        String const_J = "string" + System.currentTimeMillis();
+        String I_const = args.length + "string";
+        String J_const = System.currentTimeMillis() + "string";
+
         String newDate = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
                 LocalDateTime.now(ZoneId.of("GMT")));
 
--- a/src/java.base/share/classes/java/lang/StringConcatHelper.java	Wed Oct 17 22:06:55 2018 +0800
+++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java	Wed Oct 17 17:35:26 2018 +0200
@@ -139,61 +139,6 @@
     }
 
     /**
-     * Mix coder into current coder
-     * @param current current coder
-     * @param value   value to mix in
-     * @return new coder
-     */
-    static byte mixCoder(byte current, boolean value) {
-        // Booleans are represented with Latin1
-        return current;
-    }
-
-    /**
-     * Mix coder into current coder
-     * @param current current coder
-     * @param value   value to mix in
-     * @return new coder
-     */
-    static byte mixCoder(byte current, byte value) {
-        // Bytes are represented with Latin1
-        return current;
-    }
-
-    /**
-     * Mix coder into current coder
-     * @param current current coder
-     * @param value   value to mix in
-     * @return new coder
-     */
-    static byte mixCoder(byte current, short value) {
-        // Shorts are represented with Latin1
-        return current;
-    }
-
-    /**
-     * Mix coder into current coder
-     * @param current current coder
-     * @param value   value to mix in
-     * @return new coder
-     */
-    static byte mixCoder(byte current, int value) {
-        // Ints are represented with Latin1
-        return current;
-    }
-
-    /**
-     * Mix coder into current coder
-     * @param current current coder
-     * @param value   value to mix in
-     * @return new coder
-     */
-    static byte mixCoder(byte current, long value) {
-        // Longs are represented with Latin1
-        return current;
-    }
-
-    /**
      * Prepends the stringly representation of boolean value into buffer,
      * given the coder and final index. Index is measured in chars, not in bytes!
      *
--- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Wed Oct 17 22:06:55 2018 +0800
+++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Wed Oct 17 17:35:26 2018 +0200
@@ -1588,28 +1588,47 @@
 
                         Class<?> argClass = ptypes[ac];
                         MethodHandle lm = lengthMixer(argClass);
-                        MethodHandle cm = coderMixer(argClass);
+
+                        // Read these bottom up:
+
+                        if (argClass.isPrimitive() && argClass != char.class) {
+
+                            // 3. Drop old index, producing ("new-index", "coder", <args>)
+                            mh = MethodHandles.dropArguments(mh, 1, int.class);
 
-                        // Read this bottom up:
+                            // 2. Compute "new-index", producing ("new-index", "old-index", "coder", <args>)
+                            //    Length mixer needs old index, plus the appropriate argument
+                            mh = MethodHandles.foldArguments(mh, 0, lm,
+                                    1, // old-index
+                                    3 + ac // selected argument
+                            );
 
-                        // 4. Drop old index and coder, producing ("new-index", "new-coder", <args>)
-                        mh = MethodHandles.dropArguments(mh, 2, int.class, byte.class);
+                            // 1. The mh shape here is ("old-index", "coder", <args>); we don't need to recalculate
+                            //    the coder for non-char primitive arguments
+
+                        } else {
+                            MethodHandle cm = coderMixer(argClass);
 
-                        // 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
-                        );
+                            // 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
-                        );
+                            // 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>)
+                            // 1. The mh shape here is ("old-index", "old-coder", <args>)
+                        }
+
                         break;
                     default:
                         throw new StringConcatException("Unhandled tag: " + el.getTag());