7038542: Small performace regression in ConcurrentHashMap on c1 since CR 703655
authordl
Thu, 21 Apr 2011 17:00:23 +0100
changeset 9507 730ccba1467f
parent 9506 fb042badb461
child 9508 310b4f6c8e61
child 9509 3348615f94d7
7038542: Small performace regression in ConcurrentHashMap on c1 since CR 703655 Reviewed-by: chegar
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 <K,V> HashEntry<K,V> entryAt(HashEntry<K,V>[] tab, int i) {
@@ -389,8 +390,7 @@
                         else
                             node = new HashEntry<K,V>(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 <K,V> Segment<K,V> segmentAt(Segment<K,V>[] 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<K,V> 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<K,V> s; // manually integrate access methods to reduce overhead
+        HashEntry<K,V>[] tab;
+        int h = hash(key.hashCode());
+        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
+        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
+            (tab = s.table) != null) {
+            for (HashEntry<K,V> e = (HashEntry<K,V>) 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 @@
      *         <tt>equals</tt> method; <tt>false</tt> otherwise.
      * @throws NullPointerException if the specified key is null
      */
+    @SuppressWarnings("unchecked")
     public boolean containsKey(Object key) {
-        int hash = hash(key.hashCode());
-        for (HashEntry<K,V> 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<K,V> s; // same as get() except no need for volatile value read
+        HashEntry<K,V>[] tab;
+        int h = hash(key.hashCode());
+        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
+        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
+            (tab = s.table) != null) {
+            for (HashEntry<K,V> e = (HashEntry<K,V>) 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 @@
      *         <tt>null</tt> if there was no mapping for <tt>key</tt>
      * @throws NullPointerException if the specified key or value is null
      */
+    @SuppressWarnings("unchecked")
     public V put(K key, V value) {
+        Segment<K,V> s;
         if (value == null)
             throw new NullPointerException();
         int hash = hash(key.hashCode());
         int j = (hash >>> segmentShift) & segmentMask;
-        Segment<K,V> s = segmentAt(segments, j);
-        if (s == null)
+        if ((s = (Segment<K,V>)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 <tt>null</tt> 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<K,V> s;
         if (value == null)
             throw new NullPointerException();
         int hash = hash(key.hashCode());
         int j = (hash >>> segmentShift) & segmentMask;
-        Segment<K,V> s = segmentAt(segments, j);
-        if (s == null)
+        if ((s = (Segment<K,V>)UNSAFE.getObject
+             (segments, (j << SSHIFT) + SBASE)) == null)
             s = ensureSegment(j);
         return s.put(key, hash, value, true);
     }