[foreign] "implicit" conversions in the memory access API

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Mar 25 21:56:35 UTC 2021


On 25/03/2021 21:28, Maurizio Cimadamore wrote:
>> * we do nothing and leave the API as is (1=D, 2=B)
>> * we go back, remove the Addressable interface (1=A, 2=B)
>> * as before, but we also remove the ResourceScope overloads - no 
>> magic conversions, everything is always explcit (1=A, 2=A)
>> * we see if there's an interface name we like for ResourceScope -> 
>> SegmentAllocator, and remove the overloads, which would then be no 
>> longer necessary (1=D, 2=D)
>> * make ResourceScope <: SegmentAllocator, but leave Addresable (1=D, 
>> 2=C) 
> I think it's either the first bullet (leave everything as is), or the 
> 4th bullet (find a common supertype).

One advantage of a common supertype is that MemorySegment could join in too.

Let's imagine we have an interface Fooable:

ResourceScope <: Fooable
SegmentAllocator <: Fooable
MemorySegment <: Fooable

then, if you have a memory segment-producing API method, you can write 
it as:

MemorySegment convertString(String s, Fooable f) { ... }

then you can use this as:

convertString("hello", scope) --> allocate a new segment associated with 
'scope' and store the results in there
convertString("hello", allocator) --> allocate a new segment, using 
allocator, and store the results in there
convertString("hello", segment) --> store the results in the provided 
segment

Another possibility which we considered at some point, instead of adding 
a common supertype, just add some conversion method (a la 
MemorySegment.address()):

MemorySegment convertString(String s, SegmentAllocator) { ... }

then you can use this as:

convertString("hello", scope.toAllocator()) --> allocate a new segment 
associated with 'scope' and store the results in there
convertString("hello", allocator) --> allocate a new segment, using 
allocator, and store the results in there
convertString("hello", segment.toAllocator()) --> store the results in 
the provided segment

Which is not as concise as the former, but plays better with 
MethodHandle.invokeExact.

That said, with some sprinkling of static imports, with current code you 
can do (assuming there are no overloads):

convertString("hello", scoped(scope)) --> allocate a new segment 
associated with 'scope' and store the results in there
convertString("hello", allocator) --> allocate a new segment, using 
allocator, and store the results in there
convertString("hello", prefix(segment)) --> store the results in the 
provided segment

Which is not that worse (well, at least it seems bikeshed material as to 
whether this is worse or better than the former).

So, I think overall, I stand by the current design - it seems the less 
evil of the various alternatives. The provided overloads reduce 
verbosity in the common case, but even if there were no overloads (e.g. 
in user code) the fallback is not so terrible, thanks to the static 
factories to create allocators from segments and scopes.

That said, I think we uncovered some general sense of unease with how 
the API is promoting use of implicit segments even with the Linker, and 
how this can lead to trouble (when segments are converted to addresses). 
I think we should focus our energy to try and see if we can make the 
linker world more friendly to that use case, and if not, cut back on 
implicit segments (in the CLinker API).

Maurizio




More information about the panama-dev mailing list