> 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

Reply via email to