Index: modules/luni/src/main/java/java/util/LinkedHashMap.java =================================================================== --- modules/luni/src/main/java/java/util/LinkedHashMap.java (revision 507871) +++ modules/luni/src/main/java/java/util/LinkedHashMap.java (working copy) @@ -139,7 +139,7 @@ canRemove = false; associatedMap.modCount++; - int index = associatedMap.getModuloHash(lastEntry.key); + int index = (lastEntry.key == null)? 0 : (lastEntry.key.hashCode() & 0x7FFFFFFF) % associatedMap.elementData.length; LinkedHashMapEntry m = (LinkedHashMapEntry) associatedMap.elementData[index]; if (m == lastEntry) { associatedMap.elementData[index] = lastEntry.next; @@ -201,6 +201,13 @@ chainBackward = null; } + LinkedHashMapEntry(K theKey, int hash) { + super(theKey, hash); + chainForward = null; + chainBackward = null; + } + + @Override @SuppressWarnings("unchecked") public Object clone() { @@ -236,7 +243,14 @@ */ @Override public V get(Object key) { - LinkedHashMapEntry m = (LinkedHashMapEntry) getEntry(key); + LinkedHashMapEntry m; + if (key == null) { + m = (LinkedHashMapEntry)findNullKeyEntry(); + } else { + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % elementData.length; + m = (LinkedHashMapEntry)findNonNullKeyEntry(key, index, hash); + } if (m == null) { return null; } @@ -269,6 +283,14 @@ return m; } + Entry createHashedEntry(K key, int index, int hash) { + LinkedHashMapEntry m = new LinkedHashMapEntry(key, hash); + m.next = elementData[index]; + elementData[index] = m; + linkEntry(m); + return m; + } + /** * Set the mapped value for the given key to the given value. * @@ -281,23 +303,36 @@ */ @Override public V put(K key, V value) { - int index = getModuloHash(key); - LinkedHashMapEntry m = (LinkedHashMapEntry) findEntry(key, index); - - if (m == null) { - modCount++; - // Check if we need to remove the oldest entry - // The check includes accessOrder since an accessOrder LinkedHashMap - // does not record - // the oldest member in 'head'. - if (++elementCount > threshold) { - rehash(); - index = key == null ? 0 : (key.hashCode() & 0x7FFFFFFF) - % elementData.length; + LinkedHashMapEntry m; + if (key == null) { + m = (LinkedHashMapEntry)findNullKeyEntry(); + if (m == null) { + modCount++; + // Check if we need to remove the oldest entry + // The check includes accessOrder since an accessOrder LinkedHashMap + // does not record + // the oldest member in 'head'. + if (++elementCount > threshold) { + rehash(); + } + m = (LinkedHashMapEntry) createHashedEntry(key, 0, 0); + } else { + linkEntry(m); } - m = (LinkedHashMapEntry) createEntry(key, index, null); } else { - linkEntry(m); + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % elementData.length; + m = (LinkedHashMapEntry)findNonNullKeyEntry(key, index, hash); + if (m == null) { + modCount++; + if (++elementCount > threshold) { + rehash(); + index = (hash & 0x7FFFFFFF) % elementData.length; + } + m = (LinkedHashMapEntry) createHashedEntry(key, index, hash); + } else { + linkEntry(m); + } } V result = m.value; Index: modules/luni/src/main/java/java/util/HashMap.java =================================================================== --- modules/luni/src/main/java/java/util/HashMap.java (revision 507871) +++ modules/luni/src/main/java/java/util/HashMap.java (working copy) @@ -47,6 +47,11 @@ Entry next; + Entry(K theKey, int hash) { + super(theKey, null); + this.origKeyHash = hash; + } + Entry(K theKey, V theValue) { super(theKey, theValue); origKeyHash = (theKey == null ? 0 : theKey.hashCode()); @@ -180,8 +185,15 @@ @Override public boolean contains(Object object) { if (object instanceof Map.Entry) { - Entry entry = associatedMap - .getEntry(((Map.Entry) object).getKey()); + Object key = ((Map.Entry) object).getKey(); + Entry entry; + if (key == null) { + entry = associatedMap.findNullKeyEntry(); + } else { + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % associatedMap.elementData.length; + entry = associatedMap.findNonNullKeyEntry(key, index, hash); + } return object.equals(entry); } return false; @@ -328,29 +340,15 @@ */ @Override public boolean containsKey(Object key) { - return getEntry(key) != null; - } - - /** - * Tests two keys for equality. This method just calls key.equals but can be - * overridden. - * - * @param k1 - * first key to compare - * @param k2 - * second key to compare - * @return true if the keys are considered equal - */ - boolean keysEqual(Object k1, Entry entry) { - int k1Hash = k1 == null ? 0 : k1.hashCode(); - if (k1Hash != entry.origKeyHash) { - return false; + Entry m; + if (key == null) { + m = findNullKeyEntry(); + } else { + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % elementData.length; + m = findNonNullKeyEntry(key, index, hash); } - if (k1 == null && entry.key == null) { - return true; - } - assert k1 != null; - return k1.equals(entry.key); + return m != null; } /** @@ -408,37 +406,32 @@ */ @Override public V get(Object key) { - Entry m = getEntry(key); + Entry m; + if (key == null) { + m = findNullKeyEntry(); + } else { + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % elementData.length; + m = findNonNullKeyEntry(key, index, hash); + } if (m != null) { return m.value; } return null; } - Entry getEntry(Object key) { - int index = getModuloHash(key); - return findEntry(key, index); - } - - int getModuloHash(Object key) { - if (key == null) { - return 0; + final Entry findNonNullKeyEntry(Object key, int index, int keyHash) { + Entry m = elementData[index]; + while (m != null && (m.origKeyHash != keyHash || !key.equals(m.key))) { + m = m.next; } - return (key.hashCode() & 0x7FFFFFFF) % elementData.length; + return m; } - - Entry findEntry(Object key, int index) { - Entry m; - m = elementData[index]; - if (key != null) { - while (m != null && !keysEqual(key, m)) { - m = m.next; - } - } else { - while (m != null && m.key != null) { - m = m.next; - } - } + + final Entry findNullKeyEntry() { + Entry m = elementData[0]; + while (m != null && m.key != null) + m = m.next; return m; } @@ -482,11 +475,8 @@ @Override public boolean remove(Object key) { - if (containsKey(key)) { - HashMap.this.remove(key); - return true; - } - return false; + Entry entry = HashMap.this.removeEntry(key); + return entry != null; } @Override @@ -519,18 +509,28 @@ } private V putImpl(K key, V value) { - int index = getModuloHash(key); - Entry entry = findEntry(key, index); - - if (entry == null) { - modCount++; - if (++elementCount > threshold) { - rehash(); - index = key == null ? 0 : (key.hashCode() & 0x7FFFFFFF) - % elementData.length; + Entry entry; + if(key == null) { + entry = findNullKeyEntry(); + if (entry == null) { + modCount++; + if (++elementCount > threshold) { + rehash(); + } + entry = createHashedEntry(key, 0, 0); } - createEntry(key, index, value); - return null; + } else { + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % elementData.length; + entry = findNonNullKeyEntry(key, index, hash); + if (entry == null) { + modCount++; + if (++elementCount > threshold) { + rehash(); + index = (hash & 0x7FFFFFFF) % elementData.length; + } + entry = createHashedEntry(key, index, hash); + } } V result = entry.value; @@ -545,6 +545,13 @@ return entry; } + Entry createHashedEntry(K key, int index, int hash) { + Entry entry = new Entry(key,hash); + entry.next = elementData[index]; + elementData[index] = entry; + return entry; + } + /** * Copies all the mappings in the given map to this map. These mappings will * replace all mappings that this map had for any of the keys currently in @@ -579,9 +586,7 @@ for (int i = 0; i < elementData.length; i++) { Entry entry = elementData[i]; while (entry != null) { - Object key = entry.key; - int index = key == null ? 0 : (key.hashCode() & 0x7FFFFFFF) - % length; + int index = (entry.origKeyHash & 0x7FFFFFFF) % length; Entry next = entry.next; entry.next = newData[index]; newData[index] = entry; @@ -618,9 +623,10 @@ Entry entry; Entry last = null; if (key != null) { - index = (key.hashCode() & 0x7FFFFFFF) % elementData.length; + int hash = key.hashCode(); + index = (hash & 0x7FFFFFFF) % elementData.length; entry = elementData[index]; - while (entry != null && !keysEqual(key, entry)) { + while (entry != null && !(entry.origKeyHash == hash && key.equals(entry.key))) { last = entry; entry = entry.next; }