dissecting the Scope API

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Sat Dec 22 22:02:27 UTC 2018


Hi David,
yes, I knew about these articles as Alex pointed me at them few months 
ago - but thanks for the reference.

For the records, Loom is also exploring similar directions for managing 
lifecycle of groups of logically connected fibers.

Maurizio

On 22/12/2018 06:53, David Holmes wrote:
> Hi Maurizio,
>
> On a casual read aspects of this are sounding like RTSJ MemoryAreas 
> [1][2][3], which define allocation contexts which allow for a 
> bounded/scoped lifetime (and very strong rules about allowing things 
> to be referenced from other scopes).
>
> Are you aware of those? John may have mentioned them.
>
> Cheers,
> David
>
> [1] http://www.rtsj.org/specjavadoc/book_index.html
> [2] 
> https://docs.oracle.com/javase/realtime/doc_2.1/release/rtsj-docs/javax/realtime/MemoryArea.html
> [3] http://janvitek.org/pubs/isorc04.pdf "Real-Time Java Scoped 
> Memory: Design Patterns and Semantics", by Vitek, Pizlo, Fox & Holmes
>
>
> On 22/12/2018 10:18 am, Maurizio Cimadamore wrote:
>> Hi,
>> as mentioned in a recent email, I think the Scope API is conflating 
>> several aspects together, which makes it difficult to discuss it 
>> and/or evolve it into a more stable API. This email is an attempt at 
>> teasing apart the various aspects of the Scope API; while it's not 
>> meant to be a full proposal, I think there are many ideas in here 
>> worthy of more consideration. Much of the credits for the ideas in 
>> here go to Steve Dohrmann from Intel and Jorn Vernee who recently 
>> started a discussion on this [1]; Henry Jen also provided some 
>> insights into the dual nature played by the Scope API.
>>
>> So, before jumping into some pseudocode, let's review some basic key 
>> points:
>>
>> * I believe Scope is condensing two aspects: it has an allocation 
>> interface (Scope::allocateXYZ), but it also serves as a life-cycle 
>> management. While in the end we might (or not) end up to conflate the 
>> two, let's try to keep them separated for now
>>
>> * Let's try to get there in layers (as we did for the SystemABI); 
>> there are clearly low level allocators - e.g. things that just give 
>> you a slab of memory - called memory regions - and high-level 
>> allocators, e.g. things that can allocate user defined data (structs, 
>> arrays, etc.)
>>
>> * We'd like the approach to scale, if possible, to different kind of 
>> memories (heap, offheap, NVM, ...)
>>
>> * Let's double down on the Pointer abstraction to do the memory 
>> dereference; e.g. let's not add methods to a memory abstraction a la 
>> Unsafe (get/putLong, ...) instead, let's have a way to get a Pointer 
>> out of a memory region
>>
>> So, let's start... the first thing we need is something that creates 
>> memory regions:
>>
>> interface MemoryStore {
>>     MemoryRegion allocate(long size);
>>     MemoryRegion allocate(Access access, long size);
>>     void free(MemoryRegion region);
>>
>>     interface Access {
>>        READ, WRITE, READ_WRITE;
>>     }
>>
>>     static MemoryStore offheapStore() { ... }
>>     static MemoryStore heapStore() { ... }
>>     ... //others?
>> }
>>
>> So far so good, we can create regions, with given access etc. Note 
>> that here I'm trying to hide the addressing model used by Unsafe 
>> (Object + long offset); after all, the addressing model depends on 
>> the kind of memory you are operating on, so I don't think it's good 
>> to expose it via the API (if we can avoid doing so).
>>
>> What is a memory region? Here:
>>
>>
>> interface MemoryRegion {
>>     MemoryStore store();
>>     Pointer<?> basePointer();
>>     //maybe ByteBuffer accessor too?
>>     boolean checkAlive();
>>     boolean checkAccess(Memory.Access access);
>>     long size();
>> }
>>
>> As Jorn (and separately, Steve) suggested, this could be the place 
>> where we add the logic for liveness check - more specifically, a 
>> memory region is considered alive unless freed on its corresponding 
>> store. Interestingly, a memory region has a way to retrieve a pointer 
>> to its base location. We can assume it will be a void pointer and 
>> that the client will have to cast accordingly; this is, after all, a 
>> low level API. This is also a very general API - it's not really 
>> specific to Panama - other than the fact that a memory region can be 
>> projected to a Pointer - but we can imagine other useful projections 
>> too (e.g. Bytebuffers).
>>
>> What about high-level allocation? This is where Panama-related 
>> concepts start to kick in:
>>
>>
>> abstract class Allocator {
>>     Allocator(MemoryStore store);
>>
>>     public <Z> Pointer<Z> allocate(LayoutType<Z> type);
>>     public <Z extends Struct<Z>> allocateStruct(Class<Z> strClass);
>>     ... //other allocation factories
>> }
>>
>> So, an allocator takes a store, and then implements the various 
>> allocation functions; it is easy to see how such allocation functions 
>> can be implemented: they will typically obtain a region (using the 
>> store) of a given size (given by some LayoutType), then obtain a 
>> pointer from the region and cast it to the desired type.
>>
>> What about scope-ness? Let's start from here:
>>
>> abstract class ScopedAllocator extends Allocator implements 
>> AutoCloseable {
>>      ScopedAllocator(MemoryStore store);
>>     public void close() //this makes sure that all regions created 
>> within this 'scope' are automatically freed
>> }
>>
>> So, this is a special allocator that also supports the AutoCloseable 
>> interface, and can therefore be used with a try-with-resources, in 
>> the usual way. In other words, clients will often do things like:
>>
>> try (Scope sc = new ScopedAllocator(MemoryStore.offheapStore())) {
>>      sc.allocateStruct(...)
>> }
>>
>> You can think of this as an allocator that keeps track of the regions 
>> it creates, and frees them as soon as you call close().
>>
>> I think this looks more or less equivalent to what we have now, but 
>> we have captured and broken down the primitive concepts more clearly 
>> now. There's a *store* that is responsible for allocating regions 
>> (all relatively Panama-agnostic), and high level allocators, built on 
>> top of stores, which provide the user facing allocation facilities. 
>> Scoped allocators keep track of memory region usages, to allow for 
>> automatic collection upon closing.
>>
>> One remarkable thing is that Scope/Resource have disappeared from 
>> this API - the features available in the current Scope interface have 
>> been split between memory regions and allocators. I think there could 
>> be ways to add back explicit scopes into this flavor of the API - but 
>> I think that, before we jump to that, it's better to stop and ask - 
>> what are the use cases that would not be covered by this proposal?
>>
>> Maurizio
>>
>> [1] - 
>> http://mail.openjdk.java.net/pipermail/panama-dev/2018-December/003572.html
>>
>>


More information about the panama-dev mailing list