[Integrated] [foreign-memaccess] RFR: Move MemoryAddress::copy

John Rose john.r.rose at oracle.com
Sat May 16 01:49:09 UTC 2020

On May 15, 2020, at 6:19 PM, John Rose <john.r.rose at oracle.com> wrote:
> Nice work; thank you.
> When working with an address a, you often want to copy
> memory to or from that address, and (independently)
> before or after that address.  In C the corresponding
> pointer operations would be of form like this:
>   *p = *q;  // copy element at (= just after) pointer
>   p[0] = q[0];  // ditto
>   p[i] = q[j];  // copy indexed elements near p and q
>   *p++ = *q++;  // same, with auto-increment
>   *--p = *--q;  // copy element just before pointer + auto-incr.
> I guess the Panama code for such operations would contain
> expressions like this:
>   p.segment().asSlice(a.segmentOffset(), (some size)).copyFrom(q…)
> What are the natural idioms that might benefit the user,
> who wants to get smoothly from a MA p to a copyFrom operation?
> It seems to me that one possible primitive would be sized slice
> creator:
>    MemoryAddress sliceAfter(long size) {
>        return segment().asSlice(segmentOffset(), size);
>    }
> That is good for source operands, since the “size” value needs to
> be attached to the MA in order to get the right slice, and copyFrom
> takes the size from the source, not the destination.
> For sources of the form *--q, maybe this also:
>    MemoryAddress sliceBefore(long size) {
>        return segment().asSlice(segmentOffset() - size, size);
>    }
> Or maybe this combo:
>    MemoryAddress sliceAt(int index, long size) {
>        return segment().asSlice(segmentOffset() + (size * index), size);
>    }
> Then sliceAt(0,s) == sliceAfter(s) and sliceAt(-1,s) == sliceBefore(s).
> That suggests that the latter forms (sliceAfter(s)) are redundant,
> and that sliceAt is the interesting primitive.
> Another use case is an *unsized* slice creator for destination operands.
> This allows the sizing information to flow naturally (without redundancy)
> from the data source through copyFrom:
>    MemoryAddress sliceAfter() {
>        return segment().asSlice(segmentOffset(), segment().byteSize() - segmentOffset());
>    }
> Maybe for symmetry, and for cutting off buffers after a fill pointer, this too:
>    MemoryAddress sliceBefore() {
>        return segment().asSlice(0, segmentOffset());
>    }
> Anyway, I like the way MS is shaping up, as a small bounded location of
> state, and MA as a working pointer therein.  You all have probably had
> similar thoughts about “what sort of sugary methods we might eventually
> place on MA”.  The placement of MS::copyOf unlocked some of those ideas
> for me, and the above is what I came up with, FWIW.
> — John

P.S. A little more:  One idiom I didn’t cover was copying
something before the destination pointer, a in this:

   *--p = *q

Here, a user will reach for an expression like this:

   p.addOffset(-(some size)).copyFrom(q.sliceAfter(same size));

The need to repeat the same size in two places is a breeding
ground for bugs and non-readable code.  It seems like we would
want a method on MA which takes a source MS and *then* creates
a destination MS based on the MS and the size of the *source*.
That’s not needed for copying something *after* a pointer,
but it is needed for copying *before*.

Something like this would help.  The destination pointer can
be returned for optional use:

  MemoryAddress copyBeforeFrom(MemorySegment src) {
     MemoryAddress predec = addOffset(src.byteSize());
     return predec;

For symmetry, there could be this also:

  MemoryAddress copyAfterFrom(MemorySegment src) {
     MemoryAddress postinc = addOffset(src.byteSize());
     return postinc;

More information about the panama-dev mailing list