< 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


1612                     default:
1613                         throw new StringConcatException("Unhandled tag: " + el.getTag());
1614                 }
1615             }
1616 
1617             // Insert initial length and coder value here.
1618             // The method handle shape here is (<args>).
1619             mh = MethodHandles.insertArguments(mh, 0, initialLengthCoder);
1620 
1621             // Apply filters, converting the arguments:
1622             if (filters != null) {
1623                 mh = MethodHandles.filterArguments(mh, 0, filters);
1624             }
1625 
1626             return mh;
1627         }
1628 
1629         @ForceInline
1630         private static byte[] newArray(long indexCoder) {
1631             byte coder = (byte)(indexCoder >> 32);
1632             int index = ((int)indexCoder & 0x7FFFFFFF);
1633             return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder);
1634         }
1635 
1636         private static MethodHandle prepender(Class<?> cl) {
1637             return PREPENDERS.computeIfAbsent(cl, PREPEND);
1638         }
1639 
1640         private static MethodHandle mixer(Class<?> cl) {
1641             return MIXERS.computeIfAbsent(cl, MIX);
1642         }
1643 
1644         // This one is deliberately non-lambdified to optimize startup time:
1645         private static final Function<Class<?>, MethodHandle> PREPEND = new Function<Class<?>, MethodHandle>() {
1646             @Override
1647             public MethodHandle apply(Class<?> c) {
1648                 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", long.class, long.class, byte[].class,
1649                         Wrapper.asPrimitiveType(c));
1650             }
1651         };
1652 


1675                 throw new AssertionError(e);
1676             }
1677 
1678             PREPENDERS = new ConcurrentHashMap<>();
1679             MIXERS = new ConcurrentHashMap<>();
1680 
1681             NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, long.class);
1682             NEW_ARRAY  = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, long.class);
1683         }
1684     }
1685 
1686     /**
1687      * Public gateways to public "stringify" methods. These methods have the form String apply(T obj), and normally
1688      * delegate to {@code String.valueOf}, depending on argument's type.
1689      */
1690     private static final class Stringifiers {
1691         private Stringifiers() {
1692             // no instantiation
1693         }
1694 
1695         private static class StringifierMost extends ClassValue<MethodHandle> {
1696             @Override
1697             protected MethodHandle computeValue(Class<?> cl) {
1698                 if (cl == String.class) {
1699                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
1700                 } else if (cl == float.class) {
1701                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, float.class);
1702                 } else if (cl == double.class) {
1703                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, double.class);
1704                 } else if (!cl.isPrimitive()) {
1705                     MethodHandle mhObject = lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
1706 
1707                     // We need the additional conversion here, because String.valueOf(Object) may return null.
1708                     // String conversion rules in Java state we need to produce "null" String in this case.
1709                     // It can be easily done with applying valueOf the second time.
1710                     return MethodHandles.filterReturnValue(mhObject,
1711                             mhObject.asType(MethodType.methodType(String.class, String.class)));
1712                 }
1713 
1714                 return null;




1715             }







1716         }
1717 
1718         private static class StringifierAny extends ClassValue<MethodHandle> {



1719             @Override
1720             protected MethodHandle computeValue(Class<?> cl) {
1721                 if (cl == byte.class || cl == short.class || cl == int.class) {
1722                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, int.class);
1723                 } else if (cl == boolean.class) {
1724                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, boolean.class);
1725                 } else if (cl == char.class) {
1726                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, char.class);
1727                 } else if (cl == long.class) {
1728                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, long.class);
1729                 } else {
1730                     MethodHandle mh = STRINGIFIERS_MOST.get(cl);
1731                     if (mh != null) {
1732                         return mh;
1733                     } else {
1734                         throw new IllegalStateException("Unknown class: " + cl);
1735                     }
1736                 }
1737             }
1738         }
1739 
1740         private static final ClassValue<MethodHandle> STRINGIFIERS_MOST = new StringifierMost();
1741         private static final ClassValue<MethodHandle> STRINGIFIERS_ANY = new StringifierAny();
1742 
1743         /**
1744          * Returns a stringifier for references and floats/doubles only.
1745          * Always returns null for other primitives.
1746          *
1747          * @param t class to stringify
1748          * @return stringifier; null, if not available
1749          */
1750         static MethodHandle forMost(Class<?> t) {
1751             return STRINGIFIERS_MOST.get(t);







1752         }
1753 
1754         /**
1755          * Returns a stringifier for any type. Never returns null.
1756          *
1757          * @param t class to stringify
1758          * @return stringifier
1759          */
1760         static MethodHandle forAny(Class<?> t) {
1761             return STRINGIFIERS_ANY.get(t);
1762         }
1763     }
1764 
1765     /* ------------------------------- Common utilities ------------------------------------ */
1766 
1767     static MethodHandle lookupStatic(Lookup lookup, Class<?> refc, String name, Class<?> rtype, Class<?>... ptypes) {
1768         try {
1769             return lookup.findStatic(refc, name, MethodType.methodType(rtype, ptypes));
1770         } catch (NoSuchMethodException | IllegalAccessException e) {
1771             throw new AssertionError(e);
1772         }
1773     }
1774 
1775     static MethodHandle lookupVirtual(Lookup lookup, Class<?> refc, String name, Class<?> rtype, Class<?>... ptypes) {
1776         try {
1777             return lookup.findVirtual(refc, name, MethodType.methodType(rtype, ptypes));
1778         } catch (NoSuchMethodException | IllegalAccessException e) {
1779             throw new AssertionError(e);
1780         }
1781     }




1612                     default:
1613                         throw new StringConcatException("Unhandled tag: " + el.getTag());
1614                 }
1615             }
1616 
1617             // Insert initial length and coder value here.
1618             // The method handle shape here is (<args>).
1619             mh = MethodHandles.insertArguments(mh, 0, initialLengthCoder);
1620 
1621             // Apply filters, converting the arguments:
1622             if (filters != null) {
1623                 mh = MethodHandles.filterArguments(mh, 0, filters);
1624             }
1625 
1626             return mh;
1627         }
1628 
1629         @ForceInline
1630         private static byte[] newArray(long indexCoder) {
1631             byte coder = (byte)(indexCoder >> 32);
1632             int index = (int)indexCoder;
1633             return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder);
1634         }
1635 
1636         private static MethodHandle prepender(Class<?> cl) {
1637             return PREPENDERS.computeIfAbsent(cl, PREPEND);
1638         }
1639 
1640         private static MethodHandle mixer(Class<?> cl) {
1641             return MIXERS.computeIfAbsent(cl, MIX);
1642         }
1643 
1644         // This one is deliberately non-lambdified to optimize startup time:
1645         private static final Function<Class<?>, MethodHandle> PREPEND = new Function<Class<?>, MethodHandle>() {
1646             @Override
1647             public MethodHandle apply(Class<?> c) {
1648                 return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", long.class, long.class, byte[].class,
1649                         Wrapper.asPrimitiveType(c));
1650             }
1651         };
1652 


1675                 throw new AssertionError(e);
1676             }
1677 
1678             PREPENDERS = new ConcurrentHashMap<>();
1679             MIXERS = new ConcurrentHashMap<>();
1680 
1681             NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, long.class);
1682             NEW_ARRAY  = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, long.class);
1683         }
1684     }
1685 
1686     /**
1687      * Public gateways to public "stringify" methods. These methods have the form String apply(T obj), and normally
1688      * delegate to {@code String.valueOf}, depending on argument's type.
1689      */
1690     private static final class Stringifiers {
1691         private Stringifiers() {
1692             // no instantiation
1693         }
1694 
1695         private static class StringStringifier {
1696 
1697             // We need some additional conversion for Objects in general, because String.valueOf(Object)
1698             // may return null. String conversion rules in Java state we need to produce "null" String
1699             // in this case, so we provide a customized version that deals with this problematic corner case.
1700             private static String valueOf(Object value) {
1701                 String s;
1702                 return (value == null || (s = value.toString()) == null) ? "null" : s;









1703             }
1704 
1705             // Could have used MethodHandles.lookup() instead of Lookup.IMPL_LOOKUP, if not for the fact
1706             // java.lang.invoke Lookups are explicitly forbidden to be retrieved using that API.
1707             private static final MethodHandle INSTANCE =
1708                     lookupStatic(Lookup.IMPL_LOOKUP, StringStringifier.class, "valueOf", String.class, Object.class);
1709 
1710         }
1711 
1712         private static class FloatStringifiers {
1713             private static final MethodHandle FLOAT_INSTANCE =
1714                     lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, float.class);
1715 
1716             private static final MethodHandle DOUBLE_INSTANCE =
1717                     lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, double.class);
1718         }
1719 
1720         private static class StringifierAny extends ClassValue<MethodHandle> {
1721 
1722             private static final ClassValue<MethodHandle> INSTANCE = new StringifierAny();
1723 
1724             @Override
1725             protected MethodHandle computeValue(Class<?> cl) {
1726                 if (cl == byte.class || cl == short.class || cl == int.class) {
1727                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, int.class);
1728                 } else if (cl == boolean.class) {
1729                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, boolean.class);
1730                 } else if (cl == char.class) {
1731                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, char.class);
1732                 } else if (cl == long.class) {
1733                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, long.class);
1734                 } else {
1735                     MethodHandle mh = forMost(cl);
1736                     if (mh != null) {
1737                         return mh;
1738                     } else {
1739                         throw new IllegalStateException("Unknown class: " + cl);
1740                     }
1741                 }
1742             }
1743         }
1744 



1745         /**
1746          * Returns a stringifier for references and floats/doubles only.
1747          * Always returns null for other primitives.
1748          *
1749          * @param t class to stringify
1750          * @return stringifier; null, if not available
1751          */
1752         static MethodHandle forMost(Class<?> t) {
1753             if (!t.isPrimitive()) {
1754                 return StringStringifier.INSTANCE;
1755             } else if (t == float.class) {
1756                 return FloatStringifiers.FLOAT_INSTANCE;
1757             } else if (t == double.class) {
1758                 return FloatStringifiers.DOUBLE_INSTANCE;
1759             }
1760             return null;
1761         }
1762 
1763         /**
1764          * Returns a stringifier for any type. Never returns null.
1765          *
1766          * @param t class to stringify
1767          * @return stringifier
1768          */
1769         static MethodHandle forAny(Class<?> t) {
1770             return StringifierAny.INSTANCE.get(t);
1771         }
1772     }
1773 
1774     /* ------------------------------- Common utilities ------------------------------------ */
1775 
1776     static MethodHandle lookupStatic(Lookup lookup, Class<?> refc, String name, Class<?> rtype, Class<?>... ptypes) {
1777         try {
1778             return lookup.findStatic(refc, name, MethodType.methodType(rtype, ptypes));
1779         } catch (NoSuchMethodException | IllegalAccessException e) {
1780             throw new AssertionError(e);
1781         }
1782     }
1783 
1784     static MethodHandle lookupVirtual(Lookup lookup, Class<?> refc, String name, Class<?> rtype, Class<?>... ptypes) {
1785         try {
1786             return lookup.findVirtual(refc, name, MethodType.methodType(rtype, ptypes));
1787         } catch (NoSuchMethodException | IllegalAccessException e) {
1788             throw new AssertionError(e);
1789         }
1790     }


< prev index next >