VaList
is a preview API of the Java platform.
va_list
.
A variable argument list can be created using the make(Consumer, SegmentScope)
factory, as follows:
VaList vaList = VaList.make(builder ->
builder.addVarg(C_INT, 42)
.addVarg(C_DOUBLE, 3.8d));
va_list
type.
The contents of a foreign memory segment modelling a variable argument list can be accessed by unsafely creating a variable argument list, as follows:
void upcall(int n, MemorySegment vaListSegment) {
try (Arena arena = Arena.openConfined()) {
VaList vaList = VaList.ofAddress(vaListSegment.address(), arena.scope());
VaList copy = vaList.copy();
int i = vaList.nextVarg(C_INT);
double d = vaList.nextVarg(C_DOUBLE);
// and again
int i = copy.nextVarg(C_INT);
double d = copy.nextVarg(C_DOUBLE);
}
}
nextVarg(ValueLayout.OfInt)
and
nextVarg(ValueLayout.OfDouble)
. These methods (as well as other access methods in the VaList
PREVIEW class)
take the layout of the element that needs to be accessed and perform all the necessary alignment checks as well
as endianness conversions.
Per the C specification (see C99 standard 6.5.2.2 Function calls - item 6),
arguments to variadic calls are erased by way of 'default argument promotions',
which erases integral types by way of integer promotion (see C99 standard 6.3.1.1 - item 2),
and which erases all float
arguments to double
.
As such, this interface only supports reading int
, double
,
and any other type that fits into a long
.
Safety considerations
Accessing a value through a variable argument list using the wrong memory layout will result in undefined behavior. For instance, if a variable argument list currently points at a Cint
value, then accessing it using
nextVarg(ValueLayout.OfLong)
is illegal. Similarly, accessing the variable argument list with
skip(MemoryLayout...)
, and providing a layout other than ValueLayout.OfInt
PREVIEW is illegal.
Any such illegal accesses might not be detected by the implementation, and can corrupt the variable argument list,
so that the behavior of subsequent accesses is also undefined.
It is possible for clients to access elements outside the spatial bounds of a variable argument list. Variable argument list implementations will try to detect out-of-bounds reads on a best-effort basis.
Whether this detection succeeds depends on the factory method used to create the variable argument list:
- Variable argument lists created safely, using
make(Consumer, SegmentScope)
are capable of detecting out-of-bounds reads; - Variable argument lists created unsafely, using
ofAddress(long, SegmentScope)
are not capable of detecting out-of-bounds reads
This class is not thread safe, and all accesses should occur within a single thread (regardless of the scope used to obtain the variable arity list).
- Since:
- 19
-
Nested Class Summary
Modifier and TypeInterfaceDescriptionstatic interface
Preview.A builder used to construct a variable argument listPREVIEW. -
Method Summary
Modifier and TypeMethodDescriptioncopy()
Copies this variable argument list at its current position into a new variable argument list associated with the same scope as this variable argument list.empty()
Returns an empty variable argument list, associated with the global scopePREVIEW.make
(Consumer<VaList.BuilderPREVIEW> actions, SegmentScopePREVIEW scope) Creates a variable argument list using a builder (seeVaList.Builder
PREVIEW), with the given scope.nextVarg
(GroupLayoutPREVIEW layout, SegmentAllocatorPREVIEW allocator) Reads the next composite value into a newMemorySegment
, allocated with the provided allocator, and advances this variable argument list's position.nextVarg
(ValueLayout.OfAddressPREVIEW layout) Reads the next address value, wraps it into a native segment, and advances this variable argument list's position.double
nextVarg
(ValueLayout.OfDoublePREVIEW layout) Reads the next value as adouble
and advances this variable argument list's position.int
nextVarg
(ValueLayout.OfIntPREVIEW layout) Reads the next value as anint
and advances this variable argument list's position.long
nextVarg
(ValueLayout.OfLongPREVIEW layout) Reads the next value as along
and advances this variable argument list's position.ofAddress
(long address, SegmentScopePREVIEW scope) Creates a variable argument list from the give address value and scope.segment()
Returns a zero-length memory segmentPREVIEW associated with this variable argument list.void
skip
(MemoryLayoutPREVIEW... layouts) Skips a number of elements with the given memory layouts, and advances this variable argument list's position.
-
Method Details
-
nextVarg
Reads the next value as anint
and advances this variable argument list's position. The behavior of this method is equivalent to the Cva_arg
function.- Parameters:
layout
- the layout of the value to be read.- Returns:
- the
int
value read from this variable argument list. - Throws:
IllegalStateException
- if the scope associated with this variable argument list is not alivePREVIEW.WrongThreadException
- if this method is called from a threadT
, such thatsegment().scope().isAccessibleBy(T) == false
.NoSuchElementException
- if an out-of-bounds read is detected.
-
nextVarg
Reads the next value as along
and advances this variable argument list's position. The behavior of this method is equivalent to the Cva_arg
function.- Parameters:
layout
- the layout of the value to be read.- Returns:
- the
long
value read from this variable argument list. - Throws:
IllegalStateException
- if the scope associated with this variable argument list is not alivePREVIEW.WrongThreadException
- if this method is called from a threadT
, such thatsegment().scope().isAccessibleBy(T) == false
.NoSuchElementException
- if an out-of-bounds read is detected.
-
nextVarg
Reads the next value as adouble
and advances this variable argument list's position. The behavior of this method is equivalent to the Cva_arg
function.- Parameters:
layout
- the layout of the value- Returns:
- the
double
value read from this variable argument list. - Throws:
IllegalStateException
- if the scope associated with this variable argument list is not alivePREVIEW.WrongThreadException
- if this method is called from a threadT
, such thatsegment().scope().isAccessibleBy(T) == false
.NoSuchElementException
- if an out-of-bounds read is detected.
-
nextVarg
Reads the next address value, wraps it into a native segment, and advances this variable argument list's position. The behavior of this method is equivalent to the Cva_arg
function. The returned segment's base MemorySegment.address()PREVIEW is set to the value read from the variable argument list, and the segment is associated with the global scopePREVIEW. Under normal conditions, the size of the returned segment is0
. However, if the provided layout is an unboundedPREVIEW address layout, then the size of the returned segment isLong.MAX_VALUE
.- Parameters:
layout
- the layout of the value to be read.- Returns:
- a native segment whose addressPREVIEW is the value read from this variable argument list.
- Throws:
IllegalStateException
- if the scope associated with this variable argument list is not alivePREVIEW.WrongThreadException
- if this method is called from a threadT
, such thatsegment().scope().isAccessibleBy(T) == false
.NoSuchElementException
- if an out-of-bounds read is detected.
-
nextVarg
Reads the next composite value into a newMemorySegment
, allocated with the provided allocator, and advances this variable argument list's position. The behavior of this method is equivalent to the Cva_arg
function. The provided group layout must correspond to a C struct or union type.How the value is read in the returned segment is ABI-dependent: calling this method on a group layout with member layouts
L_1, L_2, ... L_n
is not guaranteed to be semantically equivalent to perform distinct calls tonextVarg
for each of the layouts inL_1, L_2, ... L_n
.The memory segment returned by this method will be allocated using the given
SegmentAllocator
PREVIEW.- Parameters:
layout
- the layout of the value to be read.allocator
- the allocator to be used to create a segment where the contents of the variable argument list will be copied.- Returns:
- the
MemorySegment
value read from this variable argument list. - Throws:
IllegalStateException
- if the scope associated with this variable argument list is not alivePREVIEW.WrongThreadException
- if this method is called from a threadT
, such thatsegment().scope().isAccessibleBy(T) == false
.NoSuchElementException
- if an out-of-bounds read is detected.
-
skip
Skips a number of elements with the given memory layouts, and advances this variable argument list's position.- Parameters:
layouts
- the layouts of the values to be skipped.- Throws:
IllegalStateException
- if the scope associated with this variable argument list is not alivePREVIEW.WrongThreadException
- if this method is called from a threadT
, such thatsegment().scope().isAccessibleBy(T) == false
.NoSuchElementException
- if an out-of-bounds read is detected.
-
copy
Copies this variable argument list at its current position into a new variable argument list associated with the same scope as this variable argument list. The behavior of this method is equivalent to the Cva_copy
function.Copying is useful to traverse the variable argument list elements, starting from the current position, without affecting the state of the original variable argument list, essentially allowing the elements to be traversed multiple times.
- Returns:
- a copy of this variable argument list.
- Throws:
IllegalStateException
- if the scope associated with this variable argument list is not alivePREVIEW.WrongThreadException
- if this method is called from a threadT
, such thatsegment().scope().isAccessibleBy(T) == false
.
-
segment
MemorySegmentPREVIEW segment()Returns a zero-length memory segmentPREVIEW associated with this variable argument list. The contents of the returned memory segment are platform-dependent. Whether and how the contents of the returned segment are updated when iterating the contents of a variable argument list is also platform-dependent.- Returns:
- a zero-length memory segmentPREVIEW associated with this variable argument list.
-
ofAddress
Creates a variable argument list from the give address value and scope. The address is typically obtained by callingMemorySegment.address()
PREVIEW on a foreign memory segment instance. The provided scope determines the lifecycle of the returned variable argument list: the returned variable argument list will no longer be accessible, and its associated off-heap memory region will be deallocated when the scope becomes not alivePREVIEW.This method is restricted. Restricted methods are unsafe, and, if used incorrectly, their use might crash the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on restricted methods, and use safe and supported functionalities, where possible.
- Parameters:
address
- the address of the variable argument list.scope
- the scope associated with the returned variable argument list.- Returns:
- a new variable argument list backed by an off-heap region of memory starting at the given address value.
- Throws:
IllegalStateException
- ifscope
is not alivePREVIEW.WrongThreadException
- if this method is called from a threadT
, such thatscope.isAccessibleBy(T) == false
.UnsupportedOperationException
- if the underlying native platform is not supported.IllegalCallerException
- If the caller is in a module that does not have native access enabled.
-
make
Creates a variable argument list using a builder (seeVaList.Builder
PREVIEW), with the given scope. The provided scope determines the lifecycle of the returned variable argument list: the returned variable argument list will no longer be accessible, and its associated off-heap memory region will be deallocated when the scope becomes not alivePREVIEW.Note that when there are no elements added to the created va list, this method will return the same as
empty()
.- Implementation Note:
- variable argument lists created using this method can detect out-of-bounds reads.
- Parameters:
actions
- a consumer for a builder (seeVaList.Builder
PREVIEW) which can be used to specify the elements of the underlying variable argument list.scope
- the scope to be associated with the new variable arity list.- Returns:
- a new variable argument list.
- Throws:
UnsupportedOperationException
- if the underlying native platform is not supported.IllegalStateException
- ifscope
is not alivePREVIEW.WrongThreadException
- if this method is called from a threadT
, such thatscope.isAccessibleBy(T) == false
.
-
empty
Returns an empty variable argument list, associated with the global scopePREVIEW. The resulting variable argument list does not contain any argument, and throwsUnsupportedOperationException
on all operations, except forsegment()
,copy()
.- Returns:
- an empty variable argument list.
- Throws:
UnsupportedOperationException
- if the underlying native platform is not supported.
-
VaList
when preview features are enabled.