jdk9 VarHandle and Fence methods

Gil Tene gil at azulsystems.com
Sat Aug 22 17:54:18 UTC 2015


Its' great to see storeStoreFence() and loadLoadFence() in the Fences class.

For completeness, I would really like to see loadStoreFence() and storeLoadFence() there as well. I realize that they are implicitly available via the combination fences (acquire, release, and full), but it is "strange" to have just the first two without providing the complete set. There are certainly cases where all you need is a StoreLoad or a LoadStore, and forcing the other unneeded fences in combination reduces potential compiler optimizations on that code.

— Gil.

> On Aug 21, 2015, at 7:24 AM, Doug Lea <dl at cs.oswego.edu> wrote:
> 
> 
> For those of you who haven't been following this on the jmm-dev list
> or follow-ups on concurrency-interest:
> 
> We are NOT planning a full JMM memory model update for jdk9 -- there
> are still unresolved issues in revising the formal core model.
> However, jdk9 will include APIs for VarHandles (a scaled-down version of
> the "enhanced volatiles" JEP), that together with some other
> support replaces the need to use of Unsafe to obtain these
> effects and does so compatibly with C/C++11 atomics. To do this, we
> must, until the next full JMM update, provide specs that are
> clear to readers (at least those familiar with the underlying
> concepts) but not formally tied to a base model, (Which limits
> how much we can say in them.)
> 
> The tentative methods are pasted below and also at
>  http://gee.cs.oswego.edu/dl/wwwtmp/Fodder.java
> The javadocs currently do not include any examples helping to
> explain why you would ever want to use any of these methods.
> 
> The actual VarHandle class will look a bit different because
> it will rely on specializations of polymorphic signatures.
> (Current versions can be found in the openjdk mercurial
> "jdk9/sandbox" repo.) And the "Fences" method may end up
> in a different java.lang.* utility class. We'd also retrofit
> j.u.c.atomic.Atomic* classes to use compatible methods/names.
> 
> Comments welcome.
> 
> ...
> 
> /**
> * Stand-in for spec purposes of jdk9 java.lang.invoke.VarHandle
> */
> abstract class NotReallyVarHandle<T> {
>    // Load
> 
>    /**
>     * Returns the value, with memory semantics of reading a
>     * non-volatile variable.
>     *
>     * @return the value
>     */
>    T getRelaxed(Object owner);
> 
>    /**
>     * Returns the value, with memory semantics of reading a volatile
>     * variable.
>     *
>     * @return the value
>     */
>    T getVolatile(Object owner);
> 
>    /**
>     * Returns the value, and ensures that subsequent loads and stores
>     * are not reordered before this access.
>     *
>     * @apiNote Ignoring the many semantic differences from C and
>     * C++, this method has memory ordering effects compatible with
>     * memory_order_acquire ordering.
>     *
>     * @return the value
>     */
>    T getAcquire(Object owner);
> 
>    /**
>     * Returns the value, accessed in program order, but with no
>     * assurance of memory ordering effects with respect to other
>     * threads.
>     *
>     * @return the value
>     */
>    T getOpaque(Object owner);
> 
>    // Store
> 
>    /**
>     * Sets the value, with memory semantics of setting a non-volatile
>     * variable.
>     *
>     * @param val the new value
>     */
>    void setRelaxed(Object owner, T val);
> 
>    /**
>     * Sets the value, with memory semantics of setting a volatile
>     * variable.
>     *
>     * @apiNote Ignoring the many semantic differences from C and
>     * C++, this method has memory ordering effects compatible with
>     * memory_order_seq_cst.
>     *
>     * @param val the new value
>     */
>    void setVolatile(Object owner, T val);
> 
>    /**
>     * Sets the value, and ensures that prior loads and stores are not
>     * reordered after this access.
>     *
>     * @apiNote Ignoring the many semantic differences from C and
>     * C++, this method has memory ordering effects compatible with
>     * memory_order_release ordering.
>     *
>     * @param val the new value
>     */
>    void setRelease(Object owner, T val);
> 
>    /**
>     * Sets the value, in program order, but with no assurance of
>     * memory ordering effects with respect to other threads.
>     *
>     * @param val the new value
>     */
>    void setOpaque(Object owner, T val);
> 
>    // CAS
> 
>    /**
>     * Atomically sets the value to the given updated value with the
>     * memory semantics of setVolatile if the current value {@code ==}
>     * the expected value, as accessed with the memory semantics of
>     * getVolatile.
>     *
>     * @param expected the expected value
>     * @param val the new value
>     * @return {@code true} if successful. False return indicates that
>     * the actual value was not equal to the expected value.
>     */
>    boolean compareAndSet(Object owner, T expected, T val);
> 
>    // Value-returning compare and exchange
> 
>    /**
>     * Atomically sets the value to the given updated value with the
>     * memory semantics of setVolatile if the current value {@code ==}
>     * the expected value, as accessed with the memory semantics of
>     * getVolatile.
>     *
>     * @param expected the expected value
>     * @param val the new value
>     * @return the current value, which will be the same as {@code val} if
>     * successful.
>     */
>    T compareAndExchangeVolatile(Object owner, T expected, T val);
> 
>    /**
>     * Atomically sets the value to the given updated value with the
>     * memory semantics of setRelaxed if the current value {@code ==}
>     * the expected value, as accessed with the memory semantics of
>     * getAcquire.
>     *
>     * @param expected the expected value
>     * @param val the new value
>     * @return the current value, which will be the same as {@code val} if
>     * successful.
>     */
>    T compareAndExchangeAcquire(Object owner, T expected, T val);
> 
>    /**
>     * Atomically sets the value to the given updated value with the
>     * memory semantics of setRelease if the current value {@code ==}
>     * the expected value, as accessed with the memory samantics of
>     * getRelease.
>     *
>     * @param expected the expected value
>     * @param val the new value
>     * @return the current value, which will be the same as {@code val} if
>     * successful.
>     */
>    T compareAndExchangeRelease(Object owner, T expected, T val);
> 
>    // Weak (spurious failures allowed)
> 
>    /**
>     * Possibly atomically sets the value to the given updated value
>     * with the semantics of setRelaxed if the current value {@code
>     * ==} the expected value, as as accessed with the memory
>     * semantics of getRelaxed.  This operation may fail spuriously
>     * (typically, due to memory contention) even if the current value
>     * does match the expected value.
>     *
>     * @param expected the expected value
>     * @param val the new value
>     * @return {@code true} if successful
>     */
>    boolean weakCompareAndSetRelaxed(Object owner, T expected, T val);
> 
>    /**
>     * Possibly atomically sets the value to the given updated value
>     * with the memory semantics of setRelaxed if the current value
>     * {@code ==} the expected value, as as accessed with the memory
>     * semantics of getAcquire.  This operation may fail spuriously
>     * (typically, due to memory contention) even if the current value
>     * does match the expected value.
>     *
>     * @param expected the expected value
>     * @param val the new value
>     * @return {@code true} if successful
>     */
>    boolean weakCompareAndSetAcquire(Object owner, T expected, T val);
> 
>    /**
>     * Possibly atomically sets the value to the given updated value
>     * with the memory semantics of setRelease if the current value
>     * {@code ==} the expected value, as as accessed with the memory
>     * semantics of getRelaxed.  This operation may fail spuriously
>     * (typically, due to memory contention) even if the current value
>     * does match the expected value.
>     *
>     * @param expected the expected value
>     * @param val the new value
>     * @return {@code true} if successful
>     */
>    boolean weakCompareAndSetRelease(Object owner, T expected, T val);
> 
>    // special RMW
> 
>    /**
>     * Atomically sets to the given value with the memory semantics of
>     * setVolatile and returns the old value.
>     *
>     * @param newValue the new value
>     * @return the previous value
>     */
>    T getAndSet(Object owner, T val);
> 
>    /**
>     * Atomically adds the given value to the current value with the
>     * memory semantics of setVolatile.
>     *
>     * @param delta the value to add
>     * @return the previous value
>     */
>    T getAndAdd(Object owner, T delta);
> 
>    /**
>     * Atomically adds the given value to the current value with the
>     * memory semantics of setVolatile.
>     *
>     * @param delta the value to add
>     * @return the current value
>     */
>    T addAndGet(Object owner, T delta);
> }
> 
> /**
> * A set of methods providing fine-grained control of memory ordering.
> *
> * <p>The Java Language Specification permits operations to be
> * executed in orders different than are apparent in program source
> * code, subject to constraints mainly arising from the use of locks
> * and volatile fields. The methods of this class can also be used to
> * impose constraints. Their specifications are phrased in terms of
> * the lack of "reorderings" -- observable ordering effects that might
> * otherwise occur if the fence were not present.
> *
> * @apiNote More precise phrasing of these specifications may
> * accompany future updates of the Java Language Specification.
> */
> public class Fences {
> 
>    /**
>     * Ensures that loads and stores before the fence will not be
>     * reordered with loads and stores after the fence.
>     *
>     * @apiNote Ignoring the many semantic differences from C and
>     * C++, this method has memory ordering effects compatible with
>     * atomic_thread_fence(memory_order_seq_cst)
>     */
>    public static void fullFence() {}
> 
>    /**
>     * Ensures that loads before the fence will not be reordered with
>     * loads and stores after the fence.
>     *
>     * @apiNote Ignoring the many semantic differences from C and
>     * C++, this method has memory ordering effects compatible with
>     * atomic_thread_fence(memory_order_acquire)
>     */
>    public static void acquireFence() {}
> 
>    /**
>     * Ensures that loads and stores before the fence will not be
>     * reordered with stores after the fence.
>     *
>     * @apiNote Ignoring the many semantic differences from C and
>     * C++, this method has memory ordering effects compatible with
>     * atomic_thread_fence(memory_order_release)
>     */
>    public static void releaseFence() {}
> 
>    /**
>     * Ensures that loads before the fence will not be reordered with
>     * loads after the fence.
>     */
>    public static void loadLoadFence() {}
> 
>    /**
>     * Ensures that stores before the fence will not be reordered with
>     * stores after the fence.
>     */
>    public static void storeStoreFence() {}
> 
> }
> 
> class java.lang.ref.Reference {
>    // add:
> 
>    /**
>     * Ensures that the object referenced by the given reference
>     * remains <em>strongly reachable</em> (as defined in the {@link
>     * java.lang.ref} package documentation), regardless of any prior
>     * actions of the program that might otherwise cause the object to
>     * become unreachable; thus, the referenced object is not
>     * reclaimable by garbage collection at least until after the
>     * invocation of this method. Invocation of this method does not
>     * itself initiate garbage collection or finalization.
>     *
>     * @param ref the reference. If null, this method has no effect.
>     */
>    public static void reachabilityFence(Object ref) {}
> 
> }



More information about the valhalla-dev mailing list