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