# HG changeset patch # User dl # Date 1303401623 -3600 # Node ID 730ccba1467f2ba963c13b32d1a5421b3d783e93 # Parent fb042badb461091d8a98363b56554e7e40852850 7038542: Small performace regression in ConcurrentHashMap on c1 since CR 703655 Reviewed-by: chegar diff -r fb042badb461 -r 730ccba1467f jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java Thu Apr 21 14:25:46 2011 +0100 +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java Thu Apr 21 17:00:23 2011 +0100 @@ -239,7 +239,8 @@ /** * Gets the ith element of given table (if nonnull) with volatile - * read semantics. + * read semantics. Note: This is manually integrated into a few + * performance-sensitive methods to reduce call overhead. */ @SuppressWarnings("unchecked") static final HashEntry entryAt(HashEntry[] tab, int i) { @@ -389,8 +390,7 @@ else node = new HashEntry(hash, key, value, first); int c = count + 1; - if (c > threshold && first != null && - tab.length < MAXIMUM_CAPACITY) + if (c > threshold && tab.length < MAXIMUM_CAPACITY) rehash(node); else setEntryAt(tab, index, node); @@ -647,7 +647,11 @@ /** * Gets the jth element of given segment array (if nonnull) with - * volatile element access semantics via Unsafe. + * volatile element access semantics via Unsafe. (The null check + * can trigger harmlessly only during deserialization.) Note: + * because each element of segments array is set only once (using + * fully ordered writes), some performance-sensitive methods rely + * on this method only as a recheck upon null reads. */ @SuppressWarnings("unchecked") static final Segment segmentAt(Segment[] ss, int j) { @@ -913,12 +917,19 @@ * @throws NullPointerException if the specified key is null */ public V get(Object key) { - int hash = hash(key.hashCode()); - for (HashEntry e = entryForHash(segmentForHash(hash), hash); - e != null; e = e.next) { - K k; - if ((k = e.key) == key || (e.hash == hash && key.equals(k))) - return e.value; + Segment s; // manually integrate access methods to reduce overhead + HashEntry[] tab; + int h = hash(key.hashCode()); + long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; + if ((s = (Segment)UNSAFE.getObjectVolatile(segments, u)) != null && + (tab = s.table) != null) { + for (HashEntry e = (HashEntry) UNSAFE.getObjectVolatile + (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE); + e != null; e = e.next) { + K k; + if ((k = e.key) == key || (e.hash == h && key.equals(k))) + return e.value; + } } return null; } @@ -932,13 +943,21 @@ * equals method; false otherwise. * @throws NullPointerException if the specified key is null */ + @SuppressWarnings("unchecked") public boolean containsKey(Object key) { - int hash = hash(key.hashCode()); - for (HashEntry e = entryForHash(segmentForHash(hash), hash); - e != null; e = e.next) { - K k; - if ((k = e.key) == key || (e.hash == hash && key.equals(k))) - return true; + Segment s; // same as get() except no need for volatile value read + HashEntry[] tab; + int h = hash(key.hashCode()); + long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; + if ((s = (Segment)UNSAFE.getObjectVolatile(segments, u)) != null && + (tab = s.table) != null) { + for (HashEntry e = (HashEntry) UNSAFE.getObjectVolatile + (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE); + e != null; e = e.next) { + K k; + if ((k = e.key) == key || (e.hash == h && key.equals(k))) + return true; + } } return false; } @@ -1032,13 +1051,15 @@ * null if there was no mapping for key * @throws NullPointerException if the specified key or value is null */ + @SuppressWarnings("unchecked") public V put(K key, V value) { + Segment s; if (value == null) throw new NullPointerException(); int hash = hash(key.hashCode()); int j = (hash >>> segmentShift) & segmentMask; - Segment s = segmentAt(segments, j); - if (s == null) + if ((s = (Segment)UNSAFE.getObject // nonvolatile; recheck + (segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment s = ensureSegment(j); return s.put(key, hash, value, false); } @@ -1050,13 +1071,15 @@ * or null if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ + @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { + Segment s; if (value == null) throw new NullPointerException(); int hash = hash(key.hashCode()); int j = (hash >>> segmentShift) & segmentMask; - Segment s = segmentAt(segments, j); - if (s == null) + if ((s = (Segment)UNSAFE.getObject + (segments, (j << SSHIFT) + SBASE)) == null) s = ensureSegment(j); return s.put(key, hash, value, true); }