[foreign-abi] RFR: JDK-8243669: Improve library loading for Panama libraries
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Tue May 5 10:32:33 UTC 2020
On 02/05/2020 10:34, Samuel Audet wrote:
> On 5/1/20 7:34 PM, Maurizio Cimadamore wrote:
>>
>> On 01/05/2020 10:57, Samuel Audet wrote:
>>> On 4/30/20 7:07 PM, Maurizio Cimadamore wrote:
>>>>> Right, it's not perfect, but I think these kinds of issues are
>>>>> solvable, if we're willing to spend time and work on them. For
>>>>> example, if something like `PointerScope` could be integrated into
>>>>> the Java language itself, we would be able to guarantee that what
>>>>> you describe above never happens, making everything thread-safe. I
>>>>> don't see any limitations in that regards, but I may be missing
>>>>> something. Could you provide an example that fails? Or is there
>>>>> just concern about the performance hit that could be incurred (in
>>>>> which case I'd still say "let's work on it")?
>>>>
>>>> This is the very central issue we're trying to address with memory
>>>> segments: how do you allow access to a segment from multiple
>>>> threads while:
>>>>
>>>> * retaining access performances
>>>> * retaining deterministic deallocation guarantees
>>>>
>>>> It's not a theoretical problem. If you want to make your JavaCPP
>>>> code safe you need to add a mutex so that threads can either access
>>>> memory OR deallocate. Then I'm sure you won't be happy with the
>>>> numbers that will come out of your benchmarks.
>>>>
>>>> Other solutions "include" something like reference counting, but
>>>> not the same reference counting you do in your API. That is, if a
>>>> thread wants to use a "pointer" (in your API) you must create a new
>>>> instance just for that thread, you can't just increment some shared
>>>> counter on the original pointer. That is, the _new_ thread must
>>>> _not_ have access to the original pointer. Otherwise it is possible
>>>> for people to write code where they don't call "retain" and they
>>>> happily access the pointer from multiple threads, but the pointer
>>>> doesn't know about it.
>>>>
>>>> While something like that might be made to work (we had something
>>>> similar with our MemorySegment::acquire), it is not very appealing
>>>> from an API perspective, as it creates "trees" of associated
>>>> segments/pointers where the parent cannot be deallocated until all
>>>> children are.
>>>>
>>>> All this to say what I was trying to say before: wrapping up
>>>> AtomicInteger inside some ARC abstraction is _not_ a solution to
>>>> the problem. First, it doesn't really take that long to implement,
>>>> but, most importantly, having a class which can do
>>>> "retain"/"release" doesn't save you from uncooperative clients
>>>> trying to use an instance from a different thread w/o calling
>>>> "retain".
>>>>
>>>> So, I don't see a lot of value for providing such an abstraction in
>>>> the JDK. The fact that there are libaries out there which might
>>>> rely on reference counting to provide some sort of perceived safety
>>>> doesn't automatically make this a candidate for providing something
>>>> with the degree of safety that would (and should) be expected from
>>>> a Java SE API.
>>>
>>> Thank you for bearing with me, but I must seriously be missing
>>> something. Please explain why the following doesn't work:
>>
>> Are you now proposing a _language_ feature - not just an API?
>
> Yes, that's what I said above. Do you agree this could work?
Changing the language to support reference counting in a language that
is, essentially, garbage-collected, doesn't seem like a great idea.
On top of that, moving the problem onto the language typically amounts
at 'kicking the can down the road'. Constructs like try-with-resources
are already quite convoluted in their attempt to try and detect all the
possible cases in which things could go wrong - see the code that javac
generates for them here
And, despite all that, there are still cases where the close() method in
a TWR can be skipped - and where, if we had to support something
similar, a language change alone would not be sufficient, but a deeper
change to the VM (and GC) would be required if we were to ensure that
the semantics of these 'auto-closeable' entities are correctly managed.
Project Loom explored many of these topics and concluded that TWR alone
was not sufficient to handle the use cases they had (as there was, for
instance, no guarantee that a thread could not be stopped in the middle
of a close() ).
To which you might say "why don't you just do all that?" - and the
answer (which you won't like) is that it feels to me that we are in a
land of diminishing return, where you have to do a lot of effort in
order to do something that is only marginally better to what you could
achieve _today_ with a slightly different API: if your pointer access
API is separated from the pointer API itself, then doing what you
describe can be achieved like this:
Pointer p ....
p.withHandle(PointerHandle ph -> {
ph.get(...)
ph.set(...)
});
p.deallocate() // will fail if there are any pending handles
This is a relatively pleasing API - which has the added benefit that it
makes it extra obvious as to which operations are allowed on with
entities (e.g. you cannot just call `get` on a pointer, it just isn't
there!). This is much simpler for the user to understand (IMHO) than an
API which say "there is a `get` method here, but to call it safely you
must wrap access inside some kind of try-pointer block provided by the
language".
Maurizio
>
> I'm not saying that it's going to be easy, but if the Java community
> doesn't get onto this train, it will be left behind at some point, and
> things will just move on to something else like Python or whatever
> platform where applications that require GPUs, accelerators, etc are
> welcome. I would really hate it if the best humanity can come up with
> is Python.
>
> Samuel
More information about the panama-dev
mailing list