Different treatments of offsets in MemorySegment.set and copy methods.
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Thu Jun 22 08:38:11 UTC 2023
On 22/06/2023 08:03, Andrii Lomakin wrote:
> Hi team.
> I am working with foreign API and noticed that offsets are treated
> differently for the "set" and "copy" methods of MemorySegment in the
> case of heap-based segments.
>
> If I create a segment from let's say, byte[] and call "set(OfDouble,
> 0)" on such a segment it doesn't take array offset into account during
> the calculation of the applied offset value. So it processes this
> offset as is, and I get an exception about address misalignment.
The alignment exception is by design. If you want to work with unaligned
values (because we can’t really guarantee any alignment when working on
a byte[]), then you can use the JAVA_DOUBLE_UNALIGNED constant.
> But if I pass offsets into the "copy" method, they are automatically
> corrected.
There are several copy methods in memory segments, which all bottom out
here:
|static void copy(MemorySegment srcSegment, ValueLayout
srcElementLayout, long srcOffset, MemorySegment dstSegment, ValueLayout
dstElementLayout, long dstOffset, long elementCount) { ... } |
Now, as you can see this method takes two layouts. The layouts are used
to determine alignment of the copy, as well as byte swap.
If you pass JAVA_DOUBLE to this copy method you should get exactly the
same exception you get with the get/set method. But note that the copy
method that doesn’t take a layout just uses JAVA_BYTE underneath, so
that might be why you get the impression that the copy is working. See
below:
|jshell> var seg = MemorySegment.allocateNative(10,
SegmentScope.auto()); seg ==> MemorySegment{ array: Optional.empty
address:140000700364496 limit: 10 } jshell> var byteSeg =
MemorySegment.ofArray(new byte[10]); byteSeg ==> MemorySegment{ array:
Optional[[B at 7e6cbb7a] address:0 limit: 10 } jshell>
MemorySegment.copy(byteSeg, 0, seg, 0, 10); // ok, because it uses
JAVA_BYTE jshell> MemorySegment.copy(byteSeg, JAVA_DOUBLE, 0, seg,
JAVA_DOUBLE, 0, 1); // fails | Exception
java.lang.IllegalArgumentException: Source segment incompatible with
alignment constraints | at MemorySegment.copy (MemorySegment.java:1352)
| at (#6:1) jshell> MemorySegment.copy(byteSeg, JAVA_DOUBLE_UNALIGNED,
0, seg, JAVA_DOUBLE_UNALIGNED, 0, 1); // ok again |
The treatment of alignment w.r.t. heap segments is explained in great
details here:
https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/lang/foreign/MemorySegment.html
(Java 21 has a similar section).
Note that this has nothing to do with methods not treating offsets
uniformly - offsets are in fact treated uniformly, and always checked
against the alignment constraints of the layout being used for the
dereference operation.
If you don’t care about alignment, use unaligned layouts (for which
constants are also provided), or use segments that wrap long[], which
allow for more alignment.
The current behavior is kind of a forced move, driven by the fact that
heap segments have different alignment properties based on platform and
JVM implementation. So the alignment of heap segment is defined in terms
of the lowest common denominator. If the API didn’t do this, you might
write some code using memory segments that would work well in one
platform and then fail on another because of different alignment
constraints. While platform-dependent behavior is fair game when
interacting with native code, in this case you would be able to get
platform-dependent behavior only when accessing memory, and we didn’t
want that (as this API will likely be used as a replacement for
ByteBuffer in many cases, e.g. even when no native interop is needed).
Cheers
Maurizio
> Is it done by design?
> IMHO, both methods should treat offsets uniformly, and that is not
> taking into account that such treatments of offsets in "set" methods
> make it very hard to work with heap-based segments.
>
> P.S. I am using JDK 20.
> --
> Best regards,
> Andrii Lomakin.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20230622/956a854a/attachment-0001.htm>
More information about the panama-dev
mailing list