Pointer/Scope API questions
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Wed Jan 8 00:02:49 UTC 2020
On 07/01/2020 23:18, Ty Young wrote:
> What I linked is an example of how an Nvidia attribute is implemented
> in my API. I linked it because it shows how to-the-point and easy
> Pointer is. My API implements 50+ Nvidia attributes which is very
> easy(as I linked) under Pointer... however doing this without some
> higher level would result in these small implementations becoming much
> larger - unless of course I make my own Pointer... but for use cases
> like mine, defining what a Pointer is when Project Panama could
> provide that definition(from an interface prospective) hurts more than
> it helps.
Please see also my other reply on your original email - I mistook the
example you have linked for a different one you brought up before - I
don't think the example you shared earlier today is so atypical (the
other where you have no header is :-) ).
Now, in your example, my feeling is (as in the examples that Michael
shared last week) that if you replace Pointer with
MemoryAddress/MemorySegment you don't lose all that much. After all, you
both are after an higher level wrapper, so you don't want to expose
Pointer directly - you just want something that _encodes_ a C pointer
and that can be passed to a C function where a pointer is expected
(which you can do with native method handles) - or to dereference it to
read some data (which you can do with the memory access var handles).
For instance in the code in [1], you would need to:
1) change the type of the 'utilStruct' field to MemorySegment
2) in the constructor, just create the segment
(MemorySegment::allocateNative) - if you have generated the bindings
using the minimal jextract (which will soon be available), you will have
some static constant with the layout of the struct you want
(nvmlUtilization_st), so you will be able to just do:
this.utilStruct =
MemorySegment.allocateNative(MyBindings.nvmlUtilization_st$LAYOUT);
3) In the update() method, replace:
this.utilStruct.get().gpu$get()
with something like
MyBindings.nvmlUtilization_st$gpu$get(utilStruct);
(again, the static accessor "nvmlUtilization_st$gpu$get" will be
autogenerated for you by the minimal jextract).
And that's it (for that class, at least).
I think your frustration is understandable - we're moving from an API
which has a certain level of familiarity (everyone knows what a
'pointer' is, right?) to a _different_ way of doing things. But one of
the most important lessons we've learned last year is, I think, that for
Panama to succeed, and to allow interop between Java and native code,
the Java code doesn't _have_ to look exactly like C. It is easy to fall
into a sort of trap where it feels like the goal is is to minimize the
differences between the Java code and the corresponding C code. While
attractive, that approach is a siren song, and sends you down a slippery
slope, where you need many constructs to support features in the native
language; the first one is Pointer of course, then you realize you need
Array too - and function pointers? which led us to Callback - then
there's LongDouble, and along the way you encounter Complex XYZ - after
a while you end up pulling in the entire C world inside the JDK. And
then, what about C++ ? Do we need a Reference too (and maybe
LHSReference and RHSReference) ? And what about other foreign languages?
I hope you get what I'm trying to say here.
Focusing on the primitive tools (MemoryAddress, MemorySegment, memory
var handles, native method handles) allows us to deal with a lot of
stuff (pretty much all we need) introducing basically no coupling with
the C world directly in the JDK. Which is, I think, a good place to
land. And, what was surprising, was that after you get adjusted to the
new perspective, well, it's not like the new world w/o Pointers and
friends is so much worse; see how few changes were needed in your case -
I'm sure there are worse cases than that, but still. I've replaced the
Pointer-based version of the libclang higher-level API we have to use
the memory access API and native method handles in less than a day - and
overall there were only a couple of tricky cases which required a bit
more caution - most of the translation was straightforward.
So I'd say, let's give this approach a try and see how it goes - from
where I look, it certainly seems like a (much) saner place to be.
Maurizio
More information about the panama-dev
mailing list