--- old/src/java.base/share/classes/java/util/HashMap.java 2015-01-11 12:38:51.420992127 +0100 +++ new/src/java.base/share/classes/java/util/HashMap.java 2015-01-11 12:38:51.320993871 +0100 @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.InvalidObjectException; import java.io.Serializable; +import java.lang.ref.WeakReference; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.function.BiConsumer; @@ -338,25 +339,54 @@ return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } + /** Cache of 1st encountered Class implementing Comparable */ + private static final class ClassRef extends WeakReference> { + final boolean selfComparable; + + ClassRef(Class cc, boolean selfComparable) { + super(cc); + this.selfComparable = selfComparable; + } + } + + private transient ClassRef comparableClassRef; + /** * Returns x's Class if it is of the form "class C implements * Comparable", else null. */ - static Class comparableClassFor(Object x) { + 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, cc = null; + Type[] ts, as; + ParameterizedType p; + ClassRef ccRef; + if ((c = x.getClass()) == String.class) { // bypass checks return c; + } + if ((ccRef = comparableClassRef) != null && + (cc = ccRef.get()) == c) { // cached + return ccRef.selfComparable ? c : null; + } if ((ts = c.getGenericInterfaces()) != null) { for (Type t : ts) { if ((t instanceof ParameterizedType) && ((p = (ParameterizedType) t).getRawType() == - Comparable.class) && + Comparable.class) && (as = p.getActualTypeArguments()) != null && - as.length == 1 && as[0] == c) // type arg is c + as.length == 1 && as[0] == c) { // type arg is c + if (cc == null) { + // not yet cached or already cleared + comparableClassRef = new ClassRef(c, true); + } return c; + } } } + if (cc == null) { + // not yet cached or already cleared + comparableClassRef = new ClassRef(c, false); + } } return null; } @@ -572,7 +602,7 @@ return first; if ((e = first.next) != null) { if (first instanceof TreeNode) - return ((TreeNode)first).getTreeNode(hash, key); + return ((TreeNode)first).getTreeNode(this, hash, key); do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) @@ -768,7 +798,7 @@ tl = p; } while ((e = e.next) != null); if ((tab[index] = hd) != null) - hd.treeify(tab); + hd.treeify(this, tab); } } @@ -820,7 +850,7 @@ node = p; else if ((e = p.next) != null) { if (p instanceof TreeNode) - node = ((TreeNode)p).getTreeNode(hash, key); + node = ((TreeNode)p).getTreeNode(this, hash, key); else { do { if (e.hash == hash && @@ -1097,7 +1127,7 @@ n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode) - old = (t = (TreeNode)first).getTreeNode(hash, key); + old = (t = (TreeNode)first).getTreeNode(this, hash, key); else { Node e = first; K k; do { @@ -1171,7 +1201,7 @@ n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode) - old = (t = (TreeNode)first).getTreeNode(hash, key); + old = (t = (TreeNode)first).getTreeNode(this, hash, key); else { Node e = first; K k; do { @@ -1226,7 +1256,7 @@ n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode) - old = (t = (TreeNode)first).getTreeNode(hash, key); + old = (t = (TreeNode)first).getTreeNode(this, hash, key); else { Node e = first; K k; do { @@ -1839,7 +1869,7 @@ * The kc argument caches comparableClassFor(key) upon first use * comparing keys. */ - final TreeNode find(int h, Object k, Class kc) { + final TreeNode find(HashMap map, int h, Object k, Class kc) { TreeNode p = this; do { int ph, dir; K pk; @@ -1855,10 +1885,10 @@ else if (pr == null) p = pl; else if ((kc != null || - (kc = comparableClassFor(k)) != null) && + (kc = map.comparableClassFor(k)) != null) && (dir = compareComparables(kc, k, pk)) != 0) p = (dir < 0) ? pl : pr; - else if ((q = pr.find(h, k, kc)) != null) + else if ((q = pr.find(map, h, k, kc)) != null) return q; else p = pl; @@ -1869,8 +1899,8 @@ /** * Calls find for root node. */ - final TreeNode getTreeNode(int h, Object k) { - return ((parent != null) ? root() : this).find(h, k, null); + final TreeNode getTreeNode(HashMap map, int h, Object k) { + return ((parent != null) ? root() : this).find(map, h, k, null); } /** @@ -1894,7 +1924,7 @@ * Forms tree of the nodes linked from this node. * @return root of tree */ - final void treeify(Node[] tab) { + final void treeify(HashMap map, Node[] tab) { TreeNode root = null; for (TreeNode x = this, next; x != null; x = next) { next = (TreeNode)x.next; @@ -1916,7 +1946,7 @@ else if (ph < h) dir = 1; else if ((kc == null && - (kc = comparableClassFor(k)) == null) || + (kc = map.comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) dir = tieBreakOrder(k, pk); @@ -1970,15 +2000,15 @@ else if ((pk = p.key) == k || (k != null && k.equals(pk))) return p; else if ((kc == null && - (kc = comparableClassFor(k)) == null) || + (kc = map.comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) { if (!searched) { TreeNode q, ch; searched = true; if (((ch = p.left) != null && - (q = ch.find(h, k, kc)) != null) || + (q = ch.find(map, h, k, kc)) != null) || ((ch = p.right) != null && - (q = ch.find(h, k, kc)) != null)) + (q = ch.find(map, h, k, kc)) != null)) return q; } dir = tieBreakOrder(k, pk); @@ -2150,7 +2180,7 @@ else { tab[index] = loHead; if (hiHead != null) // (else is already treeified) - loHead.treeify(tab); + loHead.treeify(map, tab); } } if (hiHead != null) { @@ -2159,7 +2189,7 @@ else { tab[index + bit] = hiHead; if (loHead != null) - hiHead.treeify(tab); + hiHead.treeify(map, tab); } } }