Search code examples
javabufferproject-panama

How to store an Object-Array in native Memory using Java Panama


I want to implement a datastructure in native memory using the Foreign Memory Access API of Project Panama.

In order to do that I need an underlying Object array (Object[]) for the entries.

In all the examples for the Foreign Memory Access API, MemorySegments are only used to store and retrieve primitives like so:

//I would like to use Object here instead of int
ResourceScope scope = ResourceScope.newConfinedScope();
SequenceLayout layout = MemoryLayout.sequenceLayout(100, MemoryLayouts.JAVA_INT); 
VarHandle intHandle = seq.varHandle(int.class, sequenceElement());
MemorySegment segment = MemorySegment.allocateNative(layout, scope);

Is there a way to store non primitives in a MemorySegment (e.g. Object)? And if that is the case how can I dereference that MemorySegment using a VarHandle, when VarHandles only support primitive carriers?


Solution

  • Is there a way to store non primitives in a MemorySegment (e.g. Object)?

    No, at least not directly. Objects are managed by the Java runtime, and they can not be safely stored in native memory (for instance because the garbage collector would not be able to trace object references inside objects in native memory).

    However, as noted in the comments, for your purposes it might be enough to store the data inside an object in native memory. For instance, if an object contains only primitive fields (though, the same could be done recursively for object fields), it would be possible to write each such field separately to native memory. For example (with the JDK 16 API):

    public static void main(String[] args) {
        try (MemorySegment segment = MemorySegment.allocateNative(Widget.NATIVE_LAYOUT)) {
            Widget widget1 = new Widget(1, 2);
            widget1.write(segment);
    
            Widget widget2 = Widget.read(segment);
            System.out.println(widget2); // Widget[x=1, y=2]
        }
    }
    
    record Widget(int x, int y) {
        static final MemoryLayout NATIVE_LAYOUT = MemoryLayout.ofStruct(
            MemoryLayouts.JAVA_INT.withName("x"),
            MemoryLayouts.JAVA_INT.withName("y")
        );
    
        static final VarHandle VH_x = NATIVE_LAYOUT.varHandle(int.class, MemoryLayout.PathElement.groupElement("x"));
        static final VarHandle VH_y = NATIVE_LAYOUT.varHandle(int.class, MemoryLayout.PathElement.groupElement("y"));
    
        public static Widget read(MemorySegment segment) {
            int x = (int) VH_x.get(segment);
            int y = (int) VH_y.get(segment);
            return new Widget(x, y);
        }
    
        public void write(MemorySegment segment) {
            VH_x.set(segment, x());
            VH_y.set(segment, y());
        }
    }