--- old/src/share/classes/java/util/IdentityHashMap.java 2014-07-08 13:13:27.759540024 +0200 +++ new/src/share/classes/java/util/IdentityHashMap.java 2014-07-08 13:13:27.664541727 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ * maximum size and the number of buckets is unspecified. * *

If the size of the map (the number of key-value mappings) sufficiently - * exceeds the expected maximum size, the number of buckets is increased + * exceeds the expected maximum size, the number of buckets is increased. * Increasing the number of buckets ("rehashing") may be fairly expensive, so * it pays to create identity hash maps with a sufficiently large expected * maximum size. On the other hand, iteration over collection views requires @@ -160,6 +160,10 @@ * The maximum capacity, used if a higher value is implicitly specified * by either of the constructors with arguments. * MUST be a power of two <= 1<<29. + * + * In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items + * because it has to have at least one slot with the key == null + * in order to avoid infinite loops in get(), put(), remove() */ private static final int MAXIMUM_CAPACITY = 1 << 29; @@ -181,11 +185,6 @@ transient int modCount; /** - * The next size value at which to resize (capacity * load factor). - */ - private transient int threshold; - - /** * Value representing null keys inside tables. */ static final Object NULL_KEY = new Object(); @@ -229,27 +228,19 @@ } /** - * Returns the appropriate capacity for the specified expected maximum - * size. Returns the smallest power of two between MINIMUM_CAPACITY - * and MAXIMUM_CAPACITY, inclusive, that is greater than - * (3 * expectedMaxSize)/2, if such a number exists. Otherwise - * returns MAXIMUM_CAPACITY. If (3 * expectedMaxSize)/2 is negative, it - * is assumed that overflow has occurred, and MAXIMUM_CAPACITY is returned. - */ - private int capacity(int expectedMaxSize) { - // Compute min capacity for expectedMaxSize given a load factor of 2/3 - int minCapacity = (3 * expectedMaxSize)/2; - - // Compute the appropriate capacity - int result; - if (minCapacity > MAXIMUM_CAPACITY || minCapacity < 0) { - result = MAXIMUM_CAPACITY; - } else { - result = MINIMUM_CAPACITY; - while (result < minCapacity) - result <<= 1; - } - return result; + * Returns the appropriate capacity for the given expected maximum size. + * Returns the smallest power of two between MINIMUM_CAPACITY and + * MAXIMUM_CAPACITY, inclusive, that is greater than (3 * + * expectedMaxSize)/2, if such a number exists. Otherwise returns + * MAXIMUM_CAPACITY. If (3 * expectedMaxSize) is negative, it is assumed + * that overflow has occurred, and MAXIMUM_CAPACITY is returned. + */ + private static int capacity(int expectedMaxSize) { + // assert expectedMaxSize >= 0; + return + (expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY : + (expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY : + Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1)); } /** @@ -262,7 +253,6 @@ // assert initCapacity >= MINIMUM_CAPACITY; // assert initCapacity <= MAXIMUM_CAPACITY; - threshold = (initCapacity * 2)/3; table = new Object[2 * initCapacity]; } @@ -445,11 +435,20 @@ i = nextKeyIndex(i, len); } + if (size == MAXIMUM_CAPACITY - 1) + throw new IllegalStateException("Capacity exhausted."); + + if (size >= len / 3 && resize(len)) { // len == 2 * current capacity. + tab = table; + len = tab.length; + i = hash(key, len); + while (tab[i] != null) + i = nextKeyIndex(i, len); + } modCount++; tab[i] = k; tab[i + 1] = value; - if (++size >= threshold) - resize(len); // len == 2 * current capacity. + size++; return null; } @@ -458,23 +457,19 @@ * * @param newCapacity the new capacity, must be a power of two. */ - private void resize(int newCapacity) { + private boolean resize(int newCapacity) { // assert (newCapacity & -newCapacity) == newCapacity; // power of 2 int newLength = newCapacity * 2; Object[] oldTable = table; int oldLength = oldTable.length; - if (oldLength == 2*MAXIMUM_CAPACITY) { // can't expand any further - if (threshold == MAXIMUM_CAPACITY-1) - throw new IllegalStateException("Capacity exhausted."); - threshold = MAXIMUM_CAPACITY-1; // Gigantic map! - return; + if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further + return false; } if (oldLength >= newLength) - return; + return false; Object[] newTable = new Object[newLength]; - threshold = newLength / 3; for (int j = 0; j < oldLength; j += 2) { Object key = oldTable[j]; @@ -490,6 +485,7 @@ } } table = newTable; + return true; } /** @@ -504,7 +500,7 @@ int n = m.size(); if (n == 0) return; - if (n > threshold) // conservatively pre-expand + if (n > table.length / 3) // conservatively pre-expand resize(capacity(n)); for (Entry e : m.entrySet()) @@ -542,7 +538,6 @@ return null; i = nextKeyIndex(i, len); } - } /** @@ -1306,8 +1301,7 @@ // Read in size (number of Mappings) int size = s.readInt(); - // Allow for 33% growth (i.e., capacity is >= 2* size()). - init(capacity((size*4)/3)); + init(capacity(size)); // Read the keys and values, and put the mappings in the table for (int i=0; i