javajava-ffmvarhandle

VarHandle for arrays of dynamic size


How can a VarHandle instance be created to access elements of a dynamically sized array (in the context of the Foreign Function and Memory API)?

package org.example;

import java.lang.foreign.*;
import java.lang.invoke.VarHandle;

public class ArrayVarHandle {

    static final StructLayout coordinateLayout = MemoryLayout.structLayout(
            ValueLayout.JAVA_INT.withName("x"),
            ValueLayout.JAVA_INT.withName("y")
    );

    static final SequenceLayout arrayLayout = MemoryLayout.sequenceLayout(1, coordinateLayout);

    static final VarHandle xInArrayVarHandle = arrayLayout.varHandle(
            MemoryLayout.PathElement.sequenceElement(),
            MemoryLayout.PathElement.groupElement("x")
    );

    public static void main(String[] args) {
        try (var arena = Arena.ofConfined()) {
            int count = 10;
            var array = arena.allocate(coordinateLayout, count);
            setXValues(array, count);
        }
    }

    static void setXValues(MemorySegment array, int count) {
        for (int i = 0; i < count; i++)
            xInArrayVarHandle.set(array, 0, i, 100);
    }
}

This code fails with the exception:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
    at org.example.ArrayVarHandle.setValues(ArrayVarHandle.java:30)
    at org.example.ArrayVarHandle.main(ArrayVarHandle.java:24)

Obviously, it checks the boundaries of the layout arrayLayout. It is declared with elementCount = 1 (first parameter).

If it is instead declared with elementCount = 999999, the error changes:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ address: 0x6000014b8140, byteSize: 80 }; new offset = 0; new length = 7999992
    at org.example.ArrayVarHandle.setValues(ArrayVarHandle.java:30)
    at org.example.ArrayVarHandle.main(ArrayVarHandle.java:24)

So it checks the size of the layout against the size of the memory segment, and fails again.

Is it possible to create an array/sequence layout without a fixed size? Or create the VarHandle differently?

In the above example, count has a fixed value. But in the real application, the count is not known at compile-time. And the goal would be to create the VarHandle instance once, and not on every call of the method.


Solution

  • It sounds like you're not looking for SequenceLayout (which, as you've observed, is intended for use with fixed-size arrays), but instead you're looking for arrayElementVarHandle, which is intended for variable-length arrays. You'd then allocate with arena.allocate(coordinateLayout, count).

    This is explicitly addressed in this section of the documentation.