3

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?

sqlearner
  • 97
  • 5
  • As a first approximation, I would assume that you can serialize your Object to a ByteArrayStream, and then you move that to the native memory segment. But I have just read the management summary for Panama, so I may be on a completely wrong track ... – tquadrat Jun 11 '21 at 21:04
  • @tquadrat You're definitely on the wrong track. That is a completely fine approach if the only goal is to store the object in native memory, but not process it there. So for example, you can serialize it to a byte array, transfer it to native memory, then send it via a native API for network transfer, read it on another JVM, and then deserialize it there. Serializing a Java object doesn't produce any meaningful format of the data, other than for the deserializing process. – Andreas is moving to Codidact Mar 24 '23 at 04:12

1 Answers1

3

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());
    }
}
Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93