APIdia Launch Partner
Top Description Inners Fields Constructors Methods
jdk.internal.foreign

public final Class CaptureStateUtil

extends Object
Class Inheritance
Imports
jdk.internal.invoke.MhUtil, jdk.internal.vm.annotation.ForceInline, java.lang.foreign.Arena, .Linker, .MemoryLayout, .MemorySegment, .StructLayout, java.lang.invoke.MethodHandle, .MethodHandles, .MethodType, .VarHandle, java.util.HashSet, .List, .Map, .Objects, .Set, java.util.function.Function, .IntFunction

An internal utility class that can be used to adapt system-call-styled method handles for efficient and easy use.

Nested and Inner Type Summary

Modifier and TypeClass and Description
private static record

Field Summary

Modifier and TypeField and Description
private static final int
private static final int
private static final int
private static final StructLayout
private static final int
private static final int
private static final List<MethodHandle>
private static final MethodHandles.Lookup
private static final int
private static final int
private static final BufferStack
private static final Map<CaptureStateUtil.SegmentExtractorKey, MethodHandle>
private static final int
private static final int
private static final IntFunction<MethodHandle>

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
private static Arena
public static MethodHandle

Returns:

a new MethodHandle that adapts the provided target so that it directly returns the same value as the target if it is non-negative, otherwise returns the negated captured state defined by the provided stateName
adaptSystemCall
(MethodHandle
method handle that returns an int or a long and has a capturing state MemorySegment as its first parameter
target
,
String
the name of the capturing state member layout (i.e. "errno", "GetLastError", or "WSAGetLastError")
stateName
)

Returns a new MethodHandle that adapts the provided target so that it directly returns the same value as the target if it is non-negative, otherwise returns the negated captured state defined by the provided stateName.

private static MemorySegment
allocate(Arena arena)

private static int
error(MethodHandle errorHandle, int value, MemorySegment segment)

private static long
error(MethodHandle errorHandle, long value, MemorySegment segment)

private static MethodHandle
makeHandle(int index)

private static MethodHandle
private static boolean
nonNegative(int value)

private static boolean
nonNegative(long value)

private static int
success(int value, MemorySegment segment)

private static long
success(long value, MemorySegment segment)

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

ACQUIRE_ARENAback to summary
private static final int ACQUIRE_ARENA
ALLOCATEback to summary
private static final int ALLOCATE
ARENA_CLOSEback to summary
private static final int ARENA_CLOSE
CAPTURE_LAYOUTback to summary
private static final StructLayout CAPTURE_LAYOUT
ERROR_INTback to summary
private static final int ERROR_INT
ERROR_LONGback to summary
private static final int ERROR_LONG
HANDLES_CACHEback to summary
private static final List<MethodHandle> HANDLES_CACHE
LOOKUPback to summary
private static final MethodHandles.Lookup LOOKUP
NON_NEGATIVE_INTback to summary
private static final int NON_NEGATIVE_INT
NON_NEGATIVE_LONGback to summary
private static final int NON_NEGATIVE_LONG
POOLback to summary
private static final BufferStack POOL
SEGMENT_EXTRACTION_HANDLE_CACHEback to summary
private static final Map<CaptureStateUtil.SegmentExtractorKey, MethodHandle> SEGMENT_EXTRACTION_HANDLE_CACHE
SUCCESS_INTback to summary
private static final int SUCCESS_INT
SUCCESS_LONGback to summary
private static final int SUCCESS_LONG
UNDERLYING_MAKE_HANDLEback to summary
private static final IntFunction<MethodHandle> UNDERLYING_MAKE_HANDLE

Constructor Detail

CaptureStateUtilback to summary
private CaptureStateUtil()

Method Detail

acquireArenaback to summary
private static Arena acquireArena()
Annotations
@ForceInline
adaptSystemCallback to summary
public static MethodHandle adaptSystemCall(MethodHandle target, String stateName)

Returns a new MethodHandle that adapts the provided target so that it directly returns the same value as the target if it is non-negative, otherwise returns the negated captured state defined by the provided stateName.

This method is suitable for adapting system-call method handles(e.g. open(), read(), and close()). Clients can check the return value as shown in this example:

// (MemorySegment capture, MemorySegment pathname, int flags)int static final MethodHandle CAPTURING_OPEN = ... // (MemorySegment pathname, int flags)int static final MethodHandle OPEN = CaptureStateUtil .adaptSystemCall(CAPTURING_OPEN, "errno"); try { int fh = (int)OPEN.invokeExact(pathName, flags); if (fh < 0) { throw new IOException("Error opening file: errno = " + (-fh)); } processFile(fh); } catch (Throwable t) { throw new RuntimeException(t); }
 // (MemorySegment capture, MemorySegment pathname, int flags)int
 static final MethodHandle CAPTURING_OPEN = ...

// (MemorySegment pathname, int flags)int
static final MethodHandle OPEN = CaptureStateUtil
       .adaptSystemCall(CAPTURING_OPEN, "errno");

try {
   int fh = (int)OPEN.invokeExact(pathName, flags);
   if (fh < 0) {
       throw new IOException("Error opening file: errno = " + (-fh));
   }
   processFile(fh);
} catch (Throwable t) {
     throw new RuntimeException(t);
}
For a target method handle that takes a MemorySegment and two int parameters and returns an int value, the method returns a new method handle that is doing the equivalent of:

private static final MemoryLayout CAPTURE_LAYOUT = Linker.Option.captureStateLayout(); private static final BufferStack POOL = BufferStack.of(CAPTURE_LAYOUT); public int invoke(MethodHandle target, String stateName, int a, int b) { try (var arena = POOL.pushFrame(CAPTURE_LAYOUT)) { final MemorySegment segment = arena.allocate(CAPTURE_LAYOUT); final int result = (int) handle.invoke(segment, a, b); if (result >= 0) { return result; } return -(int) CAPTURE_LAYOUT .varHandle(MemoryLayout.PathElement.groupElement(stateName)) .get(segment, 0); } }
private static final MemoryLayout CAPTURE_LAYOUT =
        Linker.Option.captureStateLayout();
private static final BufferStack POOL =
        BufferStack.of(CAPTURE_LAYOUT);

public int invoke(MethodHandle target,
                  String stateName,
                  int a, int b) {
    try (var arena = POOL.pushFrame(CAPTURE_LAYOUT)) {
        final MemorySegment segment = arena.allocate(CAPTURE_LAYOUT);
        final int result = (int) handle.invoke(segment, a, b);
        if (result >= 0) {
            return result;
        }
        return -(int) CAPTURE_LAYOUT
            .varHandle(MemoryLayout.PathElement.groupElement(stateName))
                .get(segment, 0);
    }
}
except it is more performant. In the above stateName is the name of the captured state (e.g. errno). The static CAPTURE_LAYOUT is shared across all target method handles adapted by this method.
Parameters
target:MethodHandle

method handle that returns an int or a long and has a capturing state MemorySegment as its first parameter

stateName:String

the name of the capturing state member layout (i.e. "errno", "GetLastError", or "WSAGetLastError")

Returns:MethodHandle

a new MethodHandle that adapts the provided target so that it directly returns the same value as the target if it is non-negative, otherwise returns the negated captured state defined by the provided stateName

Exceptions
IllegalArgumentException:
  • if the provided target's return type is not int or long
  • if the provided target's first parameter type is not MemorySegment
  • if the provided stateName is unknown on the current platform
allocateback to summary
private static MemorySegment allocate(Arena arena)
Annotations
@ForceInline
errorback to summary
private static int error(MethodHandle errorHandle, int value, MemorySegment segment) throws Throwable
Annotations
@ForceInline
errorback to summary
private static long error(MethodHandle errorHandle, long value, MemorySegment segment) throws Throwable
Annotations
@ForceInline
makeHandleback to summary
private static MethodHandle makeHandle(int index)
makeSegmentExtractionHandleback to summary
private static MethodHandle makeSegmentExtractionHandle(CaptureStateUtil.SegmentExtractorKey segmentExtractorKey)
nonNegativeback to summary
private static boolean nonNegative(int value)
Annotations
@ForceInline
nonNegativeback to summary
private static boolean nonNegative(long value)
Annotations
@ForceInline
successback to summary
private static int success(int value, MemorySegment segment)
Annotations
@ForceInline
successback to summary
private static long success(long value, MemorySegment segment)
Annotations
@ForceInline
jdk.internal.foreign back to summary

private final Record CaptureStateUtil.SegmentExtractorKey

extends Record
Class Inheritance
Record Components
returnType:Class<?> 
stateName:String 

Field Summary

Modifier and TypeField and Description
private final Class<?>
returnType

Record Component accessed by returnType().

private final String
stateName

Record Component accessed by stateName().

Constructor Summary

AccessConstructor and Description
pack-priv
private
SegmentExtractorKey(Class<?> returnType, String stateName)

Method Summary

Modifier and TypeMethod and Description
public final boolean
equals(Object o)

Implements abstract java.lang.Record.equals.

Indicates whether some other object is "equal to" this one.

public final int
hashCode()

Implements abstract java.lang.Record.hashCode.

Returns a hash code value for the record.

private static IllegalArgumentException
pack-priv static Class<?>
public Class<?>
returnType()

Record Component getter of returnType.

public String
stateName()

Record Component getter of stateName.

public final String
toString()

Implements abstract java.lang.Record.toString.

Returns a string representation of the record.

Field Detail

returnTypeback to summary
private final Class<?> returnType

Record Component accessed by returnType().

stateNameback to summary
private final String stateName

Record Component accessed by stateName().

Constructor Detail

SegmentExtractorKeyback to summary
pack-priv SegmentExtractorKey(MethodHandle target, String stateName)
SegmentExtractorKeyback to summary
private SegmentExtractorKey(Class<?> returnType, String stateName)

Method Detail

equalsback to summary
public final boolean equals(Object o)

Implements abstract java.lang.Record.equals.

Doc from java.lang.Record.equals.

Indicates whether some other object is "equal to" this one. In addition to the general contract of Object.equals, record classes must further obey the invariant that when a record instance is "copied" by passing the result of the record component accessor methods to the canonical constructor, as follows:

    R copy = new R(r.c1(), r.c2(), ..., r.cn());
then it must be the case that r.equals(copy).
hashCodeback to summary
public final int hashCode()

Implements abstract java.lang.Record.hashCode.

Doc from java.lang.Record.hashCode.

Returns a hash code value for the record. Obeys the general contract of Object.hashCode. For records, hashing behavior is constrained by the refined contract of Record.equals, so that any two records created from the same components must have the same hash code.

illegalArgDoesNotback to summary
private static IllegalArgumentException illegalArgDoesNot(MethodHandle target, String info)
returnTypeback to summary
pack-priv static Class<?> returnType(MethodHandle target)
returnTypeback to summary
public Class<?> returnType()

Record Component getter of returnType.

stateNameback to summary
public String stateName()

Record Component getter of stateName.

toStringback to summary
public final String toString()

Implements abstract java.lang.Record.toString.

Doc from java.lang.Record.toString.

Returns a string representation of the record. In accordance with the general contract of Object#toString(), the toString method returns a string that "textually represents" this record. The result should be a concise but informative representation that is easy for a person to read.

In addition to this general contract, record classes must further participate in the invariant that any two records which are equal must produce equal strings. This invariant is necessarily relaxed in the rare case where corresponding equal component values might fail to produce equal strings for themselves.