--- a/jdk/src/share/classes/java/dyn/ClassValue.java Wed Jul 05 17:38:31 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/*
- * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.dyn;
-
-import java.util.WeakHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.lang.reflect.UndeclaredThrowableException;
-
-/**
- * Lazily associate a computed value with (potentially) every type.
- * 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 {@code ClassValue} to cache information needed to
- * perform the message send quickly, for each class encountered.
- * @author John Rose, JSR 292 EG
- */
-public abstract class ClassValue<T> {
- /**
- * Compute the given class's derived value for this {@code ClassValue}.
- * <p>
- * This method will be invoked within the first thread that accesses
- * the value with the {@link #get get} method.
- * <p>
- * Normally, this method is invoked at most once per class,
- * but it may be invoked again if there has been a call to
- * {@link #remove remove}.
- * <p>
- * If this method throws an exception, the corresponding call to {@code get}
- * will terminate abnormally with that exception, and no class value will be recorded.
- *
- * @param type the type whose class value must be computed
- * @return the newly computed value associated with this {@code ClassValue}, for the given class or interface
- * @see #get
- * @see #remove
- */
- protected abstract T computeValue(Class<?> type);
-
- /**
- * Returns the value for the given class.
- * If no value has yet been computed, it is obtained by
- * an invocation of the {@link #computeValue computeValue} method.
- * <p>
- * The actual installation of the value on the class
- * is performed atomically.
- * At that point, if several racing threads have
- * computed values, one is chosen, and returned to
- * all the racing threads.
- * <p>
- * The {@code type} parameter is typically a class, but it may be any type,
- * such as an interface, a primitive type (like {@code int.class}), or {@code void.class}.
- * <p>
- * In the absence of {@code remove} calls, a class value has a simple
- * state diagram: uninitialized and initialized.
- * When {@code remove} calls are made,
- * the rules for value observation are more complex.
- * See the documentation for {@link #remove remove} for more information.
- *
- * @param type the type whose class value must be computed or retrieved
- * @return the current value associated with this {@code ClassValue}, for the given class or interface
- * @throws NullPointerException if the argument is null
- * @see #remove
- * @see #computeValue
- */
- public T get(Class<?> type) {
- ClassValueMap map = getMap(type);
- if (map != null) {
- Object x = map.get(this);
- if (x != null) {
- return (T) map.unmaskNull(x);
- }
- }
- return setComputedValue(type);
- }
-
- /**
- * Removes the associated value for the given class.
- * If this value is subsequently {@linkplain #get read} for the same class,
- * its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
- * This may result in an additional invocation of the
- * {@code computeValue computeValue} method for the given class.
- * <p>
- * In order to explain the interaction between {@code get} and {@code remove} calls,
- * we must model the state transitions of a class value to take into account
- * the alternation between uninitialized and initialized states.
- * To do this, number these states sequentially from zero, and note that
- * uninitialized (or removed) states are numbered with even numbers,
- * while initialized (or re-initialized) states have odd numbers.
- * <p>
- * When a thread {@code T} removes a class value in state {@code 2N},
- * nothing happens, since the class value is already uninitialized.
- * Otherwise, the state is advanced atomically to {@code 2N+1}.
- * <p>
- * When a thread {@code T} queries a class value in state {@code 2N},
- * the thread first attempts to initialize the class value to state {@code 2N+1}
- * by invoking {@code computeValue} and installing the resulting value.
- * <p>
- * When {@code T} attempts to install the newly computed value,
- * if the state is still at {@code 2N}, the class value will be initialized
- * with the computed value, advancing it to state {@code 2N+1}.
- * <p>
- * Otherwise, whether the new state is even or odd,
- * {@code T} will discard the newly computed value
- * and retry the {@code get} operation.
- * <p>
- * Discarding and retrying is an important proviso,
- * since otherwise {@code T} could potentially install
- * a disastrously stale value. For example:
- * <ul>
- * <li>{@code T} calls {@code CV.get(C)} and sees state {@code 2N}
- * <li>{@code T} quickly computes a time-dependent value {@code V0} and gets ready to install it
- * <li>{@code T} is hit by an unlucky paging or scheduling event, and goes to sleep for a long time
- * <li>...meanwhile, {@code T2} also calls {@code CV.get(C)} and sees state {@code 2N}
- * <li>{@code T2} quickly computes a similar time-dependent value {@code V1} and installs it on {@code CV.get(C)}
- * <li>{@code T2} (or a third thread) then calls {@code CV.remove(C)}, undoing {@code T2}'s work
- * <li> the previous actions of {@code T2} are repeated several times
- * <li> also, the relevant computed values change over time: {@code V1}, {@code V2}, ...
- * <li>...meanwhile, {@code T} wakes up and attempts to install {@code V0}; <em>this must fail</em>
- * </ul>
- * We can assume in the above scenario that {@code CV.computeValue} uses locks to properly
- * observe the time-dependent states as it computes {@code V1}, etc.
- * This does not remove the threat of a stale value, since there is a window of time
- * between the return of {@code computeValue} in {@code T} and the installation
- * of the the new value. No user synchronization is possible during this time.
- *
- * @param type the type whose class value must be removed
- * @throws NullPointerException if the argument is null
- */
- public void remove(Class<?> type) {
- ClassValueMap map = getMap(type);
- if (map != null) {
- synchronized (map) {
- map.remove(this);
- }
- }
- }
-
- /// Implementation...
-
- // The hash code for this type is based on the identity of the object,
- // and is well-dispersed for power-of-two tables.
- /** @deprecated This override, which is implementation-specific, will be removed for PFD. */
- public final int hashCode() { return hashCode; }
- private final int hashCode = HASH_CODES.getAndAdd(0x61c88647);
- private static final AtomicInteger HASH_CODES = new AtomicInteger();
-
- private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
-
- /** Slow path for {@link #get}. */
- private T setComputedValue(Class<?> type) {
- ClassValueMap map = getMap(type);
- if (map == null) {
- map = initializeMap(type);
- }
- T value = computeValue(type);
- STORE_BARRIER.lazySet(0);
- // All stores pending from computeValue are completed.
- synchronized (map) {
- // Warm up the table with a null entry.
- map.preInitializeEntry(this);
- }
- STORE_BARRIER.lazySet(0);
- // All stores pending from table expansion are completed.
- synchronized (map) {
- value = (T) map.initializeEntry(this, value);
- // One might fear a possible race condition here
- // if the code for map.put has flushed the write
- // to map.table[*] before the writes to the Map.Entry
- // are done. This is not possible, since we have
- // warmed up the table with an empty entry.
- }
- return value;
- }
-
- // Replace this map by a per-class slot.
- private static final WeakHashMap<Class<?>, ClassValueMap> ROOT
- = new WeakHashMap<Class<?>, ClassValueMap>();
-
- private static ClassValueMap getMap(Class<?> type) {
- return ROOT.get(type);
- }
-
- private static ClassValueMap initializeMap(Class<?> type) {
- synchronized (ClassValue.class) {
- ClassValueMap map = ROOT.get(type);
- if (map == null)
- ROOT.put(type, map = new ClassValueMap());
- return map;
- }
- }
-
- static class ClassValueMap extends WeakHashMap<ClassValue, Object> {
- /** Make sure this table contains an Entry for the given key, even if it is empty. */
- void preInitializeEntry(ClassValue key) {
- if (!this.containsKey(key))
- this.put(key, null);
- }
- /** Make sure this table contains a non-empty Entry for the given key. */
- Object initializeEntry(ClassValue key, Object value) {
- Object prior = this.get(key);
- if (prior != null) {
- return unmaskNull(prior);
- }
- this.put(key, maskNull(value));
- return value;
- }
-
- Object maskNull(Object x) {
- return x == null ? this : x;
- }
- Object unmaskNull(Object x) {
- return x == this ? null : x;
- }
- }
-}