MemoryHandles (Java SE 14 & JDK 14)
Description: declaration: module: jdk.incubator.foreign, package: jdk.incubator.foreign, class: MemoryHandles
Keywords: jdk.incubator.foreign.MemoryHandles class

Module jdk.incubator.foreign
Package jdk.incubator.foreign

# Class MemoryHandles

java.lang.Object
jdk.incubator.foreign.MemoryHandles

    public final class MemoryHandles
    extends Object

This class defines several factory methods for constructing and combining memory access var handles. To obtain a memory access var handle, clients must start from one of the leaf methods (see `varHandle(Class, ByteOrder)`, `varHandle(Class, long, ByteOrder)`). This determines the variable type (all primitive types but `void` and `boolean` are supported), as well as the alignment constraint and the byte order associated to a memory access var handle. The resulting memory access var handle can then be combined in various ways to emulate different addressing modes. The var handles created by this class feature a mandatory coordinate type (of type `MemoryAddress`), and zero or more `long` coordinate types, which can be used to emulate multi-dimensional array indexing.

As an example, consider the memory layout expressed by a `SequenceLayout` instance constructed as follows:

>     SequenceLayout seq = MemoryLayout.ofSequence(5,
>         MemoryLayout.ofStruct(
>             MemoryLayout.ofPaddingBits(32),
>             MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN).withName("value")
>         ));

To access the member layout named `value`, we can construct a memory access var handle as follows:

>     VarHandle handle = MemoryHandles.varHandle(int.class, ByteOrder.BIG_ENDIAN); //(MemoryAddress) -> int
>     handle = MemoryHandles.withOffset(handle, 4); //(MemoryAddress) -> int
>     handle = MemoryHandles.withStride(handle, 8); //(MemoryAddress, long) -> int

## Addressing mode

The final memory location accessed by a memory access var handle can be computed as follows:

>     address = base + offset

where `base` denotes the address expressed by the `MemoryAddress` access coordinate, and `offset` can be expressed in the following form:

>     offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)

where `x_1`, `x_2`, ... `x_n` are dynamic values provided as optional `long` access coordinates, whereas `c_1`, `c_2`, ... `c_m` and `s_0`, `s_1`, ... `s_n` are static constants which are can be acquired through the `withOffset(VarHandle, long)` and the `withStride(VarHandle, long)` combinators, respectively.

## Alignment and access modes

A memory access var handle is associated with an access size `S` and an alignment constraint `B` (both expressed in bytes). We say that a memory access operation is fully aligned if it occurs at a memory address `A` which is compatible with both alignment constraints `S` and `B`. If access is fully aligned then following access modes are supported and are guaranteed to support atomic access:

- read write access modes for all `T`, with the exception of access modes `get` and `set` for `long` and `double` on 32-bit platforms.
- atomic update access modes for `int`, `long`, `float` or `double`. (Future major platform releases of the JDK may support additional types for certain currently unsupported access modes.)
- numeric atomic update access modes for `int` and `long`. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.)
- bitwise atomic update access modes for `int` and `long`. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.)

If `T` is `float` or `double` then atomic update access modes compare values using their bitwise representation (see `Float.floatToRawIntBits(float)` and `Double.doubleToRawLongBits(double)`, respectively).

Alternatively, a memory access operation is partially aligned if it occurs at a memory address `A` which is only compatible with the alignment constraint `B`; in such cases, access for anything other than the `get` and `set` access modes will result in an `IllegalStateException`. If access is partially aligned, atomic access is only guaranteed with respect to the largest power of two that divides the GCD of `A` and `S`.

Finally, in all other cases, we say that a memory access operation is misaligned; in such cases an `IllegalStateException` is thrown, irrespective of the access mode being used.

- ## Method Summary

  Modifier and Type | Method | Description
  --- | --- | ---
  `static VarHandle` | `varHandle​(Class<?> carrier, long alignmentBytes, ByteOrder byteOrder)` | Creates a memory access var handle with the given carrier type, alignment constraint, and byte order.
  `static VarHandle` | `varHandle​(Class<?> carrier, ByteOrder byteOrder)` | Creates a memory access var handle with the given carrier type and byte order.
  `static VarHandle` | `withOffset​(VarHandle target, long bytesOffset)` | Creates a memory access var handle with a fixed offset added to the accessed offset.
  `static VarHandle` | `withStride​(VarHandle target, long bytesStride)` | Creates a memory access var handle with a variable offset added to the accessed offset.

  ### Methods declared in class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Method Details

  - ### varHandle

    public static VarHandle varHandle​(Class<?> carrier, ByteOrder byteOrder)
    Creates a memory access var handle with the given carrier type and byte order. The resulting memory access var handle features a single `MemoryAddress` access coordinate, and its variable type is set by the given carrier type. The alignment constraint for the resulting memory access var handle is the same as the in memory size of the carrier type, and the accessed offset is set at zero.
    API Note:
      the resulting var handle features certain access mode restrictions, which are common to all memory access var handles.
    Parameters:
      `carrier` - the carrier type. Valid carriers are `byte`, `short`, `char`, `int`, `float`, `long`, and `double`.
      `byteOrder` - the required byte order.
    Returns:
      the new memory access var handle.
    Throws:
      `IllegalArgumentException` - when an illegal carrier type is used

  - ### varHandle

    public static VarHandle varHandle​(Class<?> carrier, long alignmentBytes, ByteOrder byteOrder)
    Creates a memory access var handle with the given carrier type, alignment constraint, and byte order. The resulting memory access var handle features a single `MemoryAddress` access coordinate, and its variable type is set by the given carrier type. The accessed offset is zero.
    API Note:
      the resulting var handle features certain access mode restrictions, which are common to all memory access var handles.
    Parameters:
      `carrier` - the carrier type. Valid carriers are `byte`, `short`, `char`, `int`, `float`, `long`, and `double`.
      `alignmentBytes` - the alignment constraint (in bytes). Must be a power of two.
      `byteOrder` - the required byte order.
    Returns:
      the new memory access var handle.
    Throws:
      `IllegalArgumentException` - if an illegal carrier type is used, or if `alignmentBytes` is not a power of two.

  - ### withOffset

    public static VarHandle withOffset​(VarHandle target, long bytesOffset)
    Creates a memory access var handle with a fixed offset added to the accessed offset. That is, if the target memory access var handle accesses a memory location at offset O, the new memory access var handle will access a memory location at offset O' + O. The resulting memory access var handle will feature the same access coordinates as the ones in the target memory access var handle.
    API Note:
      the resulting var handle features certain access mode restrictions, which are common to all memory access var handles.
    Parameters:
      `target` - the target memory access handle to access after the offset adjustment.
      `bytesOffset` - the offset, in bytes. Must be positive or zero.
    Returns:
      the new memory access var handle.
    Throws:
      `IllegalArgumentException` - when the target var handle is not a memory access var handle, or when `bytesOffset < 0`, or otherwise incompatible with the alignment constraint.

  - ### withStride

    public static VarHandle withStride​(VarHandle target, long bytesStride)
    Creates a memory access var handle with a variable offset added to the accessed offset. That is, if the target memory access var handle accesses a memory location at offset O, the new memory access var handle will access a memory location at offset (S * X) + O, where S is a constant stride, whereas X is a dynamic value that will be provided as an additional access coordinate (of type `long`). The new access coordinate will be prepended to the ones available in the target memory access var handles (if any).
    API Note:
      the resulting var handle features certain access mode restrictions, which are common to all memory access var handles.
    Parameters:
      `target` - the target memory access handle to access after the scale adjustment.
      `bytesStride` - the stride, in bytes, by which to multiply the coordinate value. Must be greater than zero.
    Returns:
      the new memory access var handle.
    Throws:
      `IllegalArgumentException` - when the target var handle is not a memory access var handle, or if `bytesStride <= 0`, or otherwise incompatible with the alignment constraint.