--- old/src/java.base/share/classes/java/lang/Class.java 2015-01-10 13:43:09.635162120 +0100 +++ new/src/java.base/share/classes/java/lang/Class.java 2015-01-10 13:43:09.536164093 +0100 @@ -69,6 +69,8 @@ import sun.security.util.SecurityConstants; import java.lang.annotation.Annotation; import java.lang.reflect.Proxy; +import java.util.function.Function; + import sun.reflect.annotation.*; import sun.reflect.misc.ReflectUtil; @@ -2562,6 +2564,27 @@ return (genericInfo != ClassRepository.NONE) ? genericInfo : null; } + /** + * If this Class represents a generic class or interface, then the result of + * applying given function to this Class object is returned, otherwise null. + * The result is cached in per-Class map using identity of given key. + * In case of races, the function may be invoked multiple times for the same + * key, therefore it should be idempotent. + * + * @param key the non-null key who's identity is used for caching of the result + * @param function the function applied to this Class to compute the result + * @param the type of result + * @return the cached result of applying given function to this Class or null + * @throws java.lang.NullPointerException if given key or function is null + */ + D getGenericDerivative(Object key, Function, ? extends D> function) { + if (key == null || function == null) throw new NullPointerException(); + ClassRepository genericInfo = getGenericInfo(); + return (genericInfo == null) + ? null + : genericInfo.getDerivative(this, key, function); + } + // Annotations handling native byte[] getRawAnnotations(); // Since 1.8 --- old/src/java.base/share/classes/java/lang/System.java 2015-01-10 13:43:09.907156699 +0100 +++ new/src/java.base/share/classes/java/lang/System.java 2015-01-10 13:43:09.814158553 +0100 @@ -30,13 +30,13 @@ import java.security.AccessControlContext; import java.util.Properties; import java.util.PropertyPermission; -import java.util.StringTokenizer; import java.util.Map; import java.security.AccessController; import java.security.PrivilegedAction; -import java.security.AllPermission; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; +import java.util.function.Function; + import sun.nio.ch.Interruptible; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; @@ -1240,6 +1240,10 @@ E[] getEnumConstantsShared(Class klass) { return klass.getEnumConstantsShared(); } + public D getGenericDerivative(Class clazz, Object key, + Function, ? extends D> function) { + return clazz.getGenericDerivative(key, function); + } public void blockedOn(Thread t, Interruptible b) { t.blockedOn(b); } --- old/src/java.base/share/classes/java/util/HashMap.java 2015-01-10 13:43:10.228150302 +0100 +++ new/src/java.base/share/classes/java/util/HashMap.java 2015-01-10 13:43:10.107152713 +0100 @@ -25,6 +25,9 @@ package java.util; +import sun.misc.JavaLangAccess; +import sun.misc.SharedSecrets; + import java.io.IOException; import java.io.InvalidObjectException; import java.io.Serializable; @@ -339,23 +342,44 @@ } /** + * Function returning TRUE for given Class when it is safe to compare + * instances of it among themselves. + */ + private static final Function, Boolean> isSelfComparableClass = + new Function, Boolean>() { + @Override + public Boolean apply(Class c) { + Type[] ts, as; ParameterizedType p; + if ((ts = c.getGenericInterfaces()) != null) { + for (Type t : ts) { + if ((t instanceof ParameterizedType) && + ((p = (ParameterizedType) t).getRawType() == + Comparable.class) && + (as = p.getActualTypeArguments()) != null && + as.length == 1 && as[0] == c) // type arg is c + return Boolean.TRUE; + } + } + return Boolean.FALSE; + } + }; + + /** * Returns x's Class if it is of the form "class C implements * Comparable", else null. */ static Class comparableClassFor(Object x) { if (x instanceof Comparable) { - Class c; Type[] ts, as; ParameterizedType p; - if ((c = x.getClass()) == String.class) // bypass checks + Class c; + if ((c = x.getClass()) == String.class) { // bypass checks + return c; + } + JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + Boolean scc = (jla != null) + ? jla.getGenericDerivative(c, isSelfComparableClass, isSelfComparableClass) + : isSelfComparableClass.apply(c); // in case very early in boot-up sequence + if (scc != null && scc) { return c; - if ((ts = c.getGenericInterfaces()) != null) { - for (Type t : ts) { - if ((t instanceof ParameterizedType) && - ((p = (ParameterizedType) t).getRawType() == - Comparable.class) && - (as = p.getActualTypeArguments()) != null && - as.length == 1 && as[0] == c) // type arg is c - return c; - } } } return null; --- old/src/java.base/share/classes/sun/misc/JavaLangAccess.java 2015-01-10 13:43:10.492145041 +0100 +++ new/src/java.base/share/classes/sun/misc/JavaLangAccess.java 2015-01-10 13:43:10.397146934 +0100 @@ -29,6 +29,7 @@ import java.lang.reflect.Executable; import java.security.AccessControlContext; import java.util.Map; +import java.util.function.Function; import sun.reflect.ConstantPool; import sun.reflect.annotation.AnnotationType; @@ -80,6 +81,14 @@ */ > E[] getEnumConstantsShared(Class klass); + /** + * If given Class represents a generic class or interface, then the result of + * applying given function to the Class object is returned, otherwise null. + * The result is cached in per-Class map using identity of given key. + */ + D getGenericDerivative(Class clazz, Object key, + Function, ? extends D> function); + /** Set thread's blocker field. */ void blockedOn(Thread t, Interruptible b); --- old/src/java.base/share/classes/sun/reflect/generics/repository/ClassRepository.java 2015-01-10 13:43:10.748139938 +0100 +++ new/src/java.base/share/classes/sun/reflect/generics/repository/ClassRepository.java 2015-01-10 13:43:10.652141852 +0100 @@ -26,6 +26,10 @@ package sun.reflect.generics.repository; import java.lang.reflect.Type; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.function.Function; + import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.tree.ClassSignature; import sun.reflect.generics.tree.TypeTree; @@ -98,6 +102,30 @@ return value.clone(); } + private volatile Map derivatives; + private static final Object nullDerivative = new Object(); + + public D getDerivative(Class clazz, Object key, + Function, ? extends D> function) { + Map dm = derivatives; + Object d = (dm == null) ? null : dm.get(key); + if (d == null) { + d = function.apply(clazz); + if (d == null) d = nullDerivative; + // re-read derivatives reference to minimize the chance of + // loosing concurrent updates... + dm = derivatives; + Map newDm = new IdentityHashMap<>( + (dm == null) ? 1 : dm.size() + 1); + newDm.put(key, d); + if (dm != null) newDm.putAll(dm); + derivatives = newDm; + } + @SuppressWarnings("unchecked") + D derivative = (d == nullDerivative) ? null : (D) d; + return derivative; + } + private Type computeSuperclass() { Reifier r = getReifier(); // obtain visitor // Extract superclass subtree from AST and reify