Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions src/java.base/share/classes/java/lang/ClassValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,16 @@ public void remove(Class<?> type) {
/// Implementation...
/// --------

/** Return the cache, if it exists, else a dummy empty cache. */
/** Return the cache, if it exists, else null. */
private static Entry<?>[] getCacheCarefully(Class<?> type) {
// racing type.classValueMap{.cacheArray} : null => new Entry[X] <=> new Entry[Y]
ClassValueMap map = type.classValueMap;
if (map == null) return EMPTY_CACHE;
if (map == null) return null;
Entry<?>[] cache = map.getCache();
return cache;
// invariant: returned value is safe to dereference and check for an Entry
}

/** Initial, one-element, empty cache used by all Class instances. Must never be filled. */
private static final Entry<?>[] EMPTY_CACHE = { null };

/**
* Slow tail of ClassValue.get to retry at nearby locations in the cache,
* or take a slow lock and check the hash table.
Expand Down Expand Up @@ -530,9 +527,9 @@ <T> void changeEntry(ClassValue<T> classValue, T value) {

/** Load the cache entry at the given (hashed) location. */
static Entry<?> loadFromCache(Entry<?>[] cache, int i) {
// non-racing cache.length : constant
// racing cache[i & (mask)] : null <=> Entry
return cache[i & (cache.length-1)];
// non-racing cache != null && cache.length : constant
// racing cache == null || cache[i & (mask)] : null <=> Entry
return cache == null ? null : cache[i & (cache.length-1)];
// invariant: returned value is null or well-constructed (ready to match)
}

Expand All @@ -544,6 +541,7 @@ static <T> Entry<T> probeHomeLocation(Entry<?>[] cache, ClassValue<T> classValue
/** Given that first probe was a collision, retry at nearby locations. */
static <T> Entry<T> probeBackupLocations(Entry<?>[] cache, ClassValue<T> classValue) {
if (PROBE_LIMIT <= 0) return null;
if (cache == null) return null;
// Probe the cache carefully, in a range of slots.
int mask = (cache.length-1);
int home = (classValue.hashCodeForCache & mask);
Expand Down Expand Up @@ -589,11 +587,11 @@ private static int entryDislocation(Entry<?>[] cache, int pos, Entry<?> e) {
/// Below this line all functions are private, and assume synchronized access.
/// --------

private void sizeCache(int length) {
private Entry<?>[] sizeCache(int length) {
assert((length & (length-1)) == 0); // must be power of 2
cacheLoad = 0;
cacheLoadLimit = (int) ((double) length * CACHE_LOAD_LIMIT / 100);
cacheArray = new Entry<?>[length];
return cacheArray = new Entry<?>[length];
}

/** Make sure the cache load stays below its limit, if possible. */
Expand All @@ -607,12 +605,14 @@ private void reduceCacheLoad() {
if (cacheLoad < cacheLoadLimit)
return; // win
Entry<?>[] oldCache = getCache();
if (oldCache.length > HASH_MASK)
if (oldCache != null && oldCache.length > HASH_MASK)
return; // lose
sizeCache(oldCache.length * 2);
for (Entry<?> e : oldCache) {
if (e != null && e.isLive()) {
addToCache(e);
sizeCache(oldCache == null ? INITIAL_ENTRIES : oldCache.length * 2);
if (oldCache != null) {
for (Entry<?> e : oldCache) {
if (e != null && e.isLive()) {
addToCache(e);
}
}
}
}
Expand All @@ -622,6 +622,7 @@ private void reduceCacheLoad() {
*/
private void removeStaleEntries(Entry<?>[] cache, int begin, int count) {
if (PROBE_LIMIT <= 0) return;
if (cache == null) return;
int mask = (cache.length-1);
int removed = 0;
for (int i = begin; i < begin + count; i++) {
Expand Down Expand Up @@ -702,9 +703,13 @@ private <T> void addToCache(Entry<T> e) {

/** Add the given entry to the cache, in its home location. */
private <T> void addToCache(ClassValue<T> classValue, Entry<T> e) {
// assert Thread.holdsLock(this);
if (PROBE_LIMIT <= 0) return; // do not fill cache
// Add e to the cache.
Entry<?>[] cache = getCache();
if (cache == null) {
cache = sizeCache(INITIAL_ENTRIES);
}
int mask = (cache.length-1);
int home = classValue.hashCodeForCache & mask;
Entry<?> e2 = placeInCache(cache, home, e, false);
Expand Down