JDK-8161444 : VarHandles should provide access bitwise atomics
  • Type: Sub-task
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Affected Version: 9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2016-07-15
  • Updated: 2017-05-17
  • Resolved: 2016-09-01
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b135Fixed
Related Reports
Blocks :  
Description
VarHandles provide safe and efficient access to atomic operations commonly available on modern processors.  Since single-bit test-and-operate operations are common, VarHandles should support them.

Current processors (led by x86) support CAS (cmpxchg), fetch-and-add (xadd), and single-bit test-and-set, -clear, and -flip (bts, btr, btc).  The single-bit ops should be represented explicitly, because they are difficult for an optimizer to derive from an equivalent CAS-loop.

Proposed API addition:

/**
* Atomically loads the bit at the specified {@code index} in a variable with
* the memory semantics of {@link #getAcquire}; if the bit is clear,
* sets it with the memory semantics of {@link #set}; and finally returns
* the original bit value as a boolean.
*
* <p>The variable may be of any primitive type.
* Bits are numbered from zero, which refers to the arithmetically
* least-significant bit, to {@code N-1} inclusive, where {@code N} is
* the number of bits in the variable.  Booleans have exactly one bit,
* while other variables have an appropriate multiple of eight bits.
*
* <p>The method signature is of the form {@code (CT, int index)boolean}.
*
* <p>The symbolic type descriptor at the call site of {@code testAndSetBitAcquire}
* must match the access mode type that is the result of calling
* {@code accessModeType(VarHandle.AccessMode.TEST_AND_SET_BIT_ACQUIRE)} on this
* VarHandle.
*
* @implNote The effects of this method are similar to a call to
* {@code get} and {@code compareAndExchangeAcquire}, where the new
* value is obtained from the old value by setting the specified bit.
* The full effect of {@code testAndSetBitAcquire} would be obtained
* by retrying the sequence as needed until the bit is either observed
* to be set, or updated to be set.  More efficient implementations may
* be available on some platforms.
*
* @param args the signature-polymorphic parameter list of the form
* {@code (CT, int index)}
* , statically represented using varargs.
* @return a boolean, the original value of the bit (before any update)
* , statically represented using {@code Object}.
* @throws UnsupportedOperationException if the access mode is unsupported
* for this VarHandle.
* @throws WrongMethodTypeException if the access mode type is not
* compatible with the caller's symbolic type descriptor.
* @throws ClassCastException if the access mode type is compatible with the
* caller's symbolic type descriptor, but a reference cast fails.
* @throws ClassCastException if the access mode type is compatible with the
* caller's symbolic type descriptor, but a reference cast fails.
* @throws IllegalArgumentException if the supplied index is not in the range
* of zero (inclusive) to the number of bits in the variable (exclusive).
* @see #getAcquire(Object...)
* @see #set(Object...)
* @see #compareAndExchangeAcquire(Object...)
*/
public final native
@MethodHandle.PolymorphicSignature
@HotSpotIntrinsicCandidate
Object testAndSetBitAcquire(Object... args);

/**
* Atomically loads the bit at the specified {@code index} in a variable with
* the memory semantics of {@link #get}; if the bit is set,
* clears it with the memory semantics of {@link #setRelease}; and finally returns
* the original bit value as a boolean.
*
* ........................
* @see #get(Object...)
* @see #setRelease(Object...)
* @see #compareAndExchangeRelease(Object...)
*/
public final native
@MethodHandle.PolymorphicSignature
@HotSpotIntrinsicCandidate
Object testAndClearBitRelease(Object... args);

/**
* Atomically loads the bit at the specified {@code index} in a variable with
* the memory semantics of {@link #getVolatile}, and stores the complement of
* the bit with the memory semantics of {@link #setVolatile}, returning the
* updated bit value as a boolean.
*
* ........................
* @see #getVolatile(Object...)
* @see #setVolatile(Object...)
* @see #compareAndExchange(Object...)
*/
public final native
@MethodHandle.PolymorphicSignature
@HotSpotIntrinsicCandidate
Object flipAndGetBit(Object... args);


Discussion:

To keep the number of entry points down, only the
acquire version of testAndSet is supplied.
The assumption here is that a lock's critical section
state will be expressed as a set bit.

The testAndClearRelease is supplied by symmetry,
although it is unusual for a lock release operation to
be conditional.

A fuller set of entry points could be added,
though they are not needed for simple use cases like
simple locks (seq-locks) with tag bits.  These could be:
 - testAndClearBitAcquire
 - testAndSetBitRelease
 - getAndBitwise{And,Or,Xor}{,Acquire,Release}
 - testAnd{Set,Clear,Flip}Bit (with explicit memory order parameters)
 - getAndBitwise{And,Or,Xor} (with explicit memory order parameters)

The index parameter maps directly to an instruction operand on x86.
Adding explicit range checking on it is in the spirit of Java, and will cost nothing if the index value is constant.