JDK-8046183 : JEP 193: Variable Handles
  • Type: JEP
  • Component: core-libs
  • Sub-Component: java.lang
  • Priority: P2
  • Status: Closed
  • Resolution: Delivered
  • Fix Versions: 9
  • Submitted: 2014-01-06
  • Updated: 2017-08-17
  • Resolved: 2017-08-17
Related Reports
Blocks :  
Relates :  
Relates :  
Relates :  
Relates :  
Sub Tasks
JDK-8077090 :  
Description
Summary
-------

Define a standard means to invoke the equivalents of various
`java.util.concurrent.atomic` and `sun.misc.Unsafe` operations upon
object fields and array elements, a standard set of fence operations for
fine-grained control of memory ordering, and a standard
reachability-fence operation to ensure that a referenced object remains
strongly reachable.

Goals
-----

The following are required goals:

  - Safety. It must not be possible to place the Java Virtual Machine in a
    corrupt memory state.  For example, a field of an object can only be updated
    with instances that are castable to the field type, or an array element can
    only be accessed within an array if the array index is within the array
    bounds.

  - Integrity. Access to a field of an object follows the same access rules as
    with `getfield` and `putfield` byte codes in addition to the constraint that
    a `final` field of an object cannot be updated.  (Note: such safety and
    integrity rules also apply to `MethodHandles` giving read or write access to
    a field.)

  - Performance. The performance characteristics must be the same as or similar
    to equivalent `sun.misc.Unsafe` operations (specifically, generated
    assembler code should be almost identical modulo certain safety checks that
    cannot be folded away).

  - Usability. The API must be better than the `sun.misc.Unsafe` API.

It is desirable, but not required, that the API be as good as the
`java.util.concurrent.atomic` API.


Motivation
----------

As concurrent and parallel programming in Java continue to expand, programmers
are increasingly frustrated by not being able to use Java constructs to arrange
atomic or ordered operations on the fields of individual classes; for example,
atomically incrementing a `count` field.  Until now the only ways to achieve
these effects were to use a stand-alone `AtomicInteger` (adding both space
overhead and additional concurrency issues to manage indirection) or, in some
situations, to use atomic `FieldUpdater`s (often encountering more overhead
than the operation itself), or to use the unsafe (and unportable and
unsupported) `sun.misc.Unsafe` API for JVM intrinsics.  Intrinsics are faster,
so they have become widely used, to the detriment of safety and portability.

Without this JEP, these problems are expected to become worse as atomic APIs
expand to cover additional access-consistency policies (aligned with the recent
C++11 memory model) as part of Java Memory Model revisions.


Description
-----------

A variable handle is a typed reference to a variable, which supports read and
write access to the variable under a variety of access modes.  Supported
variable kinds include instance fields, static fields and array elements.  Other
variable kinds are being considered and may be supported such as array views,
viewing a byte or char array as a long array, and locations in off-heap regions
described by `ByteBuffer`s.

Variable handles require library enhancements, JVM enhancements, and
compiler support.  Additionally, it requires minor updates to the Java Language
Specification and the Java Virtual Machine Specification.  Minor language
enhancements, that enhance compile-time type checking and complement existing
syntax, are also considered.

The resulting specifications are expected to be extensible in natural ways to
additional primitive-like value types or additional array-like types, if they
are ever added to Java.  This is not, however, a general-purpose transaction
mechanism for controlling accesses and updates to multiple variables.
Alternative forms for expressing and implementing such constructs may be
explored in the course of this JEP, and may be the subject of further JEPs.

Variable handles are modelled by a single abstract class,
`java.lang.invoke.VarHandle`, where each variable access mode is
represented by a [signature-polymorphic][jdk-sigpoly] method.
    
[jdk-sigpoly]: http://docs.oracle.com/javase/8/docs/api/java/lang/invoke/MethodHandle.html#sigpoly

The set of access modes represents a minimal viable set and are designed to be 
compatible with C/C++11 atomics without depending on a revised update to the 
Java Memory Model.  Additional access modes will be added if required.  Some 
access modes may not be applicable for certain variable types and, if so, when 
invoked on an associated `VarHandle` instance will throw an 
`UnsupportedOperationException`.

The access modes are grouped into the following categories:

  1. read access modes, such as reading a variable with volatile memory
     ordering effects;

  2. write access modes, such as updating a variable with release memory 
     ordering effects;
  
  3. atomic update access modes, such as a compare-and-set on a variable
     with volatile memory order effects for both read and writing;
  
  4. numeric atomic update access modes, such as get-and-add with plain
     memory order effects for writing and acquire memory order effects
     for reading.
  
  5. bitwise atomic update access modes, such as get-and-bitwise-and 
     with release memory order effects for writing and plain memory 
     order effects for reading.

The later three categories are commonly referred to as read-modify-write
modes.
  
The signature-polymorphic characteristic of the access mode methods enables
variable handles to support many variable kinds and variable types using just
one abstract class.  This avoids an explosion of variable kind and type-specific
classes.  Furthermore, even though the access mode method signatures are
declared as a variable argument array of `Object`, such signature-polymorphic
characteristics ensure there will be no boxing of primitive value arguments and
no packing of arguments into an array.  This enables predictable behaviour and
performance at runtime for the HotSpot interpreter and C1/C2 compilers.

Methods to create `VarHandle` instances are located in the same area as that to
produce `MethodHandle` instances which access equivalent or similar variable
kinds.

Methods to create `VarHandle` instances for instance and static field variable
kinds are located in `java.lang.invoke.MethodHandles.Lookup` and are created
by a process of looking up the field within the associated receiving class.
For example, such lookup to obtain a `VarHandle` for a field named `i` of type
`int` on a receiver class `Foo` might be performed as follows:

    class Foo {
        int i;

        ...
    }

    ...

    class Bar {
        static final VarHandle VH_FOO_FIELD_I;

        static {
            try {
                VH_FOO_FIELD_I = MethodHandles.lookup().
                    in(Foo.class).
                    findVarHandle(Foo.class, "i", int.class);
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    }

The lookup of a `VarHandle` that accesses a field will, before producing and
returning the `VarHandle`, perform the exact same access control checks (on
behalf of the lookup class) as those performed by the lookup up of a
`MethodHandle` that gives read and write access to that same field (see the
`find{,Static}{Getter,Setter}` methods in the `MethodHandles.Lookup` class).

Access mode methods will throw `UnsupportedOperationException` when invoked
under the following conditions:

  - Write access mode methods for a `VarHandle` to a final field.

  - Numeric-based access mode methods (`getAndAdd` and `addAndGet`) for a
    reference variable type or a non-numeric type (such as `boolean`).
    
  - Bitwise-based access mode methods for a reference variable type or 
    the `float` and `double` types (the latter restriction may be removed
    in a future revision)

A field need not be marked as `volatile` for an associated `VarHandle` to
perform volatile access.  In effect, the `volatile` modifier, if present, is
ignored.  This is different to the behaviour of
`java.util.concurrent.atomic.Atomic{Int, Long, Reference}FieldUpdater` where
corresponding fields have to be marked as volatile.  This can be too restrictive
in certain cases where it is known certain volatile accesses are not always
required.

Methods to create `VarHandle` instances for array-based variable types are
located in `java.lang.invoke.MethodHandles` (see the
`arrayElement{Getter, Setter}` methods in the `MethodHandles` class).  For
example, a `VarHandle` to an array of `int` may be created as follows:

    VarHandle intArrayHandle = MethodHandles.arrayElementVarHandle(int[].class);

Access mode methods will throw `UnsupportedOperationException` when invoked
under the following conditions:

  - Numeric-based access mode methods (`getAndAdd` and `addAndGet`) for an
    array component reference variable type or a non-numeric type (such as `boolean`)

  - Bitwise-based access mode methods for a reference variable type or 
    the `float` and `double` types (the latter restriction may be removed
    in a future revision)
    
All primitive types and references types are supported for the variable type
of variable kinds that are instance fields, static fields and array elements.
Other variable kinds may support all or a subset of those types.

Methods to create `VarHandle` instances for array-view-based variable types are
also located in `java.lang.invoke.MethodHandles`.  For example, a `VarHandle`
to view an array of `byte` as an unaligned array of `long` may be created as
follows:

    VarHandle longArrayViewHandle = MethodHandles.byteArrayViewVarHandle(
            long[].class, java.nio.ByteOrder.BIG_ENDIAN);

Although similar mechanisms can be achieved using `java.nio.ByteBuffer`, it
requires that a `ByteBuffer` instance be created wrapping a `byte` array.  This
does not always guarantee reliable performance due to the fragility of
escape analysis and that accesses have to go through the `ByteBuffer` instance.
In the case of unaligned access all but the plain access mode methods will
throw `IllegalStateException`.  For aligned access certain volatile operations, 
depending on the variable type are possible.  Such `VarHandle` instances may be 
utilized to vectorize array access.

The number of arguments, the argument types, and return type of access mode
methods are governed by variable kind, the variable type and the characteristics
of the access mode.  `VarHandle` creation methods (such as those previously
described) will document the requirements.  For example, a `compareAndSet` on
the previously-looked up `VH_FOO_FIELD_I` handle requires 3 arguments, an
instance of receiver `Foo` and two `int`s for the expected and actual values:

    Foo f = ...
    boolean r = VH_FOO_FIELD_I.compareAndSet(f, 0, 1);

In contrast, a `getAndSet` requires 2 arguments, an instance of receiver `Foo`
and one `int` that is the value to be set:

    int o = (int) VH_FOO_FIELD_I.getAndSet(f, 2);

Access to array elements will require an additional argument, of type `int`,
between the receiver and value arguments (if any), that corresponds to the array
index of the element to be operated upon.

For predictable behaviour and performance at runtime `VarHandle` instances
should be held in static final fields (as required for instances of
`Atomic{Int, Long, Reference}FieldUpdater)`.  This ensures that constant folding
will occur for access mode method invocations, such as folding away method
signature checks and/or argument cast checks.

> Note: Future HotSpot enhancements might support constant folding for
`VarHandle`, or `MethodHandle`, instances held in non-static final fields,
 method arguments, or local variables.

A `MethodHandle` may be produced for a `VarHandle` access mode method by using
`MethodHandles.Lookup.findVirtual`.  For example, to produce a `MethodHandle`
to the "compareAndSet" access mode for a particular variable kind and type:

    Foo f = ...
    MethodHandle mhToVhCompareAndSet = MethodHandles.publicLookup().findVirtual(
            VarHandle.class,
            "compareAndSet",
            MethodType.methodType(boolean.class, Foo.class, int.class, int.class));

The `MethodHandle` can then be invoked with a variable kind and type compatible
`VarHandle` instance as the first parameter:

    boolean r = (boolean) mhToVhCompareAndSet.invokeExact(VH_FOO_FIELD_I, f, 0, 1);

Or `mhToVhCompareAndSet` can be bound to the `VarHandle` instance and then
invoked:

    MethodHandle mhToBoundVhCompareAndSet = mhToVhCompareAndSet
            .bindTo(VH_FOO_FIELD_I);
    boolean r = (boolean) mhToBoundVhCompareAndSet.invokeExact(f, 0, 1);

Such a `MethodHandle` lookup using `findVirtual` will perform an `asType` transformation
to adjust arguments and return values.  The behaviour is equivalent to a `MethodHandle`
produced using `MethodHandles.varHandleInvoker`, the analog of MethodHandles.invoker`:

    MethodHandle mhToVhCompareAndSet = MethodHandles.varHandleExactInvoker(
            VarHandle.AccessMode.COMPARE_AND_SET,
            MethodType.methodType(boolean.class, Foo.class, int.class, int.class));

    boolean r = (boolean) mhToVhCompareAndSet.invokeExact(VH_FOO_FIELD_I, f, 0, 1);

Thus a `VarHandle` may be used in erased or reflective scenarios by a 
wrapping class, for example replacing the `Unsafe` usages within the 
`java.util.concurrent.Atomic*FieldUpdater/Atomic*Array` classes. 
(Although further work is required such that the updaters are granted
access to the look up fields in the declaring class.)

The source compilation of an access mode method invocation will follow the same
rules as for signature-polymorphic method invocation to
`MethodHandle.invokeExact` and  `MethodHandle.invoke`.  The following additions
will be required to the Java Language Specification:

  1. Make reference to the signature-polymorphic access mode methods in the
     `VarHandle` class.
  2. Allow signature-polymorphic methods to return types other than Object,
     indicating that the return type is not polymorphic (and would otherwise be
     declared via a cast at the call site).  This makes it easier invoke
     write-based access methods that return void and invoke `compareAndSet` that
     returns a `boolean` value.

It would be desirable, but not a requirement, that source compilation of a
signature-polymorphic method invocation be enhanced to perform target typing of
the polymorphic return type such that an explicit cast is not required.

> Note: a syntax and runtime support for looking up a `MethodHandle` or a
`VarHandle` leveraging the syntax of method references, such as
`VarHandle VH_FOO_FIELD_I = Foo::i` is desirable but not in scope for this JEP.

The runtime invocation of an access mode method invocation will follow similar
rules as for signature-polymorphic method invocation to
`MethodHandle.invokeExact` and  `MethodHandle.invoke`.  The following additions
will be required to the Java Virtual Machine Specification:

  1. Make reference to the signature-polymorphic access mode methods in the
     `VarHandle` class.
  2. Specify `invokevirtual` byte code behaviour of invocation to access mode
     signature-polymorphic methods.  It is anticipated that such behaviour can
     be specified by defining a transformation from the access mode method
     invocation to a `MethodHandle` which is then invoked using `invokeExact`
     with the same parameters (see previous use of
     `MethodHandles.Lookup.findVirtual`).

It is important that the `VarHandle` implementations for the supported variable
kinds, types and access modes are reliably efficient and meet the performance
goals.  Leveraging signature-polymorphic methods helps in terms of avoiding
boxing and array packing.  Implementations will:

  - Reside in the `java.lang.invoke` package where HotSpot treats final fields
    of classes in that package as really final, which enables constant folding
    when the `VarHandle` itself is referenced in a static final field;

  - Leverage the JDK internal annotations `@Stable` for constant folding of
    values that change only once, and `@ForceInline` to ensure methods get
    inlined even if normal inlining thresholds are reached; and

  - Use `sun.misc.Unsafe` for underlying enhanced volatile access.

A couple of HotSpot intrinsics are necessary, some of which are enumerated as 
follows:

  - An intrinsic for `Class.cast`, which has already been added (see
    [JDK-8054492][JDK-8054492]).  Before this intrinsic was added a constant
    folded `Class.cast` would leave behind  redundant checks that may cause
    unnecessary de-optimizations.

[JDK-8054492]: https://bugs.openjdk.java.net/browse/JDK-8054492

  - An intrinsic for an `acquire-get` access mode that can synchronize with an
    intrinsic for a `set-release` access mode (see 
    `sun.misc.Unsafe.putOrdered{Int, Long, Object}`) when concurrently accessing
    variables.

  - Intrinsics for array bounds checks [JDK-8042997][JDK-8042997].  Static
    methods can be added  `java.util.Arrays` that perform such checks and accept
    a function that is invoked to return an exception to be thrown or string
    message, to be included in an exception to be thrown, if the check fails.
    Such intrinsics enable better comparisons using unsigned values (since an
    array length is always positive) and better hoisting of range checks outside
    of unrolled loops over the array elements.

In addition further improvements to range checks by HotSpot have been
implemented ([JDK-8073480][JDK-8073480]) or are needed ([JDK-8003585][JDK-8003585]
to strength reduce range checks in say the fork/join framework or in say
`HashMap` or `ConcurrentHashMap`).

[JDK-8042997]: https://bugs.openjdk.java.net/browse/JDK-8042997
[JDK-8073480]: https://bugs.openjdk.java.net/browse/JDK-8073480
[JDK-8003585]: https://bugs.openjdk.java.net/browse/JDK-8003585

The `VarHandle` implementations should have minimal dependencies on other
classes within the `java.lang.invoke` package to avoid increasing startup time
and to avoid cyclic dependencies occurring during static initialization.  For
example, `ConcurrentHashMap` is used by such classes and if `ConcurrentHashMap`
is modified to use `VarHandles` it needs to be ensured no cyclic dependencies
are introduced.  Other more subtle cycles are possible with the use of
`ThreadLocalRandom` and its use of `AtomicInteger`.  It is also is 
desirable that the C2 HotSpot compilation time is not unduly increased 
for methods containing `VarHandle` method invocations.

### Memory fences

Fenced operations are defined as static methods on the `VarHandle` class and represents a minimal 
viable set for fine grained control of memory ordering.

       /**
        * 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() {}

A full fence is stronger (in terms of ordering guarantees) than an acquire fence 
which is stronger than a load load fence.  Likewise a full fence is stronger than 
a release fence which is stronger than a store store fence.

### Reachability fence

The reachability fence is defined as a static method on 
`java.lang.ref.Reference`:

    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) {}
    
    }

See [JDK-8133348].

It is currently out of scope to provide an annotation, `@Finalized` say, to
be declared on a method, which at either compile or runtime results in as if the
method body was wrapped as follows:

    try {
        <method body>
    } finally {
        Reference.reachabilityFence(this);
    }

It is anticipated that such functionality could be supported by a compile-time 
annotation processor.

[JDK-8133348]: https://bugs.openjdk.java.net/browse/JDK-8133348

Alternatives
------------

Introducing new forms of "value type" were considered that support volatile
operations.  However, this would be inconsistent with properties of other types,
and would also require more effort for programmers to use.   Reliance upon
`java.util.concurrent.atomic` `FieldUpdater`s was also considered, but their
dynamic overhead and usage limitations make them unsuitable.

Several other alternatives, including those based on field references, have been
raised and dismissed as unworkable on syntactic, efficiency, and/or usability
grounds over the many years that these issues have been discussed.

Syntax enhancements were considered in a previous version of this JEP but were
deemed too "magical", with the overloaded use of the `volatile` keyword scoping
to floating interfaces, one for references and one for each supported primitive
type.

Generic types extending from `VarHandle` were considered in a previous version
of this JEP but such an addition, with enhanced polymorphic signatures for
generic types and special treatment of boxed type variables, was considered
immature given a future Java release with value types and generics over
primitives with [JEP 218][jep218], and improved arrays with
[Arrays 2.0][arrays2].

An implementation-specific `invokedynamic` approach was also considered in a
previous version of this JEP.  This required that compiled method calls with
and without `invokedynamic` were carefully aligned to be the same in terms of
semantics.  In addition the use of `invokedynamic` in core classes such as say
`ConcurrentHashMap` will result in cyclic dependencies.

[jep218]: http://openjdk.java.net/jeps/218
[arrays2]: http://cr.openjdk.java.net/~jrose/pres/201207-Arrays-2.pdf


Testing
-------

Stress tests will be developed using the [jcstress][jcstress] harness.

[jcstress]: http://openjdk.java.net/projects/code-tools/jcstress/


Risks and Assumptions
---------------------

A prototype implementation of `VarHandle` has been performance-tested with
nano-benchmarks and fork/join benchmarks, where the fork/join library's use of
`sun.misc.Unsafe` was replaced with `VarHandle`.  No major performance issues
have been observed so far, and the HotSpot compiler issues identified do not
seem onerous (folding cast checks and improving array bounds checks).  We are
therefore confident of the feasibility  of this approach.  However, we expect
that it will require more experimentation to ensure the compilation techniques
are reliable in the performance-critical contexts where these constructs are
most often needed.


Dependences
-----------

The classes in `java.util.concurrent` (and other areas identified in the
JDK) will be migrated from `sun.misc.Unsafe` to `VarHandle`.

This JEP does *not* depend on [JEP 188: Java Memory Model Update][jep188].

[jep188]: http://openjdk.java.net/jeps/188


Comments
FC Extension requested to complete the JEP by the 1st September. Some new feedback has arrived: - addition atomic bitwise operations for volatile/release/acquire memory orderings. - atomic set and atomic get-and-add operations for release/acquire memory orderings. - refactoring of weak compare-and-set methods for a consistent naming scheme, and removal of the atomic add-and-get operation. This work can be implemented without any HotSpot modifications which could follow on later (perhaps in an update release) in terms of adding intrinsics on various platforms.
20-07-2016

FC Extension Request We'd like to ask for an extension of the Feature Complete Due Date to July 14th. Justification: While the feature is integrated, the extra time is needed to sufficiently develop, review and integrate VarHandle-based jcstress tests into the jcstress test repository, expand the types supporting CAS (sub-word and floating point), and accommodate the integration schedule. Note that all enhancements are now pushed to hs-comp, so the extended time is to accommodate the integration schedule. No further enhancements are planned. The compare-and-exchange intrinsics have not been completed for SPARC or AARCH64. ��This does not affect the performance goals of the JEP, which was that the performance characteristics must be the same as or equivalent for sun.misc.Unsafe operations. ��The intrinsic work for those platforms is very targeted and would have limited risk/impact since it will only affect the performance of the compare-and-exchange operation on supported variables (e.g. static/non-static fields) if used on SPARC or AARCH64. ��We believe the risk is limited but per conversation with hotspot SQE, have moved these two subtasks off as separate enhancements, to be proposed after FC when ready.
23-06-2016

I have updated to be precise about the current approach to the design and implementation. Title also updated.
23-06-2015

To move this to "Targeted" it really needs to be more definite. Please update text that discusses uncertainties or different possibilities (e.g., "the target solution may require ...", "two possible solutions to avoid ...", etc.) to describe what you actually plan to do. Now that the design has settled, perhaps it's also time to retitle this JEP to "Variable Handles".
22-06-2015