[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());
predec.sliceAfter().copyFrom(src);
return predec;
}
For symmetry, there could be this also:
MemoryAddress copyAfterFrom(MemorySegment src) {
MemoryAddress postinc = addOffset(src.byteSize());
this.sliceAfter().copyFrom(src);
return postinc;
}
More information about the panama-dev
mailing list