8213741: Consolidate Object and String Stringifiers
authorredestad
Tue, 13 Nov 2018 11:34:54 +0100
changeset 52497 34510f65fb58
parent 52496 13f0aac77d60
child 52498 c3066f7465fa
8213741: Consolidate Object and String Stringifiers Reviewed-by: shade
src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java
--- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Mon Nov 12 16:36:05 2018 -0500
+++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Tue Nov 13 11:34:54 2018 +0100
@@ -1629,7 +1629,7 @@
         @ForceInline
         private static byte[] newArray(long indexCoder) {
             byte coder = (byte)(indexCoder >> 32);
-            int index = ((int)indexCoder & 0x7FFFFFFF);
+            int index = (int)indexCoder;
             return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder);
         }
 
@@ -1692,30 +1692,35 @@
             // no instantiation
         }
 
-        private static class StringifierMost extends ClassValue<MethodHandle> {
-            @Override
-            protected MethodHandle computeValue(Class<?> cl) {
-                if (cl == String.class) {
-                    return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
-                } else if (cl == float.class) {
-                    return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, float.class);
-                } else if (cl == double.class) {
-                    return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, double.class);
-                } else if (!cl.isPrimitive()) {
-                    MethodHandle mhObject = lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
+        private static class ObjectStringifier {
+
+            // We need some additional conversion for Objects in general, because String.valueOf(Object)
+            // may return null. String conversion rules in Java state we need to produce "null" String
+            // in this case, so we provide a customized version that deals with this problematic corner case.
+            private static String valueOf(Object value) {
+                String s;
+                return (value == null || (s = value.toString()) == null) ? "null" : s;
+            }
 
-                    // We need the additional conversion here, because String.valueOf(Object) may return null.
-                    // String conversion rules in Java state we need to produce "null" String in this case.
-                    // It can be easily done with applying valueOf the second time.
-                    return MethodHandles.filterReturnValue(mhObject,
-                            mhObject.asType(MethodType.methodType(String.class, String.class)));
-                }
+            // Could have used MethodHandles.lookup() instead of Lookup.IMPL_LOOKUP, if not for the fact
+            // java.lang.invoke Lookups are explicitly forbidden to be retrieved using that API.
+            private static final MethodHandle INSTANCE =
+                    lookupStatic(Lookup.IMPL_LOOKUP, ObjectStringifier.class, "valueOf", String.class, Object.class);
+
+        }
 
-                return null;
-            }
+        private static class FloatStringifiers {
+            private static final MethodHandle FLOAT_INSTANCE =
+                    lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, float.class);
+
+            private static final MethodHandle DOUBLE_INSTANCE =
+                    lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, double.class);
         }
 
         private static class StringifierAny extends ClassValue<MethodHandle> {
+
+            private static final ClassValue<MethodHandle> INSTANCE = new StringifierAny();
+
             @Override
             protected MethodHandle computeValue(Class<?> cl) {
                 if (cl == byte.class || cl == short.class || cl == int.class) {
@@ -1727,7 +1732,7 @@
                 } else if (cl == long.class) {
                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, long.class);
                 } else {
-                    MethodHandle mh = STRINGIFIERS_MOST.get(cl);
+                    MethodHandle mh = forMost(cl);
                     if (mh != null) {
                         return mh;
                     } else {
@@ -1737,9 +1742,6 @@
             }
         }
 
-        private static final ClassValue<MethodHandle> STRINGIFIERS_MOST = new StringifierMost();
-        private static final ClassValue<MethodHandle> STRINGIFIERS_ANY = new StringifierAny();
-
         /**
          * Returns a stringifier for references and floats/doubles only.
          * Always returns null for other primitives.
@@ -1748,7 +1750,14 @@
          * @return stringifier; null, if not available
          */
         static MethodHandle forMost(Class<?> t) {
-            return STRINGIFIERS_MOST.get(t);
+            if (!t.isPrimitive()) {
+                return ObjectStringifier.INSTANCE;
+            } else if (t == float.class) {
+                return FloatStringifiers.FLOAT_INSTANCE;
+            } else if (t == double.class) {
+                return FloatStringifiers.DOUBLE_INSTANCE;
+            }
+            return null;
         }
 
         /**
@@ -1758,7 +1767,7 @@
          * @return stringifier
          */
         static MethodHandle forAny(Class<?> t) {
-            return STRINGIFIERS_ANY.get(t);
+            return StringifierAny.INSTANCE.get(t);
         }
     }