> On Jan 13, 2022, at 7:05 AM, Remi Forax <fo...@univ-mlv.fr> wrote:
>
> ----- Original Message -----
>> From: "Steven Schlansker" <stevenschlans...@gmail.com>
>> To: "core-libs-dev" <core-libs-dev@openjdk.java.net>
>> Sent: Wednesday, January 12, 2022 9:56:30 PM
>> Subject: LambdaMetafactory requires full privilege access, but doesn't seem
>> to actually restrict functionality
>
>> Hi core-libs-dev,
>>
>> I am maintaining a module for the popular Jackson JSON library that attempts
>> to
>> simplify code-generation code without losing performance.
>> Long ago, it was a huge win to code-generate custom getter / setter / field
>> accessors rather than use core reflection. Now, the gap is closing a lot with
>> MethodHandles, but there still seems to be some benefit.
>>
>> The previous approach used for code generation relied on the CGLib + ASM
>> libraries, which as I am sure you know leads to horrible-to-maintain code
>> since
>> you essentially write bytecode directly.
>
> I don't see the issue here, writing bytecodes in not that hard :)
Everything I write could be done in assembly, yet somehow I keep coming back to
Java :)
>
>> Feature development basically stopped because writing out long chains of
>> `visitVarInsn(ASTORE, 3)` and the like scares off most contributors, myself
>> included.
>
> yes, sadly known issue, generating assembly code even a highlevel one like
> the Java byetcode by hands require a niche knowledge which sadly is rarely
> teached at university anymore (and let's not talked about bootcamp).
>
>>
>> As an experiment, I started to port the custom class generation logic to use
>> LambdaMetafactory. The idea is to use the factory to generate `Function<Bean,
>> T>` getter and `BiConsumer<Bean, T>` setter implementations.
>
> If you want to make the serailization/deserialization to JSON fast you will
> mostly battle two things,
> - polymorphic call site, a call that can call some many different
> implementations that the VM will not try to inline,
> usually the trick is to just have one of such call to take care of the
> different kind of objects.
> - boxing, that kind of code tends to abstract over any values, but boxing
> means allocation if there is no inlining.
>
> For me, it means that you want two specialized codes, the decoder that
> switches over the keys and call the correct setter and the encoder that calls
> the getters in sequence.
>
> Trying to abstract over getters and setters is a step too far because you
> loose the benefit to write a code specific to a peculiar class.
Yes, this is a good point. I mostly copied the existing code-gen approach which
behaved this way. I should go back and see if I can generate the more full
featured coders and decoders.
We do avoid boxing by using primitive specializations for our generated
interface types, at least for the common primitive types.
> I suppose you try to use the method handles directly with invokeExact() if
> you are able to remove the boxing
> or with invoke() if not ?
>
> Because it's not clear to me why you want to use the LambdaMetafactory ?
At the time it seemed to be significantly faster than non-static MethodHandles,
and also faster than old-school reflection.
Ref:
https://www.optaplanner.org/blog/2018/01/09/JavaReflectionButMuchFaster.html
I wrote some simple benchmarks that confirmed that it's almost as fast as
Jackson's older direct code-gen support:
https://github.com/FasterXML/jackson-modules-base/tree/2.14/blackbird/benchmarks
The results were even better with Graal's compiler (for some benchmarks).
I haven't verified that all of the above is still true as of Java 17+, so my
next step is to re-run the performance experiments with a more modern JVM.
I expect there's been many optimizations around MethodHandle.invoke and friends
since I ran my benchmark.
Maybe it's the case that there is no longer a performance benefit to using
LambdaMetafactory over (non-static) MethodHandle invoke, or if we can convert
our code to use invokeExact.
> [...]
>
>>
>> I'm also curious for any feedback on the overall approach of using the
>> Metafactory, perhaps I am way off in the weeds, and should just trust
>> MethodHandles to perform well if you use invokeExact :) JMH does seem to show
>> some benefit though especially with Graal compiler.
>>
>> Thanks a bunch for any thoughts,
>> Steven Schlansker
>
> Rémi