Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/lang/ClassValue.java
38829 views
/*1* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.lang;2627import java.lang.ClassValue.ClassValueMap;28import java.util.WeakHashMap;29import java.lang.ref.WeakReference;30import java.util.concurrent.atomic.AtomicInteger;3132import sun.misc.Unsafe;3334import static java.lang.ClassValue.ClassValueMap.probeHomeLocation;35import static java.lang.ClassValue.ClassValueMap.probeBackupLocations;3637/**38* Lazily associate a computed value with (potentially) every type.39* For example, if a dynamic language needs to construct a message dispatch40* table for each class encountered at a message send call site,41* it can use a {@code ClassValue} to cache information needed to42* perform the message send quickly, for each class encountered.43* @author John Rose, JSR 292 EG44* @since 1.745*/46public abstract class ClassValue<T> {47/**48* Sole constructor. (For invocation by subclass constructors, typically49* implicit.)50*/51protected ClassValue() {52}5354/**55* Computes the given class's derived value for this {@code ClassValue}.56* <p>57* This method will be invoked within the first thread that accesses58* the value with the {@link #get get} method.59* <p>60* Normally, this method is invoked at most once per class,61* but it may be invoked again if there has been a call to62* {@link #remove remove}.63* <p>64* If this method throws an exception, the corresponding call to {@code get}65* will terminate abnormally with that exception, and no class value will be recorded.66*67* @param type the type whose class value must be computed68* @return the newly computed value associated with this {@code ClassValue}, for the given class or interface69* @see #get70* @see #remove71*/72protected abstract T computeValue(Class<?> type);7374/**75* Returns the value for the given class.76* If no value has yet been computed, it is obtained by77* an invocation of the {@link #computeValue computeValue} method.78* <p>79* The actual installation of the value on the class80* is performed atomically.81* At that point, if several racing threads have82* computed values, one is chosen, and returned to83* all the racing threads.84* <p>85* The {@code type} parameter is typically a class, but it may be any type,86* such as an interface, a primitive type (like {@code int.class}), or {@code void.class}.87* <p>88* In the absence of {@code remove} calls, a class value has a simple89* state diagram: uninitialized and initialized.90* When {@code remove} calls are made,91* the rules for value observation are more complex.92* See the documentation for {@link #remove remove} for more information.93*94* @param type the type whose class value must be computed or retrieved95* @return the current value associated with this {@code ClassValue}, for the given class or interface96* @throws NullPointerException if the argument is null97* @see #remove98* @see #computeValue99*/100public T get(Class<?> type) {101// non-racing this.hashCodeForCache : final int102Entry<?>[] cache;103Entry<T> e = probeHomeLocation(cache = getCacheCarefully(type), this);104// racing e : current value <=> stale value from current cache or from stale cache105// invariant: e is null or an Entry with readable Entry.version and Entry.value106if (match(e))107// invariant: No false positive matches. False negatives are OK if rare.108// The key fact that makes this work: if this.version == e.version,109// then this thread has a right to observe (final) e.value.110return e.value();111// The fast path can fail for any of these reasons:112// 1. no entry has been computed yet113// 2. hash code collision (before or after reduction mod cache.length)114// 3. an entry has been removed (either on this type or another)115// 4. the GC has somehow managed to delete e.version and clear the reference116return getFromBackup(cache, type);117}118119/**120* Removes the associated value for the given class.121* If this value is subsequently {@linkplain #get read} for the same class,122* its value will be reinitialized by invoking its {@link #computeValue computeValue} method.123* This may result in an additional invocation of the124* {@code computeValue} method for the given class.125* <p>126* In order to explain the interaction between {@code get} and {@code remove} calls,127* we must model the state transitions of a class value to take into account128* the alternation between uninitialized and initialized states.129* To do this, number these states sequentially from zero, and note that130* uninitialized (or removed) states are numbered with even numbers,131* while initialized (or re-initialized) states have odd numbers.132* <p>133* When a thread {@code T} removes a class value in state {@code 2N},134* nothing happens, since the class value is already uninitialized.135* Otherwise, the state is advanced atomically to {@code 2N+1}.136* <p>137* When a thread {@code T} queries a class value in state {@code 2N},138* the thread first attempts to initialize the class value to state {@code 2N+1}139* by invoking {@code computeValue} and installing the resulting value.140* <p>141* When {@code T} attempts to install the newly computed value,142* if the state is still at {@code 2N}, the class value will be initialized143* with the computed value, advancing it to state {@code 2N+1}.144* <p>145* Otherwise, whether the new state is even or odd,146* {@code T} will discard the newly computed value147* and retry the {@code get} operation.148* <p>149* Discarding and retrying is an important proviso,150* since otherwise {@code T} could potentially install151* a disastrously stale value. For example:152* <ul>153* <li>{@code T} calls {@code CV.get(C)} and sees state {@code 2N}154* <li>{@code T} quickly computes a time-dependent value {@code V0} and gets ready to install it155* <li>{@code T} is hit by an unlucky paging or scheduling event, and goes to sleep for a long time156* <li>...meanwhile, {@code T2} also calls {@code CV.get(C)} and sees state {@code 2N}157* <li>{@code T2} quickly computes a similar time-dependent value {@code V1} and installs it on {@code CV.get(C)}158* <li>{@code T2} (or a third thread) then calls {@code CV.remove(C)}, undoing {@code T2}'s work159* <li> the previous actions of {@code T2} are repeated several times160* <li> also, the relevant computed values change over time: {@code V1}, {@code V2}, ...161* <li>...meanwhile, {@code T} wakes up and attempts to install {@code V0}; <em>this must fail</em>162* </ul>163* We can assume in the above scenario that {@code CV.computeValue} uses locks to properly164* observe the time-dependent states as it computes {@code V1}, etc.165* This does not remove the threat of a stale value, since there is a window of time166* between the return of {@code computeValue} in {@code T} and the installation167* of the the new value. No user synchronization is possible during this time.168*169* @param type the type whose class value must be removed170* @throws NullPointerException if the argument is null171*/172public void remove(Class<?> type) {173ClassValueMap map = getMap(type);174map.removeEntry(this);175}176177// Possible functionality for JSR 292 MR 1178/*public*/ void put(Class<?> type, T value) {179ClassValueMap map = getMap(type);180map.changeEntry(this, value);181}182183/// --------184/// Implementation...185/// --------186187/** Return the cache, if it exists, else a dummy empty cache. */188private static Entry<?>[] getCacheCarefully(Class<?> type) {189// racing type.classValueMap{.cacheArray} : null => new Entry[X] <=> new Entry[Y]190ClassValueMap map = type.classValueMap;191if (map == null) return EMPTY_CACHE;192Entry<?>[] cache = map.getCache();193return cache;194// invariant: returned value is safe to dereference and check for an Entry195}196197/** Initial, one-element, empty cache used by all Class instances. Must never be filled. */198private static final Entry<?>[] EMPTY_CACHE = { null };199200/**201* Slow tail of ClassValue.get to retry at nearby locations in the cache,202* or take a slow lock and check the hash table.203* Called only if the first probe was empty or a collision.204* This is a separate method, so compilers can process it independently.205*/206private T getFromBackup(Entry<?>[] cache, Class<?> type) {207Entry<T> e = probeBackupLocations(cache, this);208if (e != null)209return e.value();210return getFromHashMap(type);211}212213// Hack to suppress warnings on the (T) cast, which is a no-op.214@SuppressWarnings("unchecked")215Entry<T> castEntry(Entry<?> e) { return (Entry<T>) e; }216217/** Called when the fast path of get fails, and cache reprobe also fails.218*/219private T getFromHashMap(Class<?> type) {220// The fail-safe recovery is to fall back to the underlying classValueMap.221ClassValueMap map = getMap(type);222for (;;) {223Entry<T> e = map.startEntry(this);224if (!e.isPromise())225return e.value();226try {227// Try to make a real entry for the promised version.228e = makeEntry(e.version(), computeValue(type));229} finally {230// Whether computeValue throws or returns normally,231// be sure to remove the empty entry.232e = map.finishEntry(this, e);233}234if (e != null)235return e.value();236// else try again, in case a racing thread called remove (so e == null)237}238}239240/** Check that e is non-null, matches this ClassValue, and is live. */241boolean match(Entry<?> e) {242// racing e.version : null (blank) => unique Version token => null (GC-ed version)243// non-racing this.version : v1 => v2 => ... (updates are read faithfully from volatile)244return (e != null && e.get() == this.version);245// invariant: No false positives on version match. Null is OK for false negative.246// invariant: If version matches, then e.value is readable (final set in Entry.<init>)247}248249/** Internal hash code for accessing Class.classValueMap.cacheArray. */250final int hashCodeForCache = nextHashCode.getAndAdd(HASH_INCREMENT) & HASH_MASK;251252/** Value stream for hashCodeForCache. See similar structure in ThreadLocal. */253private static final AtomicInteger nextHashCode = new AtomicInteger();254255/** Good for power-of-two tables. See similar structure in ThreadLocal. */256private static final int HASH_INCREMENT = 0x61c88647;257258/** Mask a hash code to be positive but not too large, to prevent wraparound. */259static final int HASH_MASK = (-1 >>> 2);260261/**262* Private key for retrieval of this object from ClassValueMap.263*/264static class Identity {265}266/**267* This ClassValue's identity, expressed as an opaque object.268* The main object {@code ClassValue.this} is incorrect since269* subclasses may override {@code ClassValue.equals}, which270* could confuse keys in the ClassValueMap.271*/272final Identity identity = new Identity();273274/**275* Current version for retrieving this class value from the cache.276* Any number of computeValue calls can be cached in association with one version.277* But the version changes when a remove (on any type) is executed.278* A version change invalidates all cache entries for the affected ClassValue,279* by marking them as stale. Stale cache entries do not force another call280* to computeValue, but they do require a synchronized visit to a backing map.281* <p>282* All user-visible state changes on the ClassValue take place under283* a lock inside the synchronized methods of ClassValueMap.284* Readers (of ClassValue.get) are notified of such state changes285* when this.version is bumped to a new token.286* This variable must be volatile so that an unsynchronized reader287* will receive the notification without delay.288* <p>289* If version were not volatile, one thread T1 could persistently hold onto290* a stale value this.value == V1, while while another thread T2 advances291* (under a lock) to this.value == V2. This will typically be harmless,292* but if T1 and T2 interact causally via some other channel, such that293* T1's further actions are constrained (in the JMM) to happen after294* the V2 event, then T1's observation of V1 will be an error.295* <p>296* The practical effect of making this.version be volatile is that it cannot297* be hoisted out of a loop (by an optimizing JIT) or otherwise cached.298* Some machines may also require a barrier instruction to execute299* before this.version.300*/301private volatile Version<T> version = new Version<>(this);302Version<T> version() { return version; }303void bumpVersion() { version = new Version<>(this); }304static class Version<T> {305private final ClassValue<T> classValue;306private final Entry<T> promise = new Entry<>(this);307Version(ClassValue<T> classValue) { this.classValue = classValue; }308ClassValue<T> classValue() { return classValue; }309Entry<T> promise() { return promise; }310boolean isLive() { return classValue.version() == this; }311}312313/** One binding of a value to a class via a ClassValue.314* States are:<ul>315* <li> promise if value == Entry.this316* <li> else dead if version == null317* <li> else stale if version != classValue.version318* <li> else live </ul>319* Promises are never put into the cache; they only live in the320* backing map while a computeValue call is in flight.321* Once an entry goes stale, it can be reset at any time322* into the dead state.323*/324static class Entry<T> extends WeakReference<Version<T>> {325final Object value; // usually of type T, but sometimes (Entry)this326Entry(Version<T> version, T value) {327super(version);328this.value = value; // for a regular entry, value is of type T329}330private void assertNotPromise() { assert(!isPromise()); }331/** For creating a promise. */332Entry(Version<T> version) {333super(version);334this.value = this; // for a promise, value is not of type T, but Entry!335}336/** Fetch the value. This entry must not be a promise. */337@SuppressWarnings("unchecked") // if !isPromise, type is T338T value() { assertNotPromise(); return (T) value; }339boolean isPromise() { return value == this; }340Version<T> version() { return get(); }341ClassValue<T> classValueOrNull() {342Version<T> v = version();343return (v == null) ? null : v.classValue();344}345boolean isLive() {346Version<T> v = version();347if (v == null) return false;348if (v.isLive()) return true;349clear();350return false;351}352Entry<T> refreshVersion(Version<T> v2) {353assertNotPromise();354@SuppressWarnings("unchecked") // if !isPromise, type is T355Entry<T> e2 = new Entry<>(v2, (T) value);356clear();357// value = null -- caller must drop358return e2;359}360static final Entry<?> DEAD_ENTRY = new Entry<>(null, null);361}362363/** Return the backing map associated with this type. */364private static ClassValueMap getMap(Class<?> type) {365// racing type.classValueMap : null (blank) => unique ClassValueMap366// if a null is observed, a map is created (lazily, synchronously, uniquely)367// all further access to that map is synchronized368ClassValueMap map = type.classValueMap;369if (map != null) return map;370return initializeMap(type);371}372373private static final Object CRITICAL_SECTION = new Object();374private static final Unsafe UNSAFE = Unsafe.getUnsafe();375private static ClassValueMap initializeMap(Class<?> type) {376ClassValueMap map;377synchronized (CRITICAL_SECTION) { // private object to avoid deadlocks378// happens about once per type379if ((map = type.classValueMap) == null) {380map = new ClassValueMap(type);381// Place a Store fence after construction and before publishing to emulate382// ClassValueMap containing final fields. This ensures it can be383// published safely in the non-volatile field Class.classValueMap,384// since stores to the fields of ClassValueMap will not be reordered385// to occur after the store to the field type.classValueMap386UNSAFE.storeFence();387388type.classValueMap = map;389}390}391return map;392}393394static <T> Entry<T> makeEntry(Version<T> explicitVersion, T value) {395// Note that explicitVersion might be different from this.version.396return new Entry<>(explicitVersion, value);397398// As soon as the Entry is put into the cache, the value will be399// reachable via a data race (as defined by the Java Memory Model).400// This race is benign, assuming the value object itself can be401// read safely by multiple threads. This is up to the user.402//403// The entry and version fields themselves can be safely read via404// a race because they are either final or have controlled states.405// If the pointer from the entry to the version is still null,406// or if the version goes immediately dead and is nulled out,407// the reader will take the slow path and retry under a lock.408}409410// The following class could also be top level and non-public:411412/** A backing map for all ClassValues, relative a single given type.413* Gives a fully serialized "true state" for each pair (ClassValue cv, Class type).414* Also manages an unserialized fast-path cache.415*/416static class ClassValueMap extends WeakHashMap<ClassValue.Identity, Entry<?>> {417private final Class<?> type;418private Entry<?>[] cacheArray;419private int cacheLoad, cacheLoadLimit;420421/** Number of entries initially allocated to each type when first used with any ClassValue.422* It would be pointless to make this much smaller than the Class and ClassValueMap objects themselves.423* Must be a power of 2.424*/425private static final int INITIAL_ENTRIES = 32;426427/** Build a backing map for ClassValues, relative the given type.428* Also, create an empty cache array and install it on the class.429*/430ClassValueMap(Class<?> type) {431this.type = type;432sizeCache(INITIAL_ENTRIES);433}434435Entry<?>[] getCache() { return cacheArray; }436437/** Initiate a query. Store a promise (placeholder) if there is no value yet. */438synchronized439<T> Entry<T> startEntry(ClassValue<T> classValue) {440@SuppressWarnings("unchecked") // one map has entries for all value types <T>441Entry<T> e = (Entry<T>) get(classValue.identity);442Version<T> v = classValue.version();443if (e == null) {444e = v.promise();445// The presence of a promise means that a value is pending for v.446// Eventually, finishEntry will overwrite the promise.447put(classValue.identity, e);448// Note that the promise is never entered into the cache!449return e;450} else if (e.isPromise()) {451// Somebody else has asked the same question.452// Let the races begin!453if (e.version() != v) {454e = v.promise();455put(classValue.identity, e);456}457return e;458} else {459// there is already a completed entry here; report it460if (e.version() != v) {461// There is a stale but valid entry here; make it fresh again.462// Once an entry is in the hash table, we don't care what its version is.463e = e.refreshVersion(v);464put(classValue.identity, e);465}466// Add to the cache, to enable the fast path, next time.467checkCacheLoad();468addToCache(classValue, e);469return e;470}471}472473/** Finish a query. Overwrite a matching placeholder. Drop stale incoming values. */474synchronized475<T> Entry<T> finishEntry(ClassValue<T> classValue, Entry<T> e) {476@SuppressWarnings("unchecked") // one map has entries for all value types <T>477Entry<T> e0 = (Entry<T>) get(classValue.identity);478if (e == e0) {479// We can get here during exception processing, unwinding from computeValue.480assert(e.isPromise());481remove(classValue.identity);482return null;483} else if (e0 != null && e0.isPromise() && e0.version() == e.version()) {484// If e0 matches the intended entry, there has not been a remove call485// between the previous startEntry and now. So now overwrite e0.486Version<T> v = classValue.version();487if (e.version() != v)488e = e.refreshVersion(v);489put(classValue.identity, e);490// Add to the cache, to enable the fast path, next time.491checkCacheLoad();492addToCache(classValue, e);493return e;494} else {495// Some sort of mismatch; caller must try again.496return null;497}498}499500/** Remove an entry. */501synchronized502void removeEntry(ClassValue<?> classValue) {503Entry<?> e = remove(classValue.identity);504if (e == null) {505// Uninitialized, and no pending calls to computeValue. No change.506} else if (e.isPromise()) {507// State is uninitialized, with a pending call to finishEntry.508// Since remove is a no-op in such a state, keep the promise509// by putting it back into the map.510put(classValue.identity, e);511} else {512// In an initialized state. Bump forward, and de-initialize.513classValue.bumpVersion();514// Make all cache elements for this guy go stale.515removeStaleEntries(classValue);516}517}518519/** Change the value for an entry. */520synchronized521<T> void changeEntry(ClassValue<T> classValue, T value) {522@SuppressWarnings("unchecked") // one map has entries for all value types <T>523Entry<T> e0 = (Entry<T>) get(classValue.identity);524Version<T> version = classValue.version();525if (e0 != null) {526if (e0.version() == version && e0.value() == value)527// no value change => no version change needed528return;529classValue.bumpVersion();530removeStaleEntries(classValue);531}532Entry<T> e = makeEntry(version, value);533put(classValue.identity, e);534// Add to the cache, to enable the fast path, next time.535checkCacheLoad();536addToCache(classValue, e);537}538539/// --------540/// Cache management.541/// --------542543// Statics do not need synchronization.544545/** Load the cache entry at the given (hashed) location. */546static Entry<?> loadFromCache(Entry<?>[] cache, int i) {547// non-racing cache.length : constant548// racing cache[i & (mask)] : null <=> Entry549return cache[i & (cache.length-1)];550// invariant: returned value is null or well-constructed (ready to match)551}552553/** Look in the cache, at the home location for the given ClassValue. */554static <T> Entry<T> probeHomeLocation(Entry<?>[] cache, ClassValue<T> classValue) {555return classValue.castEntry(loadFromCache(cache, classValue.hashCodeForCache));556}557558/** Given that first probe was a collision, retry at nearby locations. */559static <T> Entry<T> probeBackupLocations(Entry<?>[] cache, ClassValue<T> classValue) {560if (PROBE_LIMIT <= 0) return null;561// Probe the cache carefully, in a range of slots.562int mask = (cache.length-1);563int home = (classValue.hashCodeForCache & mask);564Entry<?> e2 = cache[home]; // victim, if we find the real guy565if (e2 == null) {566return null; // if nobody is at home, no need to search nearby567}568// assume !classValue.match(e2), but do not assert, because of races569int pos2 = -1;570for (int i = home + 1; i < home + PROBE_LIMIT; i++) {571Entry<?> e = cache[i & mask];572if (e == null) {573break; // only search within non-null runs574}575if (classValue.match(e)) {576// relocate colliding entry e2 (from cache[home]) to first empty slot577cache[home] = e;578if (pos2 >= 0) {579cache[i & mask] = Entry.DEAD_ENTRY;580} else {581pos2 = i;582}583cache[pos2 & mask] = ((entryDislocation(cache, pos2, e2) < PROBE_LIMIT)584? e2 // put e2 here if it fits585: Entry.DEAD_ENTRY);586return classValue.castEntry(e);587}588// Remember first empty slot, if any:589if (!e.isLive() && pos2 < 0) pos2 = i;590}591return null;592}593594/** How far out of place is e? */595private static int entryDislocation(Entry<?>[] cache, int pos, Entry<?> e) {596ClassValue<?> cv = e.classValueOrNull();597if (cv == null) return 0; // entry is not live!598int mask = (cache.length-1);599return (pos - cv.hashCodeForCache) & mask;600}601602/// --------603/// Below this line all functions are private, and assume synchronized access.604/// --------605606private void sizeCache(int length) {607assert((length & (length-1)) == 0); // must be power of 2608cacheLoad = 0;609cacheLoadLimit = (int) ((double) length * CACHE_LOAD_LIMIT / 100);610cacheArray = new Entry<?>[length];611}612613/** Make sure the cache load stays below its limit, if possible. */614private void checkCacheLoad() {615if (cacheLoad >= cacheLoadLimit) {616reduceCacheLoad();617}618}619private void reduceCacheLoad() {620removeStaleEntries();621if (cacheLoad < cacheLoadLimit)622return; // win623Entry<?>[] oldCache = getCache();624if (oldCache.length > HASH_MASK)625return; // lose626sizeCache(oldCache.length * 2);627for (Entry<?> e : oldCache) {628if (e != null && e.isLive()) {629addToCache(e);630}631}632}633634/** Remove stale entries in the given range.635* Should be executed under a Map lock.636*/637private void removeStaleEntries(Entry<?>[] cache, int begin, int count) {638if (PROBE_LIMIT <= 0) return;639int mask = (cache.length-1);640int removed = 0;641for (int i = begin; i < begin + count; i++) {642Entry<?> e = cache[i & mask];643if (e == null || e.isLive())644continue; // skip null and live entries645Entry<?> replacement = null;646if (PROBE_LIMIT > 1) {647// avoid breaking up a non-null run648replacement = findReplacement(cache, i);649}650cache[i & mask] = replacement;651if (replacement == null) removed += 1;652}653cacheLoad = Math.max(0, cacheLoad - removed);654}655656/** Clearing a cache slot risks disconnecting following entries657* from the head of a non-null run, which would allow them658* to be found via reprobes. Find an entry after cache[begin]659* to plug into the hole, or return null if none is needed.660*/661private Entry<?> findReplacement(Entry<?>[] cache, int home1) {662Entry<?> replacement = null;663int haveReplacement = -1, replacementPos = 0;664int mask = (cache.length-1);665for (int i2 = home1 + 1; i2 < home1 + PROBE_LIMIT; i2++) {666Entry<?> e2 = cache[i2 & mask];667if (e2 == null) break; // End of non-null run.668if (!e2.isLive()) continue; // Doomed anyway.669int dis2 = entryDislocation(cache, i2, e2);670if (dis2 == 0) continue; // e2 already optimally placed671int home2 = i2 - dis2;672if (home2 <= home1) {673// e2 can replace entry at cache[home1]674if (home2 == home1) {675// Put e2 exactly where he belongs.676haveReplacement = 1;677replacementPos = i2;678replacement = e2;679} else if (haveReplacement <= 0) {680haveReplacement = 0;681replacementPos = i2;682replacement = e2;683}684// And keep going, so we can favor larger dislocations.685}686}687if (haveReplacement >= 0) {688if (cache[(replacementPos+1) & mask] != null) {689// Be conservative, to avoid breaking up a non-null run.690cache[replacementPos & mask] = (Entry<?>) Entry.DEAD_ENTRY;691} else {692cache[replacementPos & mask] = null;693cacheLoad -= 1;694}695}696return replacement;697}698699/** Remove stale entries in the range near classValue. */700private void removeStaleEntries(ClassValue<?> classValue) {701removeStaleEntries(getCache(), classValue.hashCodeForCache, PROBE_LIMIT);702}703704/** Remove all stale entries, everywhere. */705private void removeStaleEntries() {706Entry<?>[] cache = getCache();707removeStaleEntries(cache, 0, cache.length + PROBE_LIMIT - 1);708}709710/** Add the given entry to the cache, in its home location, unless it is out of date. */711private <T> void addToCache(Entry<T> e) {712ClassValue<T> classValue = e.classValueOrNull();713if (classValue != null)714addToCache(classValue, e);715}716717/** Add the given entry to the cache, in its home location. */718private <T> void addToCache(ClassValue<T> classValue, Entry<T> e) {719if (PROBE_LIMIT <= 0) return; // do not fill cache720// Add e to the cache.721Entry<?>[] cache = getCache();722int mask = (cache.length-1);723int home = classValue.hashCodeForCache & mask;724Entry<?> e2 = placeInCache(cache, home, e, false);725if (e2 == null) return; // done726if (PROBE_LIMIT > 1) {727// try to move e2 somewhere else in his probe range728int dis2 = entryDislocation(cache, home, e2);729int home2 = home - dis2;730for (int i2 = home2; i2 < home2 + PROBE_LIMIT; i2++) {731if (placeInCache(cache, i2 & mask, e2, true) == null) {732return;733}734}735}736// Note: At this point, e2 is just dropped from the cache.737}738739/** Store the given entry. Update cacheLoad, and return any live victim.740* 'Gently' means return self rather than dislocating a live victim.741*/742private Entry<?> placeInCache(Entry<?>[] cache, int pos, Entry<?> e, boolean gently) {743Entry<?> e2 = overwrittenEntry(cache[pos]);744if (gently && e2 != null) {745// do not overwrite a live entry746return e;747} else {748cache[pos] = e;749return e2;750}751}752753/** Note an entry that is about to be overwritten.754* If it is not live, quietly replace it by null.755* If it is an actual null, increment cacheLoad,756* because the caller is going to store something757* in its place.758*/759private <T> Entry<T> overwrittenEntry(Entry<T> e2) {760if (e2 == null) cacheLoad += 1;761else if (e2.isLive()) return e2;762return null;763}764765/** Percent loading of cache before resize. */766private static final int CACHE_LOAD_LIMIT = 67; // 0..100767/** Maximum number of probes to attempt. */768private static final int PROBE_LIMIT = 6; // 1..769// N.B. Set PROBE_LIMIT=0 to disable all fast paths.770}771}772773774