< prev index next >

src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java

Print this page
rev 52487 : 8213741: Consolidate Object and String Stringifiers
Reviewed-by: TBD

@@ -1627,11 +1627,11 @@
         }
 
         @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);
         }
 
         private static MethodHandle prepender(Class<?> cl) {
             return PREPENDERS.computeIfAbsent(cl, PREPEND);

@@ -1690,34 +1690,39 @@
     private static final class Stringifiers {
         private Stringifiers() {
             // 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);
-
-                    // 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)));
+        private static class StringStringifier {
+
+            // 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;
                 }
 
-                return null;
+            // 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, StringStringifier.class, "valueOf", String.class, Object.class);
+
             }
+
+        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) {
                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, int.class);
                 } else if (cl == boolean.class) {

@@ -1725,42 +1730,46 @@
                 } else if (cl == char.class) {
                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, char.class);
                 } 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 {
                         throw new IllegalStateException("Unknown class: " + cl);
                     }
                 }
             }
         }
 
-        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.
          *
          * @param t class to stringify
          * @return stringifier; null, if not available
          */
         static MethodHandle forMost(Class<?> t) {
-            return STRINGIFIERS_MOST.get(t);
+            if (!t.isPrimitive()) {
+                return StringStringifier.INSTANCE;
+            } else if (t == float.class) {
+                return FloatStringifiers.FLOAT_INSTANCE;
+            } else if (t == double.class) {
+                return FloatStringifiers.DOUBLE_INSTANCE;
+            }
+            return null;
         }
 
         /**
          * Returns a stringifier for any type. Never returns null.
          *
          * @param t class to stringify
          * @return stringifier
          */
         static MethodHandle forAny(Class<?> t) {
-            return STRINGIFIERS_ANY.get(t);
+            return StringifierAny.INSTANCE.get(t);
         }
     }
 
     /* ------------------------------- Common utilities ------------------------------------ */
 
< prev index next >