8170467: (reflect) Optimize SignatureParser's use of StringBuilders
Reviewed-by: shade, redestad
Contributed-by: mkanat@google.com
--- 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!