Because anonymous functions in Scala are historically
Serializable, In 2.12 we are opting to use a generic deserializer that calls
LambdaMetafactory.bootstrap, rather than emitting an indy instruction
per lambda within $deserializeLambda$, which has been noted as a problem in
javac:

Reduce size of $deserializeLambda$ method
https://bugs.openjdk.java.net/browse/JDK-8008413

At JVM language summit last week I was alerted to a flaw in
this approach: it inadvertently makes all private methods in the
lambda host class accessible by means of a forged SerializedLambda.
Thanks for the feedback, Remi and Brian!

I'm working to plug this hole, and thought I'd share the technique in case
it
if of interest beyond scalac:

SD-193 Lock down lambda deserialization
https://github.com/scala/scala/pull/5321

The body of $deserializeLambda$ is now a single invokedynamic. Its
bootstrap argument is an array of method handles to valid lambda target
methods. The generic deserializer creates a j.u.HashMap relating these
String keys of the form "$methodName $descriptor". It can then limit
deserialiazion to SerializedLambda-s targeting these methods.

This approach costs 2 bytes per serializable lambda in the constant
pool: all the entries are already there for the LambdaMetafactory
bootstrap args, we just refer to them again.

A downside is that the first lambda to be deserialized will incur a
one-time time + space cost proportional the total number of lambdas in
the host class to construct the map.

Here's the bytecode comparison between this proposal and javac:

https://gist.github.com/retronym/fcf46910cc7801f32017e8699a59c831

Regards,

Jason Zaugg
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to