Top Description Inners Methods
jdk.internal.foreign.abi

public sealed Interface Binding

Known Direct Subinterfaces
jdk.internal.foreign.abi.Binding.Move, jdk.internal.foreign.abi.Binding.Dereference
Known Direct Implementers
jdk.internal.foreign.abi.Binding.Copy, jdk.internal.foreign.abi.Binding.Allocate, jdk.internal.foreign.abi.Binding.SegmentBase, jdk.internal.foreign.abi.Binding.SegmentOffset, jdk.internal.foreign.abi.Binding.BoxAddress, jdk.internal.foreign.abi.Binding.Dup, jdk.internal.foreign.abi.Binding.ShiftLeft, jdk.internal.foreign.abi.Binding.ShiftRight, jdk.internal.foreign.abi.Binding.Cast
Imports
jdk.internal.foreign.AbstractMemorySegmentImpl, .Utils, jdk.internal.foreign.abi.BindingInterpreter.LoadFunc, .BindingInterpreter.StoreFunc, java.lang.foreign.*, java.lang.invoke.MethodHandle, .MethodHandles, .MethodType, java.util.ArrayList, .Deque, .List

The binding operators defined in the Binding class can be combined into argument and return value processing 'recipes'. The binding operators are interpreted using a stack-base interpreter. Operators can either consume operands from the stack, or push them onto the stack. In the description of each binding we talk about 'boxing' and 'unboxing'. - Unboxing is the process of taking a Java value and decomposing it, and storing components into machine storage locations. As such, the binding interpreter stack starts with the Java value on it, and should end empty. - Boxing is the process of re-composing a Java value by pulling components from machine storage locations. If a MemorySegment is needed to store the result, one should be allocated using the ALLOCATE_BUFFER operator. The binding interpreter stack starts off empty, and ends with the value to be returned as the only value on it. A binding operator can be interpreted differently based on whether we are boxing or unboxing a value. For example, the CONVERT_ADDRESS operator 'unboxes' a MemoryAddress to a long, but 'boxes' a long to a MemoryAddress. Here are some examples of binding recipes derived from C declarations, and according to the Windows ABI (recipes are ABI-specific). Note that each argument has its own recipe, which is indicated by '[number]:' (though, the only example that has multiple arguments is the one using varargs). -------------------- void f(int i); Argument bindings: 0: VM_STORE(rcx, int.class) // move an 'int' into the RCX register Return bindings: none -------------------- void f(int* i); Argument bindings: 0: UNBOX_ADDRESS // the 'MemoryAddress' is converted into a 'long' VM_STORE(rcx, long.class) // the 'long' is moved into the RCX register Return bindings: none -------------------- int* f(); Argument bindings: none Return bindings: 0: VM_LOAD(rax, long) // load a 'long' from the RAX register BOX_ADDRESS // convert the 'long' into a 'MemoryAddress' -------------------- typedef struct { // fits into single register int x; int y; } MyStruct; void f(MyStruct ms); Argument bindings: 0: BUFFER_LOAD(0, long.class) // From the struct's memory region, load a 'long' from offset '0' VM_STORE(rcx, long.class) // and copy that into the RCX register Return bindings: none -------------------- typedef struct { // does not fit into single register long long x; long long y; } MyStruct; void f(MyStruct ms); For the Windows ABI: Argument bindings: 0: COPY(16, 8) // copy the memory region containing the struct BASE_ADDRESS // take the base address of the copy UNBOX_ADDRESS // converts the base address to a 'long' VM_STORE(rcx, long.class) // moves the 'long' into the RCX register Return bindings: none For the SysV ABI: Argument bindings: 0: DUP // duplicates the MemoryRegion operand BUFFER_LOAD(0, long.class) // loads a 'long' from offset '0' VM_STORE(rdx, long.class) // moves the long into the RDX register BUFFER_LOAD(8, long.class) // loads a 'long' from offset '8' VM_STORE(rcx, long.class) // moves the long into the RCX register Return bindings: none -------------------- typedef struct { // fits into single register int x; int y; } MyStruct; MyStruct f(); Argument bindings: none Return bindings: 0: ALLOCATE(GroupLayout(C_INT, C_INT)) // allocate a buffer with the memory layout of the struct DUP // duplicate the allocated buffer VM_LOAD(rax, long.class) // loads a 'long' from rax BUFFER_STORE(0, long.class) // stores a 'long' at offset 0 -------------------- typedef struct { // does not fit into single register long long x; long long y; } MyStruct; MyStruct f(); !! uses synthetic argument, which is a pointer to a pre-allocated buffer Argument bindings: 0: UNBOX_ADDRESS // unbox the MemoryAddress synthetic argument VM_STORE(rcx, long.class) // moves the 'long' into the RCX register Return bindings: none -------------------- void f(int dummy, ...); // varargs f(0, 10f); // passing a float Argument bindings: 0: VM_STORE(rcx, int.class) // moves the 'int dummy' into the RCX register 1: DUP // duplicates the '10f' argument VM_STORE(rdx, float.class) // move one copy into the RDX register VM_STORE(xmm1, float.class) // moves the other copy into the xmm2 register Return bindings: none --------------------

Nested and Inner Type Summary

Modifier and TypeClass and Description
public static record
Binding.Allocate

ALLOCATE([size], [alignment]) Creates a new MemorySegment with the give [size] and [alignment], and pushes it onto the operand stack.

public static record
Binding.BoxAddress

BOX_ADDRESS() Pops a 'long' from the operand stack, converts it to a 'MemorySegment', with the given size and memory scope (either the context scope, or the global scope), and pushes that onto the operand stack.

public static record
Binding.BufferLoad

BUFFER_LOAD([offset into memory region], [type], [width]) Pops a MemorySegment from the operand stack, and then loads [width] bytes from it at [offset into memory region], into a [type].

public static record
Binding.BufferStore

BUFFER_STORE([offset into memory region], [type], [width]) Pops a [type] from the operand stack, then pops a MemorySegment from the operand stack.

public static class
Binding.Builder

A builder helper class for generating lists of Bindings

public static enum
Binding.Cast

CAST([fromType], [toType]) Pop a [fromType] from the stack, convert it to [toType], and push the resulting value onto the stack.

public static record
Binding.Copy

COPY([size], [alignment]) Creates a new MemorySegment with the given [size] and [alignment], and copies contents from a MemorySegment popped from the top of the operand stack into this new buffer, and pushes the new buffer onto the operand stack

public static interface
public static record
Binding.Dup

DUP() Duplicates the value on the top of the operand stack (without popping it!), and pushes the duplicate onto the operand stack

public static interface
public static record
Binding.SegmentBase

SEGMENT_BASE() Pops a MemorySegment from the stack, retrieves the heap base object from it, or null if there is none (See: AbstractMemorySegmentImpl::unsafeGetBase), and pushes the result onto the operand stack.

public static record
Binding.SegmentOffset

SEGMENT_OFFSET([allowHeap]) Pops a MemorySegment from the stack, retrieves the offset from it, (See: AbstractMemorySegmentImpl::unsafeGetOffset), and pushes the result onto the operand stack.

public static record
Binding.ShiftLeft

ShiftLeft([shiftAmount]) Shifts the Bytes on the top of the operand stack (64 bit unsigned).

public static record
Binding.ShiftRight

ShiftRight([shiftAmount]) Shifts the Bytes on the top of the operand stack (64 bit unsigned).

public static record
Binding.VMLoad

VM_LOAD([storage location], [type]) Loads a [type] from [storage location], and pushes it onto the operand stack.

public static record
Binding.VMStore

VM_STORE([storage location], [type]) Pops a [type] from the operand stack, and moves it to [storage location] The [type] must be one of byte, short, char, int, long, float, or double.

Method Summary

Modifier and TypeMethod and Description
public static Binding.Allocate
public static Binding.BoxAddress
public static Binding.BoxAddress
boxAddress(long byteSize)

public static Binding.BoxAddress
boxAddressRaw(long size, long align)

public static Binding.BufferLoad
bufferLoad(long offset, Class<?> type)

public static Binding.BufferLoad
bufferLoad(long offset, Class<?> type, int byteWidth)

public static Binding.BufferStore
bufferStore(long offset, Class<?> type)

public static Binding.BufferStore
bufferStore(long offset, Class<?> type, int byteWidth)

public static Binding.Builder
public static Binding
cast(Class<?> fromType, Class<?> toType)

private static void
checkByteWidth(int byteWidth, Class<?> type)

private static void
checkOffset(long offset)

private static void
checkType(Class<?> type)

public static Binding.Copy
public static Binding.Dup
dup()

public void
public static Binding.SegmentBase
public static Binding.SegmentOffset
public static Binding.SegmentOffset
public static Binding.ShiftLeft
shiftLeft(int shiftAmount)

public static Binding.ShiftRight
shiftRight(int shiftAmount)

public static Binding.SegmentOffset
public void
verify(Deque<Class<?>> stack)

public static Binding.VMLoad
vmLoad(VMStorage storage, Class<?> type)

public static Binding.VMStore
vmStore(VMStorage storage, Class<?> type)