1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import jdk.internal.misc.Unsafe; 29 import jdk.internal.vm.annotation.ForceInline; 30 import jdk.internal.vm.annotation.Stable; 31 32 import java.lang.ref.PhantomReference; 33 import java.lang.ref.ReferenceQueue; 34 import java.lang.ref.WeakReference; 35 import java.util.concurrent.ConcurrentHashMap; 36 import java.util.concurrent.atomic.AtomicBoolean; 37 import java.util.concurrent.atomic.AtomicInteger; 38 import java.util.concurrent.atomic.AtomicReference; 39 40 /** 41 * Lazily associate a computed value with (potentially) every type. 42 * For example, if a dynamic language needs to construct a message dispatch 43 * table for each class encountered at a message send call site, 44 * it can use a {@code ClassValue} to cache information needed to 45 * perform the message send quickly, for each class encountered. 46 * @author John Rose, JSR 292 EG 47 * @since 1.7 48 */ 49 public abstract class ClassValue<T> { 50 /** 51 * Sole constructor. (For invocation by subclass constructors, typically 52 * implicit.) 53 */ 54 protected ClassValue() { 55 } 56 57 /** 58 * Computes the given class's derived value for this {@code ClassValue}. 59 * <p> 60 * This method will be invoked within the first thread that accesses 61 * the value with the {@link #get get} method. 62 * <p> 63 * Normally, this method is invoked at most once per class, 64 * but it may be invoked again if there has been a call to 65 * {@link #remove remove}. 66 * <p> 67 * If this method throws an exception, the corresponding call to {@code get} 68 * will terminate abnormally with that exception, and no class value will be recorded. 69 * 70 * @param type the type whose class value must be computed 71 * @return the newly computed value associated with this {@code ClassValue}, for the given class or interface 72 * @see #get 73 * @see #remove 74 */ 75 protected abstract T computeValue(Class<?> type); 76 77 /** 78 * Returns the value for the given class. 79 * If no value has yet been computed, it is obtained by 80 * an invocation of the {@link #computeValue computeValue} method. 81 * <p> 82 * The actual installation of the value on the class 83 * is performed atomically. 84 * At that point, if several racing threads have 85 * computed values, one is chosen, and returned to 86 * all the racing threads. 87 * <p> 88 * The {@code type} parameter is typically a class, but it may be any type, 89 * such as an interface, a primitive type (like {@code int.class}), or {@code void.class}. 90 * <p> 91 * In the absence of {@code remove} calls, a class value has a simple 92 * state diagram: uninitialized and initialized. 93 * When {@code remove} calls are made, 94 * the rules for value observation are more complex. 95 * See the documentation for {@link #remove remove} for more information. 96 * 97 * @param type the type whose class value must be computed or retrieved 98 * @return the current value associated with this {@code ClassValue}, for the given class or interface 99 * @throws NullPointerException if the argument is null 100 * @see #remove 101 * @see #computeValue 102 */ 103 @SuppressWarnings("unchecked") 104 @ForceInline 105 public T get(Class<?> type) { 106 ClassValueMap map = type.classValueMap; 107 Object value; 108 if (map != null) { 109 value = map.get(key); 110 if (value != null && !(value instanceof Removed)) { 111 return (value == NULL_MASK) ? null : (T) value; 112 } 113 } else { 114 value = null; 115 } 116 return getSlow(type, value); 117 } 118 // ...the rest in separate method 119 @SuppressWarnings("unchecked") 120 private T getSlow(Class<?> type, Object oldValue) { 121 ClassValueMap.expungeStaleEntries(); 122 ClassValueMap map = getMap(type); 123 while (true) { 124 // assert oldValue == null || oldValue instanceof Removed; 125 T newValue = computeValue(type); 126 if (oldValue == null) { 127 oldValue = map.putIfAbsent(key, (newValue == null) ? NULL_MASK : newValue); 128 if (oldValue == null) { 129 return newValue; 130 } else { 131 // another thread has beaten us 132 if (!(oldValue instanceof Removed)) { 133 return (oldValue == NULL_MASK) ? null : (T) oldValue; 134 } 135 } 136 } else { 137 // assert oldValue instanceof Removed; 138 if (map.replace(key, oldValue, (newValue == null) ? NULL_MASK : newValue)) { 139 // this only succeeds if oldValue is still the same instance of 140 // Removed as observed before computeValue invocation 141 return newValue; 142 } else { 143 // another thread has beaten us 144 oldValue = map.get(key); 145 if (oldValue != null && !(oldValue instanceof Removed)) { 146 return (oldValue == NULL_MASK) ? null : (T) oldValue; 147 } 148 } 149 } 150 // retry compute since we observed another version of Removed 151 // as was current before compute which means that there was 152 // at least one value present in between time which means 153 // that the result of our compute is stale. 154 } 155 } 156 157 /** 158 * Removes the associated value for the given class. 159 * If this value is subsequently {@linkplain #get read} for the same class, 160 * its value will be reinitialized by invoking its {@link #computeValue computeValue} method. 161 * This may result in an additional invocation of the 162 * {@code computeValue} method for the given class. 163 * <p> 164 * In order to explain the interaction between {@code get} and {@code remove} calls, 165 * we must model the state transitions of a class value to take into account 166 * the alternation between uninitialized and initialized states. 167 * To do this, number these states sequentially from zero, and note that 168 * uninitialized (or removed) states are numbered with even numbers, 169 * while initialized (or re-initialized) states have odd numbers. 170 * <p> 171 * When a thread {@code T} removes a class value in state {@code 2N}, 172 * nothing happens, since the class value is already uninitialized. 173 * Otherwise, the state is advanced atomically to {@code 2N+1}. 174 * <p> 175 * When a thread {@code T} queries a class value in state {@code 2N}, 176 * the thread first attempts to initialize the class value to state {@code 2N+1} 177 * by invoking {@code computeValue} and installing the resulting value. 178 * <p> 179 * When {@code T} attempts to install the newly computed value, 180 * if the state is still at {@code 2N}, the class value will be initialized 181 * with the computed value, advancing it to state {@code 2N+1}. 182 * <p> 183 * Otherwise, whether the new state is even or odd, 184 * {@code T} will discard the newly computed value 185 * and retry the {@code get} operation. 186 * <p> 187 * Discarding and retrying is an important proviso, 188 * since otherwise {@code T} could potentially install 189 * a disastrously stale value. For example: 190 * <ul> 191 * <li>{@code T} calls {@code CV.get(C)} and sees state {@code 2N} 192 * <li>{@code T} quickly computes a time-dependent value {@code V0} and gets ready to install it 193 * <li>{@code T} is hit by an unlucky paging or scheduling event, and goes to sleep for a long time 194 * <li>...meanwhile, {@code T2} also calls {@code CV.get(C)} and sees state {@code 2N} 195 * <li>{@code T2} quickly computes a similar time-dependent value {@code V1} and installs it on {@code CV.get(C)} 196 * <li>{@code T2} (or a third thread) then calls {@code CV.remove(C)}, undoing {@code T2}'s work 197 * <li> the previous actions of {@code T2} are repeated several times 198 * <li> also, the relevant computed values change over time: {@code V1}, {@code V2}, ... 199 * <li>...meanwhile, {@code T} wakes up and attempts to install {@code V0}; <em>this must fail</em> 200 * </ul> 201 * We can assume in the above scenario that {@code CV.computeValue} uses locks to properly 202 * observe the time-dependent states as it computes {@code V1}, etc. 203 * This does not remove the threat of a stale value, since there is a window of time 204 * between the return of {@code computeValue} in {@code T} and the installation 205 * of the new value. No user synchronization is possible during this time. 206 * 207 * @param type the type whose class value must be removed 208 * @throws NullPointerException if the argument is null 209 */ 210 public void remove(Class<?> type) { 211 ClassValueMap.expungeStaleEntries(); 212 ClassValueMap map = type.classValueMap; 213 if (map != null) { 214 Object value, removed = null; 215 do { 216 value = map.get(key); 217 if (value == null || value instanceof Removed) { 218 // non-existence is treated as Removed(V0) 219 // invoking remove() when state is Removed(VN) does not 220 // change it to Removed(VN+1) 221 break; 222 } 223 if (removed == null) { 224 removed = new Removed(); 225 } 226 } while (!map.replace(key, value, removed)); 227 } 228 } 229 230 // Possible functionality for JSR 292 MR 1 231 /*public*/ void put(Class<?> type, T value) { 232 ClassValueMap.expungeStaleEntries(); 233 ClassValueMap map = getMap(type); 234 map.put(key, (value == null) ? NULL_MASK : value); 235 } 236 237 /// -------- 238 /// Implementation... 239 /// -------- 240 241 /** 242 * The key used in ClassValueMap for this ClassValue. 243 * Since ClassValue(s) are usually assigned to static final fields, it makes 244 * sense to promote the key to constant too. 245 */ 246 @Stable 247 private final Key key = new Key(this); 248 249 /** 250 * Key of a ClassValue and a tracker of the ClassValue at the same time. 251 */ 252 private static final class Key extends PhantomReference<ClassValue<?>> { 253 254 /** Value stream for hash. See similar structure in ThreadLocal. */ 255 private static final AtomicInteger nextHash = new AtomicInteger(); 256 257 /** Good for power-of-two tables. See similar structure in ThreadLocal. */ 258 private static final int HASH_INCREMENT = 0x61c88647; 259 260 /** Single global queue for all stale keys to be enqueued */ 261 static final ReferenceQueue<ClassValue<?>> queue = new ReferenceQueue<>(); 262 263 @Stable 264 private final int hash; 265 266 Key(ClassValue<?> cv) { 267 super(cv, queue); 268 int h = nextHash.getAndAdd(HASH_INCREMENT); 269 // undo the effect of CHM.spread() 270 this.hash = h ^ (h >>> 16); 271 } 272 273 @Override 274 public int hashCode() { 275 return hash; 276 } 277 278 // equals is identity 279 } 280 281 /** A masked null value. */ 282 private static final Object NULL_MASK = new Object(); 283 284 /** Removed value(s) */ 285 private static final class Removed {} 286 287 /** Return the backing map associated with this type, possibly constructing it. */ 288 private static ClassValueMap getMap(Class<?> type) { 289 ClassValueMap map = type.classValueMap; 290 return (map != null) ? map : initializeMap(type); 291 } 292 293 private static ClassValueMap initializeMap(Class<?> type) { 294 ClassValueMap map = ClassValueMap.create(); 295 return U.compareAndSwapObject(type, CLASS_VALUE_MAP_OFFSET, null, map) 296 ? map 297 : (ClassValueMap) U.getObjectVolatile(type, CLASS_VALUE_MAP_OFFSET); 298 } 299 300 /** A backing map for all ClassValues in a particular Class. 301 */ 302 static final class ClassValueMap extends ConcurrentHashMap<Key, Object> { 303 // eh, needed to silent the gods 304 private static final long serialVersionUID = 1L; 305 306 // a node in a linked list of WeakReference(s) to ClassValueMap(s) 307 private static final class WeakNode extends WeakReference<ClassValueMap> { 308 WeakNode next; 309 WeakNode(ClassValueMap map) { super(map); } 310 } 311 312 // the head of the linked list of WeakReference(s) to ClassValueMap(s) 313 private static final AtomicReference<WeakNode> mapsList = new AtomicReference<>(); 314 315 // the lock used to guard expunging logic 316 private static final AtomicBoolean expungeInProgress = new AtomicBoolean(); 317 318 private ClassValueMap() { 319 super(1); 320 } 321 322 static ClassValueMap create() { 323 ClassValueMap map = new ClassValueMap(); 324 WeakNode node = new WeakNode(map); 325 // register the weakly referenced map into the list 326 do { 327 node.next = mapsList.get(); 328 } while (!mapsList.compareAndSet(node.next, node)); 329 return map; 330 } 331 332 static void expungeStaleEntries() { 333 // make sure only one thread at a time is expunging stale entries; 334 // this is important for correctness so that no stale enqueued key 335 // is missed from being removed from any map that might possibly 336 // hold it. 337 if (!expungeInProgress.get() && 338 expungeInProgress.compareAndSet(false, true)) try { 339 expungeStaleEntriesImpl(); 340 } finally { 341 expungeInProgress.set(false); 342 } 343 } 344 345 private static void expungeStaleEntriesImpl() { 346 // start with an empty private list 347 WeakNode first = null, last = null; 348 // iterate Key(s) of GCed ClassValue(s) 349 Key key; 350 while ((key = (Key) Key.queue.poll()) != null) { 351 // steal any (newly) registered map(s) from the shared 'mapsList' 352 // as they might already be holding the stale 'key' that has just 353 // been removed from the queue. The following guarantees that 354 // no (stale-key, live-map) combination is missed: 355 // - a map is 1st registered into the mapsList and then non-stale 356 // keys are inserted into it 357 // - a non-stale key becomes stale when a ClassValue that it 358 // phantomly references is GCed; the key is then enqueued 359 // - a stale key is 1st removed from the queue and then mapsList 360 // is checked for any (newly) registered map(s) 361 if (mapsList.get() != null) { 362 WeakNode stolen = mapsList.getAndSet(null); 363 // add them to the end of current private list 364 if (last != null) { 365 last.next = stolen; 366 } else { 367 // assert first == null; 368 first = stolen; 369 } 370 } 371 // iterate the accumulated private list of maps 372 last = null; 373 for (WeakNode node = first; node != null; ) { 374 ClassValueMap map = node.get(); 375 if (map == null) { 376 // Class and its ClassValueMap have already been GCed 377 // -> remove the node from the list 378 if (last == null) { 379 first = node = node.next; 380 } else { 381 last.next = node = node.next; 382 } 383 } else { 384 // ClassValueMap is still alive 385 // -> attempt to remove the key from it 386 map.remove(key); 387 // navigate to next in list 388 last = node; 389 node = node.next; 390 } 391 } 392 // at this time, 'last' points to the last WeakNode in the private 393 // list (if any) and the following always holds: 394 // assert (first == null) == (last == null); 395 } 396 // re-insert the stolen and expunged list of map(s) back into shared 397 // mapsList 398 if (last != null) { 399 do { 400 last.next = mapsList.get(); 401 } while (!mapsList.compareAndSet(last.next, first)); 402 } 403 } 404 } 405 406 /** We need to cas */ 407 private static final Unsafe U = Unsafe.getUnsafe(); 408 private static final long CLASS_VALUE_MAP_OFFSET; 409 410 static { 411 try { 412 CLASS_VALUE_MAP_OFFSET = U.objectFieldOffset( 413 Class.class.getDeclaredField("classValueMap")); 414 } catch (Exception e) { 415 throw new Error(e); 416 } 417 } 418 }