8170467: (reflect) Optimize SignatureParser's use of StringBuilders
authorredestad
Tue, 29 Nov 2016 16:27:19 +0100
changeset 42324 16e82bbefbee
parent 42323 5afe7a82357f
child 42325 3729cdfc89f6
8170467: (reflect) Optimize SignatureParser's use of StringBuilders Reviewed-by: shade, redestad Contributed-by: mkanat@google.com
jdk/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java
--- a/jdk/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java	Tue Nov 29 14:55:56 2016 +0300
+++ b/jdk/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java	Tue Nov 29 16:27:19 2016 +0100
@@ -70,6 +70,11 @@
     private static final char EOI = ':';
     private static final boolean DEBUG = false;
 
+    // StringBuilder does a lot of array copies if we don't pre-size
+    // it when parsing a full class name. This value was determined
+    // empirically by measurements of real-world code.
+    private static final int CLASS_NAME_SB_SIZE = 48;
+
     // private constructor - enforces use of static factory
     private SignatureParser(){}
 
@@ -251,9 +256,19 @@
         return FormalTypeParameter.make(id, bs);
     }
 
-    private String parseIdentifier(){
+    private String parseIdentifier() {
         StringBuilder result = new StringBuilder();
-        while (!Character.isWhitespace(current())) {
+        parseIdentifierInto(result);
+        return result.toString();
+    }
+
+    // This is separate from parseIdentifier for performance reasons.
+    // For a caller who already has a StringBuilder, it's much faster to
+    // re-use the existing builder, because it results in far fewer internal
+    // array copies inside of StringBuilder.
+    private void parseIdentifierInto(StringBuilder result) {
+        int startIndex = index;
+        parseLoop: while (!Character.isWhitespace(current())) {
             char c = current();
             switch(c) {
             case ';':
@@ -263,16 +278,14 @@
             case ':':
             case '>':
             case '<':
-                return result.toString();
-            default:{
-                result.append(c);
+                break parseLoop;
+            default:
                 advance();
             }
+        }
+        result.append(input, startIndex, index - startIndex);
+    }
 
-            }
-        }
-        return result.toString();
-    }
     /**
      * FieldTypeSignature:
      *     ClassTypeSignature
@@ -325,19 +338,17 @@
         // Parse both any optional leading PackageSpecifier as well as
         // the following SimpleClassTypeSignature.
 
-        String id = parseIdentifier();
-
-        if (current() == '/') { // package name
-            StringBuilder idBuild = new StringBuilder(id);
+        StringBuilder idBuild = new StringBuilder(CLASS_NAME_SB_SIZE);
+        parseIdentifierInto(idBuild);
 
-            while(current() == '/') {
-                advance();
-                idBuild.append(".");
-                idBuild.append(parseIdentifier());
-            }
-            id = idBuild.toString();
+        while (current() == '/') { // package name
+            advance();
+            idBuild.append('.');
+            parseIdentifierInto(idBuild);
         }
 
+        String id = idBuild.toString();
+
         switch (current()) {
         case ';':
             return SimpleClassTypeSignature.make(id, false, new TypeArgument[0]); // all done!