[foreign-memaccess] RFC: to scope or not to scope?
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Jun 3 22:50:26 UTC 2019
One clarification of this.
There is an API side to this story, and an implementation side.
The main question I'm asking here is about the value of MemoryScope _in
the API_.
Implementation-wise there's always going to be some mutable state
somewhere (since either Scopes or MemorySegments can be closed). But I
don't see how getting rid of Scope in the API would necessarily mean
giving it up in the implementation. We could have a Scope-like
abstraction in the implementation, and have it attached to a
MemorySegment. Do you want to slice a segment? Fine, you obtain a new
segment with new bounds, and same scope object as before. But this is,
the way I see it, mostly an implementation detail, and I think we have
enough freedom to go in any direction we want with the impl, from more
'value class' hostile, to more 'value class' friendly.
To me the important question is the user model one - is this something
we think make sense:
try (MemoryScope scope = MemoryScope.globalScope().fork()) {
MemoryAddress address = scope.allocate(bytes);
}
That is, how important is it, in the user model, that addresses/segments
come from a third abstraction called scope? Or is this going to be
perceived as an attractive nuisance?
And, again, are we comfortable with the fact that Scope acts as a
de-facto allocator, therefore making an hard-wired choice that is going
to work in certain cases, but not in others? (our current scope tries to
limit system calls to allocate memory, but it does so at expense of
footprint, and there's no opt-out). Yes, we could add 10 different
scopes, but wouldn't it better to have something simpler/closer to
Unsafe::allocateMemory/freeMemory and let people build complex
allocation strategies on top?
I think if you pull the string, you end up in a place where either
MemoryScope disappears (after all clients want to allocate/use
memory/free it, so they can just allocate a segment within a
try-with-resource block); or maybe it's something completely
_orthogonal_ which helps you managing _groups_ of segments, but that is
not forced on clients by default. But if it's orthogonal, it still means
that a client should be able to close its own segment w/o necessarily
relying on a scope, which then raises some of the same implementation
issues that I've seen discussed in this thread.
My claim is that the API can be simplified - and that you still end up
with an implementation that is not too far from the one we have now
(e.g. an implementation that knows about 'scopes' internally, although
we would rip allocation strategy out of such simpler scopes). Which
means same abilities to take stateless snapshot views, etc.
My second claim is that, while in principle we could entertain the idea
of having a simpler _optional_ scope concept in the API, in reality
managing big groups of segments with inter-dependent lifecycles is not
really the focus of this low level API. I can see the appeal of
something like that when e.g. talking about C interop and pointers; but
I think for this API the focus should be on simplicity (as simpler here
typically means faster) and composability - as we want to make sure that
the rich idioms we wanna be able to express are going to be well
supported by these foundations.
Maurizio
On 03/06/2019 22:17, John Rose wrote:
> But if we merge down Scope into MemorySegment, we*must* make
> MS stateful, and thus give it an identity. At that point, I think we lose
> the ability to quickly make fresh views of the MS.
>
> I think a "sweet spot" in this design, for my taste, might be to keep
> Scope, and restrict it a one-shot state diagram. Need to open the
> same MS twice in two places? No problem, but make two Scopes.
> If you want a swarm of threads to jointly work on a workload, you'll
> want a smart Scope that can manage the A and E events of that.
>
> (And a one-shot scope can be further confined, not just to a thread,
> but also to a particular stack frame, as outlined above.)
>
> Meanwhile, a MS can be sliced and diced and re-viewed, statelessly,
> any number of times. Access control consists simply of holding back
> access to the MS (or perhaps to endowing the MS with a token that
> confers access, so the MS can be published safely, if that's desirable).
> Code that creates MS views has to take serious responsibility for
> preventing racing access, and for documenting circumstances where
> races might happen. So perhaps MS factories are privileged.
> (Or else they have token-checked accessors, and making a token
> is privileged. The token might be the global Unsafe instance if
> we don't need fine distinctions of privilege.)
>
> Merging scopes with MSs would over-constrain the design in such
> a way that we'd have to throw away some use cases we'd rather
> not. At least that's the way it looks to me. If you can't reslice
> MSs statelessly, because they are doubling as the stateful guardians
> of confinement, then suddenly you can't delegate restricted view,
> or else you have to define a new type for such a view, and that new
> type ends up being MS again.
More information about the panama-dev
mailing list