APIdia Launch Partner
Top Description Inners Methods
java.lang.foreign

public sealed Interface MemoryLayout

permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout
Known Direct Subinterfaces
java.lang.foreign.PaddingLayout, java.lang.foreign.SequenceLayout, java.lang.foreign.ValueLayout, java.lang.foreign.GroupLayout
Imports
jdk.internal.foreign.LayoutPath, .Utils, jdk.internal.foreign.layout.MemoryLayoutUtil, .PaddingLayoutImpl, .SequenceLayoutImpl, .StructLayoutImpl, .UnionLayoutImpl, java.lang.invoke.MethodHandle, .VarHandle, java.util.Objects, .Optional, java.util.stream.Stream

A memory layout describes the contents of a memory segment.

There are two leaves in the layout hierarchy, value layouts, which are used to represent values of given size and kind and padding layouts which are used, as the name suggests, to represent a portion of a memory segment whose contents should be ignored, and which are primarily present for alignment reasons. Some common value layout constants, such as ValueLayout#JAVA_INT and ValueLayout#JAVA_FLOAT_UNALIGNED are defined in the ValueLayout class. A special kind of value layout, namely an address layout, is used to model values that denote the address of a region of memory.

More complex layouts can be derived from simpler ones: a sequence layout denotes a homogeneous repetition of zero or more occurrences of an element layout; a group layout denotes a heterogeneous aggregation of zero or more member layouts. Group layouts come in two flavors: struct layouts, where member layouts are laid out one after the other, and union layouts where member layouts are laid out at the same starting offset.

Layouts can be optionally associated with a name. A layout name can be referred to when constructing layout paths.

Consider the following struct declaration in C:

typedef struct { char kind; int value; } TaggedValues[5];
typedef struct {
    char kind;
    int value;
} TaggedValues[5];
The above declaration can be modeled using a layout object, as follows:
SequenceLayout TAGGED_VALUES = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout( ValueLayout.JAVA_BYTE.withName("kind"), MemoryLayout.paddingLayout(3), ValueLayout.JAVA_INT.withName("value") ) ).withName("TaggedValues");
SequenceLayout TAGGED_VALUES = MemoryLayout.sequenceLayout(5,
    MemoryLayout.structLayout(
        ValueLayout.JAVA_BYTE.withName("kind"),
        MemoryLayout.paddingLayout(3),
        ValueLayout.JAVA_INT.withName("value")
    )
).withName("TaggedValues");

Characteristics of memory layouts

All layouts have a size (expressed in bytes), which is defined as follows:

Furthermore, all layouts have a natural alignment (expressed in bytes) which is defined as follows:

A layout's alignment can be overridden if needed (see MemoryLayout#withByteAlignment(long)), which can be useful to describe layouts with weaker or stronger alignment constraints.

Layout paths

A layout path is used to unambiguously select a layout that is nested in some other layout. Layout paths are typically expressed as a sequence of one or more path elements. (A more formal definition of layout paths is provided below).

Layout paths can be used to:

For instance, given the taggedValues sequence layout constructed above, we can obtain the offset, in bytes, of the member layout named value in the first sequence element, as follows:

long valueOffset = TAGGED_VALUES.byteOffset(PathElement.sequenceElement(0), PathElement.groupElement("value")); // yields 4
long valueOffset = TAGGED_VALUES.byteOffset(PathElement.sequenceElement(0),
                                          PathElement.groupElement("value")); // yields 4
Similarly, we can select the member layout named value, as follows:
MemoryLayout value = TAGGED_VALUES.select(PathElement.sequenceElement(), PathElement.groupElement("value"));
MemoryLayout value = TAGGED_VALUES.select(PathElement.sequenceElement(),
                                         PathElement.groupElement("value"));

Open path elements

Some layout path elements, said open path elements, can select multiple layouts at once. For instance, the open path elements PathElement#sequenceElement(), PathElement#sequenceElement(long, long) select an unspecified element in a sequence layout. A var handle derived from a layout path containing one or more open path element features additional coordinates of type long, which can be used by clients to bind the open elements in the path:
VarHandle valueHandle = TAGGED_VALUES.varHandle(PathElement.sequenceElement(), PathElement.groupElement("value")); MemorySegment taggedValues = ... // reads the "value" field of the third struct in the array (taggedValues[2].value) int val = (int) valueHandle.get(taggedValues, 0L, // base offset 2L); // sequence index
VarHandle valueHandle = TAGGED_VALUES.varHandle(PathElement.sequenceElement(),
                                               PathElement.groupElement("value"));
MemorySegment taggedValues = ...
// reads the "value" field of the third struct in the array (taggedValues[2].value)
int val = (int) valueHandle.get(taggedValues,
        0L,  // base offset
        2L); // sequence index

Open path elements also affect the creation of offset-computing method handles. Each open path element becomes an additional long parameter in the obtained method handle. This parameter can be used to specify the index of the sequence element whose offset is to be computed:

MethodHandle offsetHandle = TAGGED_VALUES.byteOffsetHandle(PathElement.sequenceElement(), PathElement.groupElement("kind")); long offset1 = (long) offsetHandle.invokeExact(0L, 1L); // 0 + (1 * 8) = 8 long offset2 = (long) offsetHandle.invokeExact(0L, 2L); // 0 + (2 * 8) = 16
MethodHandle offsetHandle = TAGGED_VALUES.byteOffsetHandle(PathElement.sequenceElement(),
                                                          PathElement.groupElement("kind"));
long offset1 = (long) offsetHandle.invokeExact(0L, 1L); // 0 + (1 * 8) = 8
long offset2 = (long) offsetHandle.invokeExact(0L, 2L); // 0 + (2 * 8) = 16

Dereference path elements

A special kind of path element, called dereference path element, allows var handles obtained from memory layouts to follow pointers. Consider the following layout:
StructLayout RECTANGLE = MemoryLayout.structLayout( ValueLayout.ADDRESS.withTargetLayout( MemoryLayout.sequenceLayout(4, MemoryLayout.structLayout( ValueLayout.JAVA_INT.withName("x"), ValueLayout.JAVA_INT.withName("y") ).withName("point") ) ).withName("points") );
StructLayout RECTANGLE = MemoryLayout.structLayout(
        ValueLayout.ADDRESS.withTargetLayout(
                MemoryLayout.sequenceLayout(4,
                        MemoryLayout.structLayout(
                                ValueLayout.JAVA_INT.withName("x"),
                                ValueLayout.JAVA_INT.withName("y")
                        ).withName("point")
                 )
         ).withName("points")
);
This layout is a struct layout describing a rectangle. It contains a single field, namely points, an address layout whose target layout is a sequence layout of four struct layouts. Each struct layout describes a two-dimensional point, and is defined as a pair or ValueLayout#JAVA_INT coordinates, with names x and y, respectively.

With dereference path elements, we can obtain a var handle that accesses the y coordinate of one of the point in the rectangle, as follows:

VarHandle rectPointYs = RECTANGLE.varHandle( PathElement.groupElement("points"), PathElement.dereferenceElement(), PathElement.sequenceElement(), PathElement.groupElement("y") ); MemorySegment rect = ... // dereferences the third point struct in the "points" array, and reads its "y" coordinate (rect.points[2]->y) int rect_y_2 = (int) rectPointYs.get(rect, 0L, // base offset 2L); // sequence index
VarHandle rectPointYs = RECTANGLE.varHandle(
        PathElement.groupElement("points"),
        PathElement.dereferenceElement(),
        PathElement.sequenceElement(),
        PathElement.groupElement("y")
);

MemorySegment rect = ...
// dereferences the third point struct in the "points" array, and reads its "y" coordinate (rect.points[2]->y)
int rect_y_2 = (int) rectPointYs.get(rect,
    0L,  // base offset
    2L); // sequence index

Layout path well-formedness

A layout path is applied to a layout C_0, also called the initial layout. Each path element in a layout path can be thought of as a function that updates the current layout C_i-1 to some other layout C_i. That is, for each path element E1, E2, ... En, in a layout path P, we compute C_i = f_i(C_i-1), where f_i is the selection function associated with the path element under consideration, denoted as E_i. The final layout C_i is also called the selected layout.

A layout path P is considered well-formed for an initial layout C_0 if all its path elements E1, E2, ... En are well-formed for their corresponding input layouts C_0, C_1, ... C_n-1. A path element E is considered well-formed for a layout L if any of the following is true:

Any attempt to provide a layout path P that is not well-formed for an initial layout C_0 will result in an IllegalArgumentException.

Access mode restrictions

A var handle returned by varHandle(PathElement...) or ValueLayout#varHandle() features certain access characteristics, which are derived from the selected layout L: Depending on the above characteristics, the returned var handle might feature certain access mode restrictions. We say that a var handle is aligned if its alignment constraint A is compatible with the access size S, that is if A >= S. An aligned var handle is guaranteed to support the following access modes: If T is float, double or MemorySegment then atomic update access modes compare values using their bitwise representation (see Float#floatToRawIntBits, Double#doubleToRawLongBits and MemorySegment#address(), respectively).

Alternatively, a var handle is unaligned if its alignment constraint A is incompatible with the access size S, that is, if A < S. An unaligned var handle only supports the get and set access modes. All other access modes will result in UnsupportedOperationException being thrown. Moreover, while supported, access modes get and set might lead to word tearing.

Working with variable-length arrays

We have seen how sequence layouts are used to describe the contents of an array whose size is known statically. There are cases, however, where the array size is only known dynamically. We call such arrays variable-length arrays. There are two common kinds of variable-length arrays: While variable-length arrays cannot be modeled directly using sequence layouts, clients can still enjoy structured access to elements of variable-length arrays using var handles as demonstrated in the following sections.

Toplevel variable-length arrays

Consider the following struct declaration in C:
typedef struct { int x; int y; } Point;
typedef struct {
    int x;
    int y;
} Point;
In the above code, a point is modeled as two coordinates (x and y respectively). Now consider the following snippet of C code:
int size = ... Point *points = (Point*)malloc(sizeof(Point) * size); for (int i = 0 ; i < size ; i++) { ... points[i].x ... }
int size = ...
Point *points = (Point*)malloc(sizeof(Point) * size);
for (int i = 0 ; i < size ; i++) {
   ... points[i].x ...
}
Here, we allocate an array of points (points). Crucially, the size of the array is dynamically bound to the value of the size variable. Inside the loop, the x coordinate of all the points in the array is accessed.

To model this code in Java, let's start by defining a layout for the Point struct, as follows:

StructLayout POINT = MemoryLayout.structLayout( ValueLayout.JAVA_INT.withName("x"), ValueLayout.JAVA_INT.withName("y") );
StructLayout POINT = MemoryLayout.structLayout(
            ValueLayout.JAVA_INT.withName("x"),
            ValueLayout.JAVA_INT.withName("y")
);
Since we know we need to create and access an array of points, it would be tempting to create a sequence layout modelling the variable-length array, and then derive the necessary access var handles from the sequence layout. But this approach is problematic, as the size of the variable-length array is not known. Instead, a var handle that provides structured access to the elements of a variable-length array can be obtained directly from the layout describing the array elements (e.g. the point layout), as demonstrated below:
VarHandle POINT_ARR_X = POINT.arrayElementVarHandle(PathElement.groupElement("x")); int size = ... MemorySegment points = ... for (int i = 0 ; i < size ; i++) { ... POINT_ARR_X.get(points, 0L, (long)i) ... }
VarHandle POINT_ARR_X = POINT.arrayElementVarHandle(PathElement.groupElement("x"));

int size = ...
MemorySegment points = ...
for (int i = 0 ; i < size ; i++) {
    ... POINT_ARR_X.get(points, 0L, (long)i) ...
}
Here, the coordinate x of subsequent point in the array is accessed using the POINT_ARR_X var handle, which is obtained using the arrayElementVarHandle(PathElement...) method. This var handle features two long coordinates: the first is a base offset (set to 0L), while the second is a logical index that can be used to stride over all the elements of the point array.

The base offset coordinate allows clients to express complex access operations, by injecting additional offset computation into the var handle (we will see an example of that below). In cases where the base offset is constant (as in the previous example) clients can, if desired, drop the base offset parameter and make the access expression simpler. This is achieved using the java.lang.invoke.MethodHandles#insertCoordinates(VarHandle, int, Object...) var handle adapter.

Nested variable-length arrays

Consider the following struct declaration in C:
typedef struct { int size; Point points[]; } Polygon;
typedef struct {
    int size;
    Point points[];
} Polygon;
In the above code, a polygon is modeled as a size (the number of edges in the polygon) and an array of points (one for each vertex in the polygon). The number of vertices depends on the number of edges in the polygon. As such, the size of the points array is left unspecified in the C declaration, using a Flexible Array Member (a feature standardized in C99).

Again, clients can perform structured access to elements in the nested variable-length array using the arrayElementVarHandle(PathElement...) method, as demonstrated below:

StructLayout POLYGON = MemoryLayout.structLayout( ValueLayout.JAVA_INT.withName("size"), MemoryLayout.sequenceLayout(0, POINT).withName("points") ); VarHandle POLYGON_SIZE = POLYGON.varHandle(0, PathElement.groupElement("size")); long POINTS_OFFSET = POLYGON.byteOffset(PathElement.groupElement("points"));
StructLayout POLYGON = MemoryLayout.structLayout(
            ValueLayout.JAVA_INT.withName("size"),
            MemoryLayout.sequenceLayout(0, POINT).withName("points")
);

VarHandle POLYGON_SIZE = POLYGON.varHandle(0, PathElement.groupElement("size"));
long POINTS_OFFSET = POLYGON.byteOffset(PathElement.groupElement("points"));
The POLYGON layout contains a sequence layout of size zero. The element layout of the sequence layout is the POINT layout, shown previously. The polygon layout is used to obtain a var handle that provides access to the polygon size, as well as an offset (POINTS_OFFSET) to the start of the variable-length points array.

The x coordinates of all the points in a polygon can then be accessed as follows:

MemorySegment polygon = ... int size = POLYGON_SIZE.get(polygon, 0L); for (int i = 0 ; i < size ; i++) { ... POINT_ARR_X.get(polygon, POINTS_OFFSET, (long)i) ... }
MemorySegment polygon = ...
int size = POLYGON_SIZE.get(polygon, 0L);
for (int i = 0 ; i < size ; i++) {
    ... POINT_ARR_X.get(polygon, POINTS_OFFSET, (long)i) ...
}
Here, we first obtain the polygon size, using the POLYGON_SIZE var handle. Then, in a loop, we read the x coordinates of all the points in the polygon. This is done by providing a custom offset (namely, POINTS_OFFSET) to the offset coordinate of the POINT_ARR_X var handle. As before, the loop induction variable i is passed as the index of the POINT_ARR_X var handle, to stride over all the elements of the variable-length array.

Implementation Specification

Implementations of this interface are immutable, thread-safe and value-based.

Since
22

Nested and Inner Type Summary

Modifier and TypeClass and Description
public static interface

Method Summary

Modifier and TypeMethod and Description
public VarHandle

Returns:

a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path
arrayElementVarHandle
(MemoryLayout.PathElement...
the layout path elements
elements
)

Creates a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path, where the accessed elements have this layout, and where the initial layout in the path is this layout.

public long

Returns:

the alignment constraint associated with this layout, expressed in bytes
byteAlignment
()

Returns the alignment constraint associated with this layout, expressed in bytes.

public long

Returns:

The offset, in bytes, of the layout selected by the layout path in elements
byteOffset
(MemoryLayout.PathElement...
the layout path elements
elements
)

Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout.

public MethodHandle

Returns:

a method handle that computes the offset, in bytes, of the layout selected by the given layout path
byteOffsetHandle
(MemoryLayout.PathElement...
the layout path elements
elements
)

Creates a method handle that computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout.

public long

Returns:

the layout size, in bytes
byteSize
()

Returns the layout size, in bytes.

public boolean

Returns:

true if the specified object is equal to this layout
equals
(Object
the object to be compared for equality with this layout
other
)

Compares the specified object with this layout for equality.

public int

Returns:

the hash code value for this layout
hashCode
()

Returns the hash code value for this layout.

public Optional<String>

Returns:

the name (if any) associated with this layout
name
()

Returns the name (if any) associated with this layout.

public static PaddingLayout

Returns:

the new selector layout
paddingLayout
(long
the padding size (expressed in bytes)
byteSize
)

Creates a padding layout with the given byte size.

public long

Returns:

offset + (byteSize() * index)
scale
(long
the base offset
offset
,
long
the index to be scaled by the byte size of this layout
index
)

Returns offset + (byteSize() * index).

public MethodHandle

Returns:

a method handle that can be used to invoke scale(long, long) on this layout
scaleHandle
()

Returns a method handle that can be used to invoke scale(long, long) on this layout.

public MemoryLayout

Returns:

the layout selected by the layout path in elements
select
(MemoryLayout.PathElement...
the layout path elements
elements
)

Returns the layout selected from the provided path, where the initial layout in the path is this layout.

public static SequenceLayout

Returns:

the new sequence layout with the given element layout and size
sequenceLayout
(long
the sequence element count
elementCount
,
MemoryLayout
the sequence element layout
elementLayout
)

Creates a sequence layout with the given element layout and element count.

public MethodHandle

Returns:

a method handle that is used to slice a memory segment at the offset selected by the given layout path
sliceHandle
(MemoryLayout.PathElement...
the layout path elements
elements
)

Creates a method handle which, given a memory segment, returns a slice corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout.

public static StructLayout

Returns:

a struct layout with the given member layouts
structLayout
(MemoryLayout...
The member layouts of the struct layout
elements
)

Creates a struct layout with the given member layouts.

public String

Returns:

the string representation of this layout
toString
()

Returns the string representation of this layout.

public static UnionLayout

Returns:

a union layout with the given member layouts
unionLayout
(MemoryLayout...
The member layouts of the union layout
elements
)

Creates a union layout with the given member layouts.

public VarHandle

Returns:

a var handle that accesses a memory segment at the offset selected by the given layout path
varHandle
(MemoryLayout.PathElement...
the layout path elements
elements
)

Creates a var handle that accesses a memory segment at the offset selected by the given layout path, where the initial layout in the path is this layout.

public MemoryLayout

Returns:

a memory layout with the same characteristics as this layout, but with the given alignment constraint (in bytes)
withByteAlignment
(long
the layout alignment constraint, expressed in bytes
byteAlignment
)

Returns a memory layout with the same characteristics as this layout, but with the given alignment constraint (in bytes).

public MemoryLayout

Returns:

a memory layout with the same characteristics as this layout, but with the given name
withName
(String
the layout name
name
)

Returns a memory layout with the same characteristics as this layout, but with the given name.

public MemoryLayout

Returns:

a memory layout with the same characteristics as this layout, but with no name
withoutName
()

Returns a memory layout with the same characteristics as this layout, but with no name.

Method Detail

arrayElementVarHandleback to summary
public VarHandle arrayElementVarHandle(MemoryLayout.PathElement... elements)

Creates a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path, where the accessed elements have this layout, and where the initial layout in the path is this layout.

The returned var handle has the following characteristics:

  • its type is derived from the carrier of the selected value layout;
  • it has a leading parameter of type MemorySegment representing the accessed segment
  • a following long parameter, corresponding to the base offset, denoted as B;
  • a following long parameter, corresponding to the array index, denoted as I0. The array index is used to scale the accessed offset by this layout size;
  • it has zero or more trailing access coordinates of type long, one for each open path element in the provided layout path, denoted as I1, I2, ... In, respectively. The order of these access coordinates corresponds to the order in which the open path elements occur in the provided layout path.

If the provided layout path P contains no dereference elements, then the offset O of the access operation is computed as follows:

O = this.byteOffsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);
O = this.byteOffsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);

More formally, the method handle returned by this method is obtained from varHandle(PathElement...), as follows:

MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle())
MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle())

Accessing a memory segment using the var handle returned by this method is subject to the following checks:

  • The physical address of the accessed memory segment must be aligned according to the alignment constraint of the root layout (this layout), or an IllegalArgumentException is thrown. Note that the alignment constraint of the root layout can be more strict (but not less) than the alignment constraint of the selected value layout.
  • The access operation must fall inside the spatial bounds of the accessed memory segment, or an IndexOutOfBoundsException is thrown. This is the case when B + A <= S, where B is the base offset (defined above), A is the size of this layout and S is the size of the accessed memory segment. Note that the size of this layout might be bigger than the size of the accessed layout (e.g. when accessing a struct member).
  • If the provided layout path has an open path element whose size is S, its corresponding trailing long coordinate value I must be 0 <= I < S, or an IndexOutOfBoundsException is thrown.
  • The accessed memory segment must be accessible from the thread performing the access operation, or a WrongThreadException is thrown.
  • For write operations, the accessed memory segment must not be read only, or an IllegalArgumentException is thrown.
  • The scope associated with the accessed segment must be alive, or an IllegalStateException is thrown.

API Note

As the leading index coordinate I0 is not bound by any sequence layout, it can assume any non-negative value - provided that the resulting offset computation does not overflow, or that the computed offset does not fall outside the spatial bound of the accessed memory segment. As such, the var handles returned from this method can be especially useful when accessing variable-length arrays.

Parameters
elements:MemoryLayout.PathElement[]

the layout path elements

Returns:VarHandle

a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path

Exceptions
IllegalArgumentException:
  • if the layout path is not well-formed for this layout
  • if the layout selected by the provided path is not a value layout
byteAlignmentback to summary
public long byteAlignment()

Returns the alignment constraint associated with this layout, expressed in bytes.

Layout alignment defines a power of two A which is the byte-wise alignment of the layout, where A is the number of bytes that must be aligned for any pointer that correctly points to this layout. Thus:

  • A=1 means unaligned (in the usual sense), which is common in packets.
  • A=8 means word aligned (on LP64), A=4 int aligned, A=2 short aligned, etc.
  • A=64 is the most strict alignment required by the x86/SV ABI (for AVX-512 data).
If no explicit alignment constraint was set on this layout ( see withByteAlignment(long)), then this method returns the natural alignment constraint (in bytes) associated with this layout.
Returns:long

the alignment constraint associated with this layout, expressed in bytes

byteOffsetback to summary
public long byteOffset(MemoryLayout.PathElement... elements)

Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout.

Parameters
elements:MemoryLayout.PathElement[]

the layout path elements

Returns:long

The offset, in bytes, of the layout selected by the layout path in elements

Exceptions
IllegalArgumentException:
byteOffsetHandleback to summary
public MethodHandle byteOffsetHandle(MemoryLayout.PathElement... elements)

Creates a method handle that computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout.

The returned method handle has the following characteristics:

  • its return type is long;
  • it has one leading long parameter representing the base offset;
  • it has as zero or more trailing parameters of type long, one for each open path element in the provided layout path. The order of these parameters corresponds to the order in which the open path elements occur in the provided layout path.

The final offset returned by the method handle is computed as follows:

offset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
where b represents the base offset provided as a dynamic long argument, x_1, x_2, ... x_n represent indices into sequences provided as dynamic long arguments, whereas s_1, s_2, ... s_n are static stride constants derived from the size of the element layout of a sequence, and c_1, c_2, ... c_m are other static offset constants (such as field offsets) which are derived from the layout path.

For any given dynamic argument x_i, it must be that 0 <= x_i < size_i, where size_i is the size of the open path element associated with x_i. Otherwise, the returned method handle throws IndexOutOfBoundsException. Moreover, the value of b must be such that the computation for offset does not overflow, or the returned method handle throws ArithmeticException.

API Note

The returned method handle can be used to compute a layout offset, similarly to byteOffset(PathElement...), but more flexibly, as some indices can be specified when invoking the method handle.

Parameters
elements:MemoryLayout.PathElement[]

the layout path elements

Returns:MethodHandle

a method handle that computes the offset, in bytes, of the layout selected by the given layout path

Exceptions
IllegalArgumentException:
byteSizeback to summary
public long byteSize()

Returns the layout size, in bytes.

Returns:long

the layout size, in bytes

equalsback to summary
public boolean equals(Object other)

Compares the specified object with this layout for equality. Returns true if and only if the specified object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of the same kind, have the same size, name and alignment constraint. Furthermore, depending on the layout kind, additional conditions must be satisfied:

Parameters
other:Object

the object to be compared for equality with this layout

Returns:boolean

true if the specified object is equal to this layout

hashCodeback to summary
public int hashCode()

Returns the hash code value for this layout.

Returns:int

the hash code value for this layout

nameback to summary
public Optional<String> name()

Returns the name (if any) associated with this layout.

Returns:Optional<String>

the name (if any) associated with this layout

See Also
MemoryLayout#withName(String)
paddingLayoutback to summary
public static PaddingLayout paddingLayout(long byteSize)

Creates a padding layout with the given byte size. The alignment constraint of the returned layout is 1. As such, regardless of its size, in the absence of an explicit alignment constraint, a padding layout does not affect the natural alignment of the group or sequence layout it is nested into.

Parameters
byteSize:long

the padding size (expressed in bytes)

Returns:PaddingLayout

the new selector layout

Exceptions
IllegalArgumentException:
if byteSize <= 0
scaleback to summary
public long scale(long offset, long index)

Returns offset + (byteSize() * index).

Parameters
offset:long

the base offset

index:long

the index to be scaled by the byte size of this layout

Returns:long

offset + (byteSize() * index)

Exceptions
IllegalArgumentException:
if offset or index is negative
ArithmeticException:
if either the addition or multiplication overflows
scaleHandleback to summary
public MethodHandle scaleHandle()

Returns a method handle that can be used to invoke scale(long, long) on this layout.

Returns:MethodHandle

a method handle that can be used to invoke scale(long, long) on this layout

selectback to summary
public MemoryLayout select(MemoryLayout.PathElement... elements)

Returns the layout selected from the provided path, where the initial layout in the path is this layout.

Parameters
elements:MemoryLayout.PathElement[]

the layout path elements

Returns:MemoryLayout

the layout selected by the layout path in elements

Exceptions
IllegalArgumentException:
sequenceLayoutback to summary
public static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout)

Creates a sequence layout with the given element layout and element count.

Parameters
elementCount:long

the sequence element count

elementLayout:MemoryLayout

the sequence element layout

Returns:SequenceLayout

the new sequence layout with the given element layout and size

Exceptions
IllegalArgumentException:
  • if elementCount is negative
  • if elementLayout.byteSize() * elementCount overflows
  • if elementLayout.byteSize() % elementLayout.byteAlignment() != 0
sliceHandleback to summary
public MethodHandle sliceHandle(MemoryLayout.PathElement... elements)

Creates a method handle which, given a memory segment, returns a slice corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout.

The returned method handle has the following characteristics:

  • its return type is MemorySegment;
  • it has a leading parameter of type MemorySegment corresponding to the memory segment to be sliced
  • a following long parameter, corresponding to the base offset
  • it has as zero or more trailing parameters of type long, one for each open path element in the provided layout path. The order of these parameters corresponds to the order in which the open path elements occur in the provided layout path.

The offset O of the returned segment is computed as if by a call to a byte offset handle constructed using the given path elements.

Computing a slice of a memory segment using the method handle returned by this method is subject to the following checks:

  • The physical address of the accessed memory segment must be aligned according to the alignment constraint of the root layout (this layout), or an IllegalArgumentException will be issued. Note that the alignment constraint of the root layout can be more strict (but not less) than the alignment constraint of the selected layout.
  • The slicing operation must fall inside the spatial bounds of the accessed memory segment, or an IndexOutOfBoundsException is thrown. This is the case when B + A <= S, where B is the base offset (defined above), A is the size of this layout and S is the size of the accessed memory segment. Note that the size of this layout might be bigger than the size of the accessed layout (e.g. when accessing a struct member).
  • If the provided layout path has an open path element whose size is S, its corresponding trailing long coordinate value I must be 0 <= I < S, or an IndexOutOfBoundsException is thrown.

API Note

The returned method handle can be used to obtain a memory segment slice, similarly to MemorySegment#asSlice(long, long), but more flexibly, as some indices can be specified when invoking the method handle.

Parameters
elements:MemoryLayout.PathElement[]

the layout path elements

Returns:MethodHandle

a method handle that is used to slice a memory segment at the offset selected by the given layout path

Exceptions
IllegalArgumentException:
structLayoutback to summary
public static StructLayout structLayout(MemoryLayout... elements)

Creates a struct layout with the given member layouts.

API Note

This factory does not automatically align element layouts, by inserting additional padding layout elements. As such, the following struct layout creation will fail with an exception:

structLayout(JAVA_SHORT, JAVA_INT);
structLayout(JAVA_SHORT, JAVA_INT);
To avoid the exception, clients can either insert additional padding layout elements:
structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);
structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);
Or, alternatively, they can use a member layout that features a smaller alignment constraint. This will result in a packed struct layout:
structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
Parameters
elements:MemoryLayout[]

The member layouts of the struct layout

Returns:StructLayout

a struct layout with the given member layouts

Exceptions
IllegalArgumentException:
  • if the sum of the byte sizes of the member layouts overflows
  • if a member layout in elements occurs at an offset (relative to the start of the struct layout) which is not compatible with its alignment constraint
toStringback to summary
public String toString()

Returns the string representation of this layout.

Returns:String

the string representation of this layout

Annotations
@Override
unionLayoutback to summary
public static UnionLayout unionLayout(MemoryLayout... elements)

Creates a union layout with the given member layouts.

Parameters
elements:MemoryLayout[]

The member layouts of the union layout

Returns:UnionLayout

a union layout with the given member layouts

varHandleback to summary
public VarHandle varHandle(MemoryLayout.PathElement... elements)

Creates a var handle that accesses a memory segment at the offset selected by the given layout path, where the initial layout in the path is this layout.

The returned var handle has the following characteristics:

  • its type is derived from the carrier of the selected value layout;
  • it has a leading parameter of type MemorySegment representing the accessed segment
  • a following long parameter, corresponding to the base offset, denoted as B;
  • it has zero or more trailing access coordinates of type long, one for each open path element in the provided layout path, denoted as I1, I2, ... In, respectively. The order of these access coordinates corresponds to the order in which the open path elements occur in the provided layout path.

If the provided layout path P contains no dereference elements, then the offset O of the access operation is computed as follows:

O = this.byteOffsetHandle(P).invokeExact(B, I1, I2, ... In);
O = this.byteOffsetHandle(P).invokeExact(B, I1, I2, ... In);

Accessing a memory segment using the var handle returned by this method is subject to the following checks:

  • The physical address of the accessed memory segment must be aligned according to the alignment constraint of the root layout (this layout), or an IllegalArgumentException is thrown. Note that the alignment constraint of the root layout can be more strict (but not less) than the alignment constraint of the selected value layout.
  • The access operation must fall inside the spatial bounds of the accessed memory segment, or an IndexOutOfBoundsException is thrown. This is the case when B + A <= S, where B is the base offset (defined above), A is the size of this layout and S is the size of the accessed memory segment. Note that the size of this layout might be bigger than the size of the accessed layout (e.g. when accessing a struct member).
  • If the provided layout path has an open path element whose size is S, its corresponding trailing long coordinate value I must be 0 <= I < S, or an IndexOutOfBoundsException is thrown.
  • The accessed memory segment must be accessible from the thread performing the access operation, or a WrongThreadException is thrown.
  • For write operations, the accessed memory segment must not be read only, or an IllegalArgumentException is thrown.
  • The scope associated with the accessed segment must be alive, or an IllegalStateException is thrown.

If the selected layout is an address layout, calling VarHandle#get(Object...) on the returned var handle will return a new memory segment. The segment is associated with the global scope. Moreover, the size of the segment depends on whether the address layout has a target layout. More specifically:

  • If the address layout has a target layout T, then the size of the returned segment is T.byteSize();
  • Otherwise, the address layout has no target layout and the size of the returned segment is zero.
Moreover, if the selected layout is an address layout, calling VarHandle#set(Object...) can throw IllegalArgumentException if the memory segment representing the address to be written is not a native memory segment.

If the provided layout path has size m and contains a dereference path element in position k (where k <= m) then two layout paths P and Q are derived, where P contains all the path elements from 0 to k - 1 and Q contains all the path elements from k + 1 to m (Q could be an empty layout path if k == m). Then, the returned var handle is computed as follows:

VarHandle baseHandle = this.varHandle(P); MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get(); VarHandle targetHandle = target.varHandle(Q); targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0 targetHandle = MethodHandles.collectCoordinates(targetHandle, 0, baseHandle.toMethodHandle(VarHandle.AccessMode.GET));
VarHandle baseHandle = this.varHandle(P);
MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get();
VarHandle targetHandle = target.varHandle(Q);
targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0
targetHandle = MethodHandles.collectCoordinates(targetHandle, 0,
        baseHandle.toMethodHandle(VarHandle.AccessMode.GET));
(The above can be trivially generalized to cases where the provided layout path contains more than one dereference path elements).

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

GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout( MemoryLayout.paddingLayout(4), ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value") );
GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout(
        MemoryLayout.paddingLayout(4),
        ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
);
To access the member layout named value, we can construct a var handle as follows:
VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int
VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int

API Note

The resulting var handle features certain access mode restrictions, which are common to all var handles derived from memory layouts.

Parameters
elements:MemoryLayout.PathElement[]

the layout path elements

Returns:VarHandle

a var handle that accesses a memory segment at the offset selected by the given layout path

Exceptions
IllegalArgumentException:
  • if the layout path is not well-formed for this layout
  • if the layout selected by the provided path is not a value layout
withByteAlignmentback to summary
public MemoryLayout withByteAlignment(long byteAlignment)

Returns a memory layout with the same characteristics as this layout, but with the given alignment constraint (in bytes).

Parameters
byteAlignment:long

the layout alignment constraint, expressed in bytes

Returns:MemoryLayout

a memory layout with the same characteristics as this layout, but with the given alignment constraint (in bytes)

Exceptions
IllegalArgumentException:
if byteAlignment is not a power of two
withNameback to summary
public MemoryLayout withName(String name)

Returns a memory layout with the same characteristics as this layout, but with the given name.

Parameters
name:String

the layout name

Returns:MemoryLayout

a memory layout with the same characteristics as this layout, but with the given name

See Also
MemoryLayout#name()
withoutNameback to summary
public MemoryLayout withoutName()

Returns a memory layout with the same characteristics as this layout, but with no name.

API Note

This can be useful to compare two layouts that have different names, but are otherwise equal.

Returns:MemoryLayout

a memory layout with the same characteristics as this layout, but with no name

See Also
MemoryLayout#name()
java.lang.foreign back to summary

public sealed Interface MemoryLayout.PathElement

permits DereferenceElement, GroupElementByIndex, GroupElementByName, SequenceElement, SequenceElementByIndex, SequenceElementByRange
Known Direct Implementers
jdk.internal.foreign.LayoutPath.GroupElementByName, jdk.internal.foreign.LayoutPath.GroupElementByIndex, jdk.internal.foreign.LayoutPath.SequenceElementByIndex, jdk.internal.foreign.LayoutPath.SequenceElementByRange, jdk.internal.foreign.LayoutPath.SequenceElement, jdk.internal.foreign.LayoutPath.DereferenceElement

An element in a layout path. There are three kinds of path elements: Sequence path elements selecting more than one sequence element layout are called open path elements. The size of an open path element determines the number of element layouts that can be selected by it.

Implementation Specification

Implementations of this interface are immutable, thread-safe and value-based.

Since
22

Method Summary

Modifier and TypeMethod and Description
public static MemoryLayout.PathElement

Returns:

a path element that selects the target layout of an address layout (where set)
dereferenceElement
()

Returns a path element that selects the target layout of an address layout (where set).

public static MemoryLayout.PathElement

Returns:

a path element which selects a member layout with the given name in a group layout
groupElement
(String
the name of the member layout to be selected
name
)

Returns a path element which selects a member layout with the given name in a group layout.

public static MemoryLayout.PathElement

Returns:

a path element that selects a member layout with the given index in a group layout
groupElement
(long
the index of the member layout element to be selected
index
)

Returns a path element that selects a member layout with the given index in a group layout.

public static MemoryLayout.PathElement

Returns:

a path element which selects the element layout at the specified index in a sequence layout
sequenceElement
(long
the index of the sequence element to be selected
index
)

Returns a path element which selects the element layout at the specified index in a sequence layout.

public static MemoryLayout.PathElement

Returns:

a path element that selects the sequence element layout with the given index.
sequenceElement
(long
the index of the first sequence element to be selected
start
,
long
the step factor at which subsequence sequence elements are to be selected
step
)

Returns an open path element that selects the element layout in a range of positions in a sequence layout.

public static MemoryLayout.PathElement

Returns:

an open path element that selects an unspecified element layout in a sequence layout
sequenceElement
()

Returns an open path element that selects an unspecified element layout in a sequence layout.

Method Detail

dereferenceElementback to summary
public static MemoryLayout.PathElement dereferenceElement()

Returns a path element that selects the target layout of an address layout (where set).

Returns:MemoryLayout.PathElement

a path element that selects the target layout of an address layout (where set)

groupElementback to summary
public static MemoryLayout.PathElement groupElement(String name)

Returns a path element which selects a member layout with the given name in a group layout.

Implementation Specification

in case multiple group elements with a matching name exist, the path element returned by this method will select the first one; that is, the group element with the lowest offset from the current path is selected. In such cases, using groupElement(long) might be preferable.

Parameters
name:String

the name of the member layout to be selected

Returns:MemoryLayout.PathElement

a path element which selects a member layout with the given name in a group layout

groupElementback to summary
public static MemoryLayout.PathElement groupElement(long index)

Returns a path element that selects a member layout with the given index in a group layout.

Parameters
index:long

the index of the member layout element to be selected

Returns:MemoryLayout.PathElement

a path element that selects a member layout with the given index in a group layout

Exceptions
IllegalArgumentException:
if index < 0
sequenceElementback to summary
public static MemoryLayout.PathElement sequenceElement(long index)

Returns a path element which selects the element layout at the specified index in a sequence layout.

Parameters
index:long

the index of the sequence element to be selected

Returns:MemoryLayout.PathElement

a path element which selects the element layout at the specified index in a sequence layout

Exceptions
IllegalArgumentException:
if index < 0
sequenceElementback to summary
public static MemoryLayout.PathElement sequenceElement(long start, long step)

Returns an open path element that selects the element layout in a range of positions in a sequence layout. The range is expressed as a pair of starting index (inclusive) S and step factor (which can also be negative) F.

The exact sequence element selected by this layout is expressed as an index I. If C is the sequence element count, it follows that 0 <= I < B, where B is computed as follows:

  • if F > 0, then B = ceilDiv(C - S, F)
  • if F < 0, then B = ceilDiv(S + 1, -F)
That is, the size of the returned open path element is B.
Parameters
start:long

the index of the first sequence element to be selected

step:long

the step factor at which subsequence sequence elements are to be selected

Returns:MemoryLayout.PathElement

a path element that selects the sequence element layout with the given index.

Exceptions
IllegalArgumentException:
if start < 0, or step == 0
sequenceElementback to summary
public static MemoryLayout.PathElement sequenceElement()

Returns an open path element that selects an unspecified element layout in a sequence layout.

The exact sequence element selected by this layout is expressed as an index I. If C is the sequence element count, it follows that 0 <= I < C. That is, C is the size of the returned open path element.

Returns:MemoryLayout.PathElement

an open path element that selects an unspecified element layout in a sequence layout