/** Called when the fast path of get fails, and cache reprobe also fails. */ private T getFromHashMap(Class<?> type) { // The fail-safe recovery is to fall back to the underlying classValueMap. ClassValueMap map = getMap(type); for (;;) { Entry<T> e = map.startEntry(this); if (!e.isPromise()) return e.value(); try { // Try to make a real entry for the promised version. e = makeEntry(e.version(), computeValue(type)); } finally { // Whether computeValue throws or returns normally, // be sure to remove the empty entry. e = map.finishEntry(this, e); } if (e != null) return e.value(); // else try again, in case a racing thread called remove (so e == null) } }
/** Return the cache, if it exists, else a dummy empty cache. */ 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; Entry<?>[] cache = map.getCache(); return cache; // invariant: returned value is safe to dereference and check for an Entry }
/** Return the backing map associated with this type. */ private static ClassValueMap getMap(Class<?> type) { // racing type.classValueMap : null (blank) => unique ClassValueMap // if a null is observed, a map is created (lazily, synchronously, uniquely) // all further access to that map is synchronized ClassValueMap map = type.classValueMap; if (map != null) return map; return initializeMap(type); }
private static ClassValueMap initializeMap(Class<?> type) { ClassValueMap map; synchronized (CRITICAL_SECTION) { // private object to avoid deadlocks // happens about once per type if ((map = type.classValueMap) == null) type.classValueMap = map = new ClassValueMap(type); } return map; }