APIdia Launch Partner
Top Description Inners Fields Constructors Methods
java.lang

public abstract Class ClassValue<T>

extends Object
Class Inheritance
Type Parameters
<T>
the type of the associated value
Imports
java.util.WeakHashMap, java.lang.ref.WeakReference, java.util.concurrent.atomic.AtomicInteger, jdk.internal.misc.Unsafe

Lazily associate a computed value with any Class object. For example, if a dynamic language needs to construct a message dispatch table for each class encountered at a message send call site, it can use a ClassValue to cache information needed to perform the message send quickly, for each class encountered.

The basic operation of a ClassValue is get, which returns the associated value, initially created by an invocation to computeValue; multiple invocations may happen under race, but exactly one value is associated to a Class and returned.

Another operation is remove: it clears the associated value (if it exists), and ensures the next associated value is computed with input states up-to-date with the removal.

For a particular association, there is a total order for accesses to the associated value. Accesses are atomic; they include:

A get call always include at least one access; a remove call always has exactly one access; a computeValue call always happens between two accesses. This establishes the order of computeValue calls with respect to remove calls and determines whether the results of a computeValue can be successfully associated by a get.
Author
John Rose, JSR 292 EG
Since
1.7

Nested and Inner Type Summary

Modifier and TypeClass and Description
pack-priv static class
ClassValue.ClassValueMap

A backing map for all ClassValues.

pack-priv static class
ClassValue.Entry<T>

One binding of a value to a class via a ClassValue.

pack-priv static class
ClassValue.Identity

Private key for retrieval of this object from ClassValueMap.

private static class
ClassValue.RemovalToken

Besides a value (represented by an Entry), a "removal token" object, including the value null, can be present at a ClassValue-Class coordinate.

pack-priv static record

Field Summary

Modifier and TypeField and Description
private static final Object
private static final ClassValue.Entry<?>[]
EMPTY_CACHE

Initial, one-element, empty cache used by all Class instances.

private static final int
HASH_INCREMENT

Good for power-of-two tables.

pack-priv static final int
HASH_MASK

Mask a hash code to be positive but not too large, to prevent wraparound.

pack-priv final int
hashCodeForCache

Internal hash code for accessing Class.classValueMap.cacheArray.

pack-priv final ClassValue.Identity
identity

This ClassValue's identity, expressed as an opaque object.

private static final AtomicInteger
nextHashCode

Value stream for hashCodeForCache.

private static final Unsafe
private volatile ClassValue.Version<T>
version

Current version for retrieving this class value from the cache.

Constructor Summary

AccessConstructor and Description
protected
ClassValue()

Sole constructor.

Method Summary

Modifier and TypeMethod and Description
pack-priv void
pack-priv ClassValue.Entry<T>
protected abstract T

Returns:

the newly computed value to associate
computeValue
(Class<?>
the Class to associate a value to
type
)

Computes the value to associate to the given Class.

public T

Returns:

the value associated to the given Class
get
(Class<?>
the Class to retrieve the associated value for
type
)

Returns the value associated to the given Class.

private static ClassValue.Entry<?>[]
getCacheCarefully(Class<?> type)

Return the cache, if it exists, else a dummy empty cache.

private T
getFromBackup(ClassValue.Entry<?>[] cache, Class<?> type)

Slow tail of ClassValue.get to retry at nearby locations in the cache, or take a slow lock and check the hash table.

private T
getFromHashMap(Class<?> type)

Called when the fast path of get fails, and cache reprobe also fails.

private static ClassValue.ClassValueMap
getMap(Class<?> type)

Return the backing map associated with this type.

private static ClassValue.ClassValueMap
pack-priv static <T> ClassValue.Entry<T>
makeEntry(ClassValue.Version<T> explicitVersion, T value)

pack-priv boolean
match(ClassValue.Entry<?> e)

Check that e is non-null, matches this ClassValue, and is live.

pack-priv void
put(Class<?> type, T value)

public void
remove(Class<?>
the type whose class value must be removed
type
)

Removes the associated value for the given Class and invalidates all out-of-date computations.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

CRITICAL_SECTIONback to summary
private static final Object CRITICAL_SECTION
EMPTY_CACHEback to summary
private static final ClassValue.Entry<?>[] EMPTY_CACHE

Initial, one-element, empty cache used by all Class instances. Must never be filled.

HASH_INCREMENTback to summary
private static final int HASH_INCREMENT

Good for power-of-two tables. See similar structure in ThreadLocal.

HASH_MASKback to summary
pack-priv static final int HASH_MASK

Mask a hash code to be positive but not too large, to prevent wraparound.

hashCodeForCacheback to summary
pack-priv final int hashCodeForCache

Internal hash code for accessing Class.classValueMap.cacheArray.

identityback to summary
pack-priv final ClassValue.Identity identity

This ClassValue's identity, expressed as an opaque object. The main object ClassValue.this is incorrect since subclasses may override ClassValue.equals, which could confuse keys in the ClassValueMap.

nextHashCodeback to summary
private static final AtomicInteger nextHashCode

Value stream for hashCodeForCache. See similar structure in ThreadLocal.

UNSAFEback to summary
private static final Unsafe UNSAFE
versionback to summary
private volatile ClassValue.Version<T> version

Current version for retrieving this class value from the cache. Any number of computeValue calls can be cached in association with one version. But the version changes when a remove (on any type) is executed. A version change invalidates all cache entries for the affected ClassValue, by marking them as stale. Stale cache entries do not force another call to computeValue, but they do require a synchronized visit to a backing map.

All user-visible state changes on the ClassValue take place under a lock inside the synchronized methods of ClassValueMap. Readers (of ClassValue.get) are notified of such state changes when this.version is bumped to a new token. This variable must be volatile so that an unsynchronized reader will receive the notification without delay.

If version were not volatile, one thread T1 could persistently hold onto a stale value this.value == V1, while another thread T2 advances (under a lock) to this.value == V2. This will typically be harmless, but if T1 and T2 interact causally via some other channel, such that T1's further actions are constrained (in the JMM) to happen after the V2 event, then T1's observation of V1 will be an error.

The practical effect of making this.version be volatile is that it cannot be hoisted out of a loop (by an optimizing JIT) or otherwise cached. Some machines may also require a barrier instruction to execute before this.version.

Constructor Detail

ClassValueback to summary
protected ClassValue()

Sole constructor. (For invocation by subclass constructors, typically implicit.)

Method Detail

bumpVersionback to summary
pack-priv void bumpVersion()
castEntryback to summary
pack-priv ClassValue.Entry<T> castEntry(ClassValue.Entry<?> e)
Annotations
@SuppressWarnings:unchecked
computeValueback to summary
protected abstract T computeValue(Class<?> type)

Computes the value to associate to the given Class.

This method is invoked when the initial read-only access by get finds no associated value.

If this method throws an exception, the initiating get call will not attempt to associate a value, and may terminate by returning the associated value if it exists, or by propagating that exception otherwise.

Otherwise, the value is computed and returned. An attempt to associate the return value happens, with one of the following outcomes:

  • The associated value is present; it is returned and no association is done.
  • The most recent remove call, if it exists, does not happen-before (JLS 17.4.5) the finish of the computeValue that computed the value to associate. A new invocation to computeValue, which that remove call happens-before, will re-establish this happens-before relationship.
  • Otherwise, this value is successfully associated and returned.

API Note

A computeValue call may, due to class loading or other circumstances, recursively call get or remove for the same type. The recursive get, if the recursion stops, successfully finishes and this initiating get observes the associated value from recursion. The recursive remove is no-op, since being on the same thread, the remove already happens-before the finish of this computeValue; the result from this computeValue still may be associated.

Parameters
type:Class<?>

the Class to associate a value to

Returns:T

the newly computed value to associate

See Also
get, remove
getback to summary
public T get(Class<?> type)

Returns the value associated to the given Class.

This method first performs a read-only access, and returns the associated value if it exists. Otherwise, this method tries to associate a value from a computeValue invocation until the associated value exists, which could be associated by a competing thread.

This method may throw an exception from a computeValue invocation. In this case, no association happens.

Parameters
type:Class<?>

the Class to retrieve the associated value for

Returns:T

the value associated to the given Class

Exceptions
NullPointerException:
if the argument is null
See Also
remove, computeValue
getCacheCarefullyback to summary
private static ClassValue.Entry<?>[] getCacheCarefully(Class<?> type)

Return the cache, if it exists, else a dummy empty cache.

getFromBackupback to summary
private T getFromBackup(ClassValue.Entry<?>[] cache, Class<?> type)

Slow tail of ClassValue.get to retry at nearby locations in the cache, or take a slow lock and check the hash table. Called only if the first probe was empty or a collision. This is a separate method, so compilers can process it independently.

getFromHashMapback to summary
private T getFromHashMap(Class<?> type)

Called when the fast path of get fails, and cache reprobe also fails.

getMapback to summary
private static ClassValue.ClassValueMap getMap(Class<?> type)

Return the backing map associated with this type.

initializeMapback to summary
private static ClassValue.ClassValueMap initializeMap(Class<?> type)
makeEntryback to summary
pack-priv static <T> ClassValue.Entry<T> makeEntry(ClassValue.Version<T> explicitVersion, T value)
matchback to summary
pack-priv boolean match(ClassValue.Entry<?> e)

Check that e is non-null, matches this ClassValue, and is live.

putback to summary
pack-priv void put(Class<?> type, T value)
removeback to summary
public void remove(Class<?> type)

Removes the associated value for the given Class and invalidates all out-of-date computations. If this association is subsequently accessed, this removal happens-before (JLS 17.4.5) the finish of the computeValue call that returned the associated value.

Parameters
type:Class<?>

the type whose class value must be removed

Exceptions
NullPointerException:
if the argument is null
java.lang back to summary

pack-priv final Class ClassValue.ClassValueMap

extends WeakHashMap<ClassValue.Identity, Object>
Class Inheritance

A backing map for all ClassValues. Gives a fully serialized "true state" for each pair (ClassValue cv, Class type). The state may be assigned value or unassigned token. Also manages an unserialized fast-path cache.

Field Summary

Modifier and TypeField and Description
private static final int
CACHE_LOAD_LIMIT

Percent loading of cache before resize.

private ClassValue.Entry<?>[]
private int
private int
private static final int
INITIAL_ENTRIES

Number of entries initially allocated to each type when first used with any ClassValue.

private static final int
PROBE_LIMIT

Maximum number of probes to attempt.

Constructor Summary

AccessConstructor and Description
pack-priv
ClassValueMap()

Build a backing map for ClassValues.

Method Summary

Modifier and TypeMethod and Description
private <T> void
addToCache(ClassValue.Entry<T> e)

Add the given entry to the cache, in its home location, unless it is out of date.

private <T> void
addToCache(ClassValue<T> classValue, ClassValue.Entry<T> e)

Add the given entry to the cache, in its home location.

pack-priv synchronized <T> Object
associateAccess(ClassValue<T> classValue, ClassValue.RemovalToken startToken, T value)

private void
checkCacheLoad()

Make sure the cache load stays below its limit, if possible.

private static int
entryDislocation(ClassValue.Entry<?>[] cache, int pos, ClassValue.Entry<?> e)

How far out of place is e?

private ClassValue.Entry<?>
findReplacement(ClassValue.Entry<?>[] cache, int home1)

Clearing a cache slot risks disconnecting following entries from the head of a non-null run, which would allow them to be found via reprobes.

pack-priv synchronized <T> void
forcedAssociateAccess(ClassValue<T> classValue, T value)

pack-priv ClassValue.Entry<?>[]
pack-priv static ClassValue.Entry<?>
loadFromCache(ClassValue.Entry<?>[] cache, int i)

Load the cache entry at the given (hashed) location.

private <T> ClassValue.Entry<T>
overwrittenEntry(ClassValue.Entry<T> e2)

Note an entry that is about to be overwritten.

private ClassValue.Entry<?>
placeInCache(ClassValue.Entry<?>[] cache, int pos, ClassValue.Entry<?> e, boolean gently)

Store the given entry.

pack-priv static <T> ClassValue.Entry<T>
probeBackupLocations(ClassValue.Entry<?>[] cache, ClassValue<T> classValue)

Given that first probe was a collision, retry at nearby locations.

pack-priv static <T> ClassValue.Entry<T>
probeHomeLocation(ClassValue.Entry<?>[] cache, ClassValue<T> classValue)

Look in the cache, at the home location for the given ClassValue.

pack-priv synchronized <T> Object
readAccess(ClassValue<T> classValue)

private void
pack-priv synchronized void
removeAccess(ClassValue<?> classValue)

private void
removeStaleEntries(ClassValue.Entry<?>[] cache, int begin, int count)

Remove stale entries in the given range.

private void
removeStaleEntries(ClassValue<?> classValue)

Remove stale entries in the range near classValue.

private void
removeStaleEntries()

Remove all stale entries, everywhere.

private void
sizeCache(int length)

<hr> Below this line all functions are private, and assume synchronized access.

Inherited from java.util.WeakHashMap:
clearcontainsKeycontainsValueentrySetforEachgetisEmptykeySetnewWeakHashMapputputAllremovereplaceAllsizevalues

Field Detail

CACHE_LOAD_LIMITback to summary
private static final int CACHE_LOAD_LIMIT

Percent loading of cache before resize.

cacheArrayback to summary
private ClassValue.Entry<?>[] cacheArray
cacheLoadback to summary
private int cacheLoad
cacheLoadLimitback to summary
private int cacheLoadLimit
INITIAL_ENTRIESback to summary
private static final int INITIAL_ENTRIES

Number of entries initially allocated to each type when first used with any ClassValue. It would be pointless to make this much smaller than the Class and ClassValueMap objects themselves. Must be a power of 2.

PROBE_LIMITback to summary
private static final int PROBE_LIMIT

Maximum number of probes to attempt.

Constructor Detail

ClassValueMapback to summary
pack-priv ClassValueMap()

Build a backing map for ClassValues. Also, create an empty cache array and install it on the class.

Method Detail

addToCacheback to summary
private <T> void addToCache(ClassValue.Entry<T> e)

Add the given entry to the cache, in its home location, unless it is out of date.

addToCacheback to summary
private <T> void addToCache(ClassValue<T> classValue, ClassValue.Entry<T> e)

Add the given entry to the cache, in its home location.

associateAccessback to summary
pack-priv synchronized <T> Object associateAccess(ClassValue<T> classValue, ClassValue.RemovalToken startToken, T value)
checkCacheLoadback to summary
private void checkCacheLoad()

Make sure the cache load stays below its limit, if possible.

entryDislocationback to summary
private static int entryDislocation(ClassValue.Entry<?>[] cache, int pos, ClassValue.Entry<?> e)

How far out of place is e?

findReplacementback to summary
private ClassValue.Entry<?> findReplacement(ClassValue.Entry<?>[] cache, int home1)

Clearing a cache slot risks disconnecting following entries from the head of a non-null run, which would allow them to be found via reprobes. Find an entry after cache[begin] to plug into the hole, or return null if none is needed.

forcedAssociateAccessback to summary
pack-priv synchronized <T> void forcedAssociateAccess(ClassValue<T> classValue, T value)
getCacheback to summary
pack-priv ClassValue.Entry<?>[] getCache()
loadFromCacheback to summary
pack-priv static ClassValue.Entry<?> loadFromCache(ClassValue.Entry<?>[] cache, int i)

Load the cache entry at the given (hashed) location.

overwrittenEntryback to summary
private <T> ClassValue.Entry<T> overwrittenEntry(ClassValue.Entry<T> e2)

Note an entry that is about to be overwritten. If it is not live, quietly replace it by null. If it is an actual null, increment cacheLoad, because the caller is going to store something in its place.

placeInCacheback to summary
private ClassValue.Entry<?> placeInCache(ClassValue.Entry<?>[] cache, int pos, ClassValue.Entry<?> e, boolean gently)

Store the given entry. Update cacheLoad, and return any live victim. 'Gently' means return self rather than dislocating a live victim.

probeBackupLocationsback to summary
pack-priv static <T> ClassValue.Entry<T> probeBackupLocations(ClassValue.Entry<?>[] cache, ClassValue<T> classValue)

Given that first probe was a collision, retry at nearby locations.

probeHomeLocationback to summary
pack-priv static <T> ClassValue.Entry<T> probeHomeLocation(ClassValue.Entry<?>[] cache, ClassValue<T> classValue)

Look in the cache, at the home location for the given ClassValue.

readAccessback to summary
pack-priv synchronized <T> Object readAccess(ClassValue<T> classValue)
reduceCacheLoadback to summary
private void reduceCacheLoad()
removeAccessback to summary
pack-priv synchronized void removeAccess(ClassValue<?> classValue)
removeStaleEntriesback to summary
private void removeStaleEntries(ClassValue.Entry<?>[] cache, int begin, int count)

Remove stale entries in the given range. Should be executed under a Map lock.

removeStaleEntriesback to summary
private void removeStaleEntries(ClassValue<?> classValue)

Remove stale entries in the range near classValue.

removeStaleEntriesback to summary
private void removeStaleEntries()

Remove all stale entries, everywhere.

sizeCacheback to summary
private void sizeCache(int length)


Below this line all functions are private, and assume synchronized access.
java.lang back to summary

pack-priv final Class ClassValue.Entry<T>

extends Object
Class Inheritance

One binding of a value to a class via a ClassValue. Shared for the map and the cache array. The version is only meaningful for the cache array; whatever in the map is authentic, but state informs the cache an entry may be out-of-date. States are: Once an entry goes stale, it can be reset at any time into the dead state.

Field Summary

Modifier and TypeField and Description
pack-priv static final ClassValue.Entry<?>
pack-priv final T
pack-priv final WeakReference<ClassValue.Version<T>>

Constructor Summary

AccessConstructor and Description
pack-priv
Entry(ClassValue.Version<T> version, T value)

Method Summary

Modifier and TypeMethod and Description
pack-priv ClassValue<T>
pack-priv boolean
pack-priv ClassValue.Entry<T>
pack-priv ClassValue.Version<T>
Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

DEAD_ENTRYback to summary
pack-priv static final ClassValue.Entry<?> DEAD_ENTRY
valueback to summary
pack-priv final T value
versionback to summary
pack-priv final WeakReference<ClassValue.Version<T>> version

Constructor Detail

Entryback to summary
pack-priv Entry(ClassValue.Version<T> version, T value)

Method Detail

classValueOrNullback to summary
pack-priv ClassValue<T> classValueOrNull()
isLiveback to summary
pack-priv boolean isLive()
refreshVersionback to summary
pack-priv ClassValue.Entry<T> refreshVersion(ClassValue.Version<T> v2)
versionback to summary
pack-priv ClassValue.Version<T> version()
java.lang back to summary

pack-priv Class ClassValue.Identity

extends Object
Class Inheritance

Private key for retrieval of this object from ClassValueMap.

Constructor Summary

AccessConstructor and Description
pack-priv

Method Summary

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Constructor Detail

Identityback to summary
pack-priv Identity()
java.lang back to summary

private final Class ClassValue.RemovalToken

extends Object
Class Inheritance

Besides a value (represented by an Entry), a "removal token" object, including the value null, can be present at a ClassValue-Class coordinate. A removal token indicates whether the value from a computation is up-to-date; the value is up-to-date if the token is the same before and after computation (no removal during this period), or if the token is from the same thread (removed during computeValue). null is the initial state, meaning all computations are valid. Later tokens are always non-null, no matter if they replace existing entries or outdated tokens.

Field Summary

Modifier and TypeField and Description
private final long

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
private static boolean
Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

actorIdback to summary
private final long actorId

Constructor Detail

RemovalTokenback to summary
private RemovalToken()

Method Detail

allowsAssociationback to summary
private static boolean allowsAssociation(ClassValue.RemovalToken current, ClassValue.RemovalToken start)
java.lang back to summary

pack-priv final Record ClassValue.Version<T>

extends Record
Class Inheritance
Record Components
classValue:ClassValue<T> 

Field Summary

Modifier and TypeField and Description
private final ClassValue<T>
classValue

Record Component accessed by classValue().

Constructor Summary

AccessConstructor and Description
pack-priv
Version(ClassValue<T> classValue)

Method Summary

Modifier and TypeMethod and Description
public ClassValue<T>
classValue()

Record Component getter of classValue.

public final boolean
equals(Object o)

Implements abstract java.lang.Record.equals.

Indicates whether some other object is "equal to" this one.

public final int
hashCode()

Implements abstract java.lang.Record.hashCode.

Returns a hash code value for the record.

pack-priv boolean
public final String
toString()

Implements abstract java.lang.Record.toString.

Returns a string representation of the record.

Field Detail

classValueback to summary
private final ClassValue<T> classValue

Record Component accessed by classValue().

Constructor Detail

Versionback to summary
pack-priv Version(ClassValue<T> classValue)

Method Detail

classValueback to summary
public ClassValue<T> classValue()

Record Component getter of classValue.

equalsback to summary
public final boolean equals(Object o)

Implements abstract java.lang.Record.equals.

Doc from java.lang.Record.equals.

Indicates whether some other object is "equal to" this one. In addition to the general contract of Object.equals, record classes must further obey the invariant that when a record instance is "copied" by passing the result of the record component accessor methods to the canonical constructor, as follows:

    R copy = new R(r.c1(), r.c2(), ..., r.cn());
then it must be the case that r.equals(copy).
hashCodeback to summary
public final int hashCode()

Implements abstract java.lang.Record.hashCode.

Doc from java.lang.Record.hashCode.

Returns a hash code value for the record. Obeys the general contract of Object.hashCode. For records, hashing behavior is constrained by the refined contract of Record.equals, so that any two records created from the same components must have the same hash code.

isLiveback to summary
pack-priv boolean isLive()
toStringback to summary
public final String toString()

Implements abstract java.lang.Record.toString.

Doc from java.lang.Record.toString.

Returns a string representation of the record. In accordance with the general contract of Object#toString(), the toString method returns a string that "textually represents" this record. The result should be a concise but informative representation that is easy for a person to read.

In addition to this general contract, record classes must further participate in the invariant that any two records which are equal must produce equal strings. This invariant is necessarily relaxed in the rare case where corresponding equal component values might fail to produce equal strings for themselves.