[foreign] RFR 8217420: Have UniversalNativeInvoker and UniversalUpcallHandler create (and close) the scopes used by boxing code
Jorn Vernee
jbvernee at xs4all.nl
Tue Jan 22 11:15:19 UTC 2019
Comments inline...
John Rose schreef op 2019-01-22 01:47:
> On Jan 21, 2019, at 10:13 AM, Jorn Vernee <jbvernee at xs4all.nl> wrote:
>
>> We have 2 options here:
>>
>> 1.) Go with C style. Struct arguments are valid only during an
>> upcall, and we have to manually copy them if we want to 'leak' them
>> from the scope of the upcall.
>> 2.) Go with status quo. Struct doesn't need to be copied manually
>> when saving it outside the scope of the upcall. The copy is
>> defensively done in Windows boxing code instead, and sometimes
>> redundant. Only on Windows (for now), struct arguments to an upcall
>> have to be manually released to avoid a memory leak.
>
> I wouldn't call #1 C style, but rather ABI style. C style allows
> by-value
> passes of structs in all directions, with zero concern for pointer
> scoping,
> because the pointers are kept invisible.
>
> I think #2 is closer to C style, properly understood, but it's not
> perfect
> either if it requires manual deallocation.
>
> So, calling #1 ABI style, we then also have:
>
> 3.) Go with C style. Struct arguments (as opposed to pointers to
> structs)
> are passed by value and all appearances in Java exhibit value-like
> semantics,
> which includes no lifetime constraints. The struct is copied onto the
> Java
> heap, defensively, and is preserved there with no writability. If we
> had
> true Valhalla value types, it could be a value object instance, but it
> should
> be at least a value-based class.
I have not been keeping up with Valhalla lately.
Having value-like semantics in Java would mean embedding the bit-image
directly into the value-type object right? I thought the tech was not
there yet for this. I think you'd need some kind of fixed-length long[]
that is fused into the struct object and gets copied along with it? This
has the same problem that a user would need to create an off-heap copy
if they wanted to pass a pointer to it to a C function (that you
mentioned later). Or could there be support for direct pointers to value
types, as alternative to the Object + offset scheme in Unsafe right now?
(since they don't get moved by the GC, right?).
> There's still a trade-off here, as usual. Putting the struct
> bit-image
> on the Java heap means it is safe to share across threads and across
> scopes, and will be GC-ed when no longer in use. That's all good.
> The downside is you can only use it for further by-value actions,
> such as passing it as an argument later on to a down-call or storing
> it bitwise into a container. If you need to pass an address for the
> struct data to a C function, that address needs to point to a scoped
> off-heap copy of the struct value. Internally, at the ABI level, the
> by-value calling sequence will almost certainly need to recopy the
> struct into registers or into a stack buffer: But that's what C does
> anyway, so that copy doesn't really bear on the decision to store
> struct values on-heap or off-heap.
>
> Also, design issues for arguments to up-calls are often paralleled
> with returns from down-calls, and it's probably true in this case.
> Whatever policy we go with for by-value structs should apply
> equally to up-call arguments and down-call returns.
The way I think this would work for down-call returns is that; a
by-value struct return constitutes a transfer of resources to the
caller. In native code this is also true, but the returned value
immediately gets automatic storage duration, because it's a value type.
But, on the Java side the value resides (currently) off-heap, and
_someone_ has to manage this resource. So I feel we'd need to teach
users that they have to keep that in mind (maybe with some
@ResourceTransfer annotation).
In the patch this is asymmetrical with upcalls, and I didn't find a way
of doing something automatic for struct by-value returns yet. I
experimented with tying the returned value's Scope to the lifetime of
the returned Struct object using a Cleaner. But, I realized this also
means that whenever you want to pass a pointer to the struct to a C
function it's up to the caller to keep the object alive, and if the
passing of this pointer is meant as a resource-transfer then you'd
really want a way to detach the object from the Cleaner again (which I
don't think there is?).
Having symmetry for down-/up-calls seems important to me as well for
simplicity's sake, and I'm starting to see the appeal of the status quo
more and more (i.e. defensive copy of up-call args). If we go with that
I think it's important to tell the developer when we're transferring a
resource to them, and it's up to them to manage it.
Jorn
More information about the panama-dev
mailing list