Make Formatter %d cost about the same as %s (i.e. 60% faster).

Fast-path "%d" and "%s", the only two cases that matter, so they don't have to
go through all the flags, width, and precision machinery unless flags, widths,
or precisions are actually specified.

This makes "%s" slightly but not significantly faster -- because I'd already
optimized that code for the default case pretty well -- but makes a huge
difference to "%d", which wasn't as amenable to general optimization.

I've also improved the identifiers and comments surrounding the date suffix,
after TraceView misled me into attempting to optimize this non-hotspot (though
to be fair, I'm only benchmarking on passion-eng with JIT; TraceView might be
telling the truth for a G1 without JIT).

TraceView also misled me into trying to optimize away the check for uppercase
conversion types at the end of Transformer.transform (by adding different bodies
to the uppercase entries in the switch directly above it), but that made no
convincing difference on passion-eng.

Bug: 2272346
diff --git a/libcore/luni/src/main/java/java/util/Formatter.java b/libcore/luni/src/main/java/java/util/Formatter.java
index 71051ee..0a4250d 100644
--- a/libcore/luni/src/main/java/java/util/Formatter.java
+++ b/libcore/luni/src/main/java/java/util/Formatter.java
@@ -1027,10 +1027,15 @@
 
         private StringBuilder strFlags;
 
-        private char dateSuffix;// will be used in new feature.
+        private char dateSuffix;
 
         private char conversionType = (char) UNSET;
 
+        // Tests whether there were no flags, no width, and no precision specified.
+        boolean isDefault() {
+            return flags == 0 && width == UNSET && precision == UNSET;
+        }
+
         boolean isPrecisionSet() {
             return precision != UNSET;
         }
@@ -1200,11 +1205,29 @@
          * argument.
          */
         CharSequence transform(FormatToken token, Object argument) {
-
-            /* init data member to print */
             this.formatToken = token;
             this.arg = argument;
 
+            // There are only two format specifiers that matter: "%d" and "%s".
+            // Nothing else is common in the wild. We fast-path these two to
+            // avoid the heavyweight machinery needed to cope with all the
+            if (token.isDefault()) {
+                switch (token.getConversionType()) {
+                case 's':
+                    if (!(arg instanceof Formattable)) {
+                        return arg.toString();
+                    }
+                    break;
+                case 'd':
+                    if (arg instanceof Integer || arg instanceof Long || arg instanceof Short || arg instanceof Byte) {
+                        // TODO: when we fix the rest of formatter to correctly use locale-specific
+                        // digits when getDecimalFormatSymbols().getZeroDigit() != '0', we'll need
+                        // to add a special case here too.
+                        return arg.toString();
+                    }
+                }
+            }
+
             CharSequence result;
             switch (token.getConversionType()) {
                 case 'B':
@@ -1268,7 +1291,7 @@
             }
 
             if (Character.isUpperCase(token.getConversionType())) {
-                if (null != result) {
+                if (result != null) {
                     result = result.toString().toUpperCase(locale);
                 }
             }
@@ -2684,10 +2707,11 @@
         }
 
         private FormatToken parseConversionType(FormatToken token) {
-            char ch = advance(); // This is mandatory, so no need to peek.
-            token.setConversionType(ch);
-            if (ch == 't' || ch == 'T') {
-                token.setDateSuffix(advance());
+            char conversionType = advance(); // A conversion type is mandatory.
+            token.setConversionType(conversionType);
+            if (conversionType == 't' || conversionType == 'T') {
+                char dateSuffix = advance(); // A date suffix is mandatory for 't' or 'T'.
+                token.setDateSuffix(dateSuffix);
             }
             return token;
         }