Introducing Arena and MemorySegment 2 – Foreign (Function) Memory API


Setting/getting the content of a memory segment

The Arena API provides a set of allocate() methods that can be used to allocate a memory segment and set its content in the same line of code (in the previous section, we have used only the allocate() flavors that allocate memory segments but don’t set their content). For instance, calling allocate(OfInt layout, int value) allocates a memory segment for storing an int and sets that int to the given value (OfInt is an interface that extends ValueLayout). Here we consider the int as being Integer.MAX_VALUE:

MemorySegment segment = arena.allocate(
  ValueLayout.JAVA_INT, Integer.MAX_VALUE);          

Or, here we allocate a memory segment for a char and set that char to a (allocate(OfChar layout, char value)):

MemorySegment segment = arena.allocate(
  ValueLayout.JAVA_CHAR, ‘a’);

But, if we want to set the content of a memory segment later (not in the same time as the allocation) then we can use the MemorySegment.set() or setAtIndex() methods.For instance, we can set the Integer.MAX_VALUE via set(OfInt layout, long offset, int value) as follows:

MemorySegment segment = …;
segment.set(ValueLayout.JAVA_INT, 0, Integer.MAX_VALUE);

The second argument is the offset (0, 4, 8, 12, …) which in this case must be 0. Alternatively, we can use setAtIndex(OfInt layout, long index, int value) as follows:

segment.setAtIndex(
  ValueLayout.JAVA_INT, 0, Integer.MAX_VALUE);

Here, the second argument represents an index exactly as in an array (0, 1, 2, 3…). In this case, it must be 0 since we have a single integer stored in the memory segment.Getting content from a certain offset can be done via get() and from a certain index via getAtIndex() methods. For instance, getting the int stored at a certain offset can be obtained via get(OfInt layout, long offset):

int val = segment.get(ValueLayout.JAVA_INT, 0);

And, the int stored at a certain index via getAtIndex(OfInt layout, long index) as follows:

int val = segment.getAtIndex(ValueLayout.JAVA_INT, 0);

In the next problems, you’ll see more examples of using these methods.

Working with Java strings

Allocating a memory segment for storing a Java String is a special case. If we have an Arena instance then we can allocate a memory segment and set its content as a Java String via allocateUtf8String(String str) as follows (here, the Java string is abcd):

MemorySegment segment = arena.allocateUtf8String(“abcd”);

The allocateUtf8String(String str) converts a Java String into a C-like string that is UTF-8 encoded and null-terminated. The size of the memory segment is obtained as str.length + 1. Relying on MemorySegment.allocateNative() will allocate a segment for the abcd string as follows:

MemorySegment segment = MemorySegment
  .allocateNative(5, arena.scope());

Or, more expressive:

MemorySegment segment = MemorySegment
  .allocateNative(“abcd”.length() + 1, arena.scope());

Having the allocated memory segment, we can set the string via setUtf8String(long offset, String str) as follows:

segment.setUtf8String(0, “abcd”);

Offset 0 means exactly at the start of the memory segment. Since this memory segment has the size computed to fit exactly the string abcd, we cannot have another offset than 0. For instance the following snippet results in an IndexOutOfBoundsException:

segment.setUtf8String(1, “abcd”);

Getting the string stored in a memory segment can be done via MemorySegment.getUtf8String(long offset), so we can do it as follows:

String str = segment.getUtf8String(0);

You can practice all these examples in the bundled code.

Leave a Reply

Your email address will not be published. Required fields are marked *