Module java.base

Interface VaList


public sealed interface VaList
VaList is a preview API of the Java platform.
Programs can only use VaList when preview features are enabled.
Preview features may be removed in a future release, or upgraded to permanent features of the Java platform.
Helper class to create and manipulate variable argument lists, similar in functionality to a C 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));
Once created, clients can obtain the platform-dependent memory segment associated with a variable argument list, which can then be passed to downcall method handlesPREVIEW targeting native functions using the C 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);
     }
 }
The above method receives a foreign segment modelling a variable argument list; the contents of the segment are accessed by creating a new variable argument list, from the segment address. Note that the variable argument list is first copied into a second list before any element is accessed: this will allow us to iterate through the elements twice. Elements in the variable argument list are accessed using nextVarg(ValueLayout.OfInt) and nextVarg(ValueLayout.OfDouble). These methods (as well as other access methods in the VaListPREVIEW 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 C int 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.OfIntPREVIEW 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:

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
  • Method Details

    • nextVarg

      int nextVarg(ValueLayout.OfIntPREVIEW layout)
      Reads the next value as an int and advances this variable argument list's position. The behavior of this method is equivalent to the C va_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 thread T, such that segment().scope().isAccessibleBy(T) == false.
      NoSuchElementException - if an out-of-bounds read is detected.
    • nextVarg

      long nextVarg(ValueLayout.OfLongPREVIEW layout)
      Reads the next value as a long and advances this variable argument list's position. The behavior of this method is equivalent to the C va_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 thread T, such that segment().scope().isAccessibleBy(T) == false.
      NoSuchElementException - if an out-of-bounds read is detected.
    • nextVarg

      double nextVarg(ValueLayout.OfDoublePREVIEW layout)
      Reads the next value as a double and advances this variable argument list's position. The behavior of this method is equivalent to the C va_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 thread T, such that segment().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 C va_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 is 0. However, if the provided layout is an unboundedPREVIEW address layout, then the size of the returned segment is Long.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 thread T, such that segment().scope().isAccessibleBy(T) == false.
      NoSuchElementException - if an out-of-bounds read is detected.
    • nextVarg

      Reads the next composite value into a new MemorySegment, allocated with the provided allocator, and advances this variable argument list's position. The behavior of this method is equivalent to the C va_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 to nextVarg for each of the layouts in L_1, L_2, ... L_n.

      The memory segment returned by this method will be allocated using the given SegmentAllocatorPREVIEW.

      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 thread T, such that segment().scope().isAccessibleBy(T) == false.
      NoSuchElementException - if an out-of-bounds read is detected.
    • skip

      void skip(MemoryLayoutPREVIEW... layouts)
      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 thread T, such that segment().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 C va_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 thread T, such that segment().scope().isAccessibleBy(T) == false.
    • 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

      static VaListPREVIEW ofAddress(long address, SegmentScopePREVIEW scope)
      Creates a variable argument list from the give address value and scope. The address is typically obtained by calling MemorySegment.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 - if scope is not alivePREVIEW.
      WrongThreadException - if this method is called from a thread T, such that scope.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 (see VaList.BuilderPREVIEW), 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 (see VaList.BuilderPREVIEW) 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 - if scope is not alivePREVIEW.
      WrongThreadException - if this method is called from a thread T, such that scope.isAccessibleBy(T) == false.
    • empty

      static VaListPREVIEW empty()
      Returns an empty variable argument list, associated with the global scopePREVIEW. The resulting variable argument list does not contain any argument, and throws UnsupportedOperationException on all operations, except for segment(), copy().
      Returns:
      an empty variable argument list.
      Throws:
      UnsupportedOperationException - if the underlying native platform is not supported.