[jmm-dev] jdk9 APIs
Doug Lea
dl at cs.oswego.edu
Mon Aug 10 18:22:05 UTC 2015
It's been a while...
As everyone has surely noticed, progress on revising the core Java
Memory Model stalled after discovering that some new ideas are needed
to deal with out-of-thin-air and related issues in both Java and
C/C++. Some people are pursuing promising approaches, but there is
little chance that a full reformulation will be ready before jdk9 is
released (about a year from now).
However, despite this, jdk9 will include access and fence APIs that
need specs. This is non-negotiable, because the current weird way of
accessing the (mostly existing) underlying JVM functionality via
sun.misc.Unsafe is going away. (Actually, planned to only partly go
away in jdk9, but also introducing classes/methods allowing future
decomission.)
For accesses (mostly) corresponding to C11 atomics with memory_order,
the alternatives reside in "VarHandles". These are more-or-less
similar to AtomicXFieldUpdaters, but are designed to support
generation of much better code (without dynamic/reflective baggage),
generally as good as handcrafting, at least after warmup. The setup
for them is unusual -- relying on just-in-time specialization of
generic wrappers. This is a scale-down in ambition compared to the
original "enhanced volatiles" proposal that would have required
language syntax changes that met opposition.
Plans are to also include a stand-alone Fences class with all-static
methods. (Deja vu for many of us.) Plus to separately add the
reachabilityFence/keepAlive method discussed last year as a static
method most likely in class java.lang.ref.Reference.
There seems to be only a little room for discussion on the exact sets
of methods in the VarHandle* and Fences classes:
Current versions of VarHandle do NOT include an analog of C11
"consume" mode. As discussed last year, considering its uncertain fate
in C/C++, a better tactic might be to support a method of the form
"getDependently(ref)" (sorta like in the linux kernel) that covers its
{only? main?} use case. But for now omitted.
For Fences, adding plain StoreStore and LoadLoad fences to the set
acquireFence, ReleaseFence, and fullFence seems wise. The main
arguments against LoadLoad and StoreStore in C11 were usability
concerns. But they have been found to be useful enough internally to
JVMs (mainly on ARM) to be semi-supported within hotspot. And we'd
like to not keep making the same mistake of unnecessarily making
things ARM/POWER hostile.
But the main issue at hand is how we can provide library specs for the
APIs without revising the underlying Java Memory Model.
My proposal is that we muddle through. Doing so seems surprisingly
workable: Moded accesses and fences allow programmers to rule out some
behaviors. Specifying them need not spell out underlying rules that
hold when these methods are not used. And on the other side, they need
not promise any overall property (as in: it might be the case that
using a fullFence between every access gives you SC, but we don't need
to guarantee it.) It is in a sense cheating to convey this in method
specs by using terms that are not fully backed by a formal underlying
model. But they still can be made good enough for readers to
understand intent, and made more rigorous someday. We can and should
also comfort programmers that, when applicable, the primary effects
of these methods are compatible with C/C++. Given all this, the
specs can be pretty simple. They are done out for Fences below, and
if OK should not be hard to apply to VarHandle methods.
Other ideas are of course welcome.
Pasted below are preliminary versions. If they don't format
nicely in your mail reader, get them at
http://gee.cs.oswego.edu/dl/wwwtmp/Fodder.java
/**
* 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 stemming 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 semantics 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 semantics 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 semantics 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 sample VHUsages {
int aField;
static Varhandle AFIELD = ...;
void usage1() {
int aFieldValue = AFIELD.getVolatile(this);
}
}
/**
* Stand-in for spec purposes of jdk9 java.lang.invoke.VarHandle
*/
abstract class NotReallyVarHandle<T> {
// Load
T getRelaxed(Object owner);
T getAcquire(Object owner);
T getVolatile(Object owner);
// tbd: Consume analog
// Store
void setRelaxed(Object owner, T val);
void setRelease(Object owner, T val);
void setVolatile(Object owner, T val);
// CAS
boolean compareAndSet(Object owner, T cmp, T val);
boolean compareAndSetAcquire(Object owner, T cmp, T val);
boolean compareAndSetRelease(Object owner, T cmp, T val);
boolean weakCompareAndSet(Object owner, T cmp, T val);
boolean weakCompareAndSetAcquire(Object owner, T cmp, T val);
boolean weakCompareAndSetRelease(Object owner, T cmp, T val);
// special RMW
T getAndSet(Object owner, T val);
T getAndAdd(Object owner, T delta);
T addAndGet(Object owner, T delta);
}
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 jmm-dev
mailing list