1/*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7package java.util.concurrent.atomic;
8import dalvik.system.VMStack; // android-added
9import sun.misc.Unsafe;
10import java.lang.reflect.Field;
11import java.lang.reflect.Modifier;
12
13/**
14 * A reflection-based utility that enables atomic updates to
15 * designated {@code volatile} reference fields of designated
16 * classes.  This class is designed for use in atomic data structures
17 * in which several reference fields of the same node are
18 * independently subject to atomic updates. For example, a tree node
19 * might be declared as
20 *
21 *  <pre> {@code
22 * class Node {
23 *   private volatile Node left, right;
24 *
25 *   private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
26 *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
27 *   private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
28 *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
29 *
30 *   Node getLeft() { return left;  }
31 *   boolean compareAndSetLeft(Node expect, Node update) {
32 *     return leftUpdater.compareAndSet(this, expect, update);
33 *   }
34 *   // ... and so on
35 * }}</pre>
36 *
37 * <p>Note that the guarantees of the {@code compareAndSet}
38 * method in this class are weaker than in other atomic classes.
39 * Because this class cannot ensure that all uses of the field
40 * are appropriate for purposes of atomic access, it can
41 * guarantee atomicity only with respect to other invocations of
42 * {@code compareAndSet} and {@code set} on the same updater.
43 *
44 * @since 1.5
45 * @author Doug Lea
46 * @param <T> The type of the object holding the updatable field
47 * @param <V> The type of the field
48 */
49public abstract class AtomicReferenceFieldUpdater<T,V> {
50
51    /**
52     * Creates and returns an updater for objects with the given field.
53     * The Class arguments are needed to check that reflective types and
54     * generic types match.
55     *
56     * @param tclass the class of the objects holding the field
57     * @param vclass the class of the field
58     * @param fieldName the name of the field to be updated
59     * @return the updater
60     * @throws IllegalArgumentException if the field is not a volatile reference type
61     * @throws RuntimeException with a nested reflection-based
62     * exception if the class does not hold field or is the wrong type,
63     * or the field is inaccessible to the caller according to Java language
64     * access control
65     */
66    public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
67        return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
68                                                        vclass,
69                                                        fieldName);
70    }
71
72    /**
73     * Protected do-nothing constructor for use by subclasses.
74     */
75    protected AtomicReferenceFieldUpdater() {
76    }
77
78    /**
79     * Atomically sets the field of the given object managed by this updater
80     * to the given updated value if the current value {@code ==} the
81     * expected value. This method is guaranteed to be atomic with respect to
82     * other calls to {@code compareAndSet} and {@code set}, but not
83     * necessarily with respect to other changes in the field.
84     *
85     * @param obj An object whose field to conditionally set
86     * @param expect the expected value
87     * @param update the new value
88     * @return true if successful
89     */
90    public abstract boolean compareAndSet(T obj, V expect, V update);
91
92    /**
93     * Atomically sets the field of the given object managed by this updater
94     * to the given updated value if the current value {@code ==} the
95     * expected value. This method is guaranteed to be atomic with respect to
96     * other calls to {@code compareAndSet} and {@code set}, but not
97     * necessarily with respect to other changes in the field.
98     *
99     * <p><a href="package-summary.html#weakCompareAndSet">May fail
100     * spuriously and does not provide ordering guarantees</a>, so is
101     * only rarely an appropriate alternative to {@code compareAndSet}.
102     *
103     * @param obj An object whose field to conditionally set
104     * @param expect the expected value
105     * @param update the new value
106     * @return true if successful
107     */
108    public abstract boolean weakCompareAndSet(T obj, V expect, V update);
109
110    /**
111     * Sets the field of the given object managed by this updater to the
112     * given updated value. This operation is guaranteed to act as a volatile
113     * store with respect to subsequent invocations of {@code compareAndSet}.
114     *
115     * @param obj An object whose field to set
116     * @param newValue the new value
117     */
118    public abstract void set(T obj, V newValue);
119
120    /**
121     * Eventually sets the field of the given object managed by this
122     * updater to the given updated value.
123     *
124     * @param obj An object whose field to set
125     * @param newValue the new value
126     * @since 1.6
127     */
128    public abstract void lazySet(T obj, V newValue);
129
130    /**
131     * Gets the current value held in the field of the given object managed
132     * by this updater.
133     *
134     * @param obj An object whose field to get
135     * @return the current value
136     */
137    public abstract V get(T obj);
138
139    /**
140     * Atomically sets the field of the given object managed by this updater
141     * to the given value and returns the old value.
142     *
143     * @param obj An object whose field to get and set
144     * @param newValue the new value
145     * @return the previous value
146     */
147    public V getAndSet(T obj, V newValue) {
148        for (;;) {
149            V current = get(obj);
150            if (compareAndSet(obj, current, newValue))
151                return current;
152        }
153    }
154
155    private static final class AtomicReferenceFieldUpdaterImpl<T,V>
156        extends AtomicReferenceFieldUpdater<T,V> {
157        private static final Unsafe unsafe = Unsafe.getUnsafe();
158        private final long offset;
159        private final Class<T> tclass;
160        private final Class<V> vclass;
161        private final Class<?> cclass;
162
163        /*
164         * Internal type checks within all update methods contain
165         * internal inlined optimizations checking for the common
166         * cases where the class is final (in which case a simple
167         * getClass comparison suffices) or is of type Object (in
168         * which case no check is needed because all objects are
169         * instances of Object). The Object case is handled simply by
170         * setting vclass to null in constructor.  The targetCheck and
171         * updateCheck methods are invoked when these faster
172         * screenings fail.
173         */
174
175        AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
176                                        Class<V> vclass,
177                                        final String fieldName) {
178            final Field field;
179            final Class<?> fieldClass;
180            final Class<?> caller;
181            final int modifiers;
182            try {
183                field = tclass.getDeclaredField(fieldName); // android-changed
184                caller = VMStack.getStackClass2(); // android-changed
185                modifiers = field.getModifiers();
186            // BEGIN android-removed
187            //     sun.reflect.misc.ReflectUtil.ensureMemberAccess(
188            //         caller, tclass, null, modifiers);
189            //     ClassLoader cl = tclass.getClassLoader();
190            //     ClassLoader ccl = caller.getClassLoader();
191            //     if ((ccl != null) && (ccl != cl) &&
192            //         ((cl == null) || !isAncestor(cl, ccl))) {
193            //       sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
194            //     }
195            // END android-removed
196                fieldClass = field.getType();
197            // BEGIN android-removed
198            // } catch (PrivilegedActionException pae) {
199            //     throw new RuntimeException(pae.getException());
200            // END android-removed
201            } catch (Exception ex) {
202                throw new RuntimeException(ex);
203            }
204
205            if (vclass != fieldClass)
206                throw new ClassCastException();
207
208            if (!Modifier.isVolatile(modifiers))
209                throw new IllegalArgumentException("Must be volatile type");
210
211            this.cclass = (Modifier.isProtected(modifiers) &&
212                           caller != tclass) ? caller : null;
213            this.tclass = tclass;
214            if (vclass == Object.class)
215                this.vclass = null;
216            else
217                this.vclass = vclass;
218            offset = unsafe.objectFieldOffset(field);
219        }
220
221        // BEGIN android-removed
222        // /**
223        //  * Returns true if the second classloader can be found in the first
224        //  * classloader's delegation chain.
225        //  * Equivalent to the inaccessible: first.isAncestor(second).
226        //  */
227        //
228        // private static boolean isAncestor(ClassLoader first, ClassLoader second) {
229        //     ClassLoader acl = first;
230        //     do {
231        //         acl = acl.getParent();
232        //         if (second == acl) {
233        //             return true;
234        //        }
235        //     } while (acl != null);
236        //     return false;
237        // }
238        // END android-removed
239
240        void targetCheck(T obj) {
241            if (!tclass.isInstance(obj))
242                throw new ClassCastException();
243            if (cclass != null)
244                ensureProtectedAccess(obj);
245        }
246
247        void updateCheck(T obj, V update) {
248            if (!tclass.isInstance(obj) ||
249                (update != null && vclass != null && !vclass.isInstance(update)))
250                throw new ClassCastException();
251            if (cclass != null)
252                ensureProtectedAccess(obj);
253        }
254
255        public boolean compareAndSet(T obj, V expect, V update) {
256            if (obj == null || obj.getClass() != tclass || cclass != null ||
257                (update != null && vclass != null &&
258                 vclass != update.getClass()))
259                updateCheck(obj, update);
260            return unsafe.compareAndSwapObject(obj, offset, expect, update);
261        }
262
263        public boolean weakCompareAndSet(T obj, V expect, V update) {
264            // same implementation as strong form for now
265            if (obj == null || obj.getClass() != tclass || cclass != null ||
266                (update != null && vclass != null &&
267                 vclass != update.getClass()))
268                updateCheck(obj, update);
269            return unsafe.compareAndSwapObject(obj, offset, expect, update);
270        }
271
272        public void set(T obj, V newValue) {
273            if (obj == null || obj.getClass() != tclass || cclass != null ||
274                (newValue != null && vclass != null &&
275                 vclass != newValue.getClass()))
276                updateCheck(obj, newValue);
277            unsafe.putObjectVolatile(obj, offset, newValue);
278        }
279
280        public void lazySet(T obj, V newValue) {
281            if (obj == null || obj.getClass() != tclass || cclass != null ||
282                (newValue != null && vclass != null &&
283                 vclass != newValue.getClass()))
284                updateCheck(obj, newValue);
285            unsafe.putOrderedObject(obj, offset, newValue);
286        }
287
288        @SuppressWarnings("unchecked")
289        public V get(T obj) {
290            if (obj == null || obj.getClass() != tclass || cclass != null)
291                targetCheck(obj);
292            return (V)unsafe.getObjectVolatile(obj, offset);
293        }
294
295        private void ensureProtectedAccess(T obj) {
296            if (cclass.isInstance(obj)) {
297                return;
298            }
299            throw new RuntimeException(
300                new IllegalAccessException("Class " +
301                    cclass.getName() +
302                    " can not access a protected member of class " +
303                    tclass.getName() +
304                    " using an instance of " +
305                    obj.getClass().getName()
306                )
307            );
308        }
309    }
310}
311