| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The old design allowed a forged `SerializedLambda` to be
deserialized into a lambda that could call any private method
in the host class.
This commit passes through the list of all lambda impl methods
to the bootstrap method and verifies that you are deserializing
one of these.
The new test case shows that a forged lambda can no longer call
the private method, and that the new encoding is okay with a large
number of lambdas in a file.
We already have method handle constants in the constant pool
to support the invokedynamic through LambdaMetafactory, so
the only additional cost will be referring to these in
the boostrap args for `LambdaDeserialize`, 2 bytes per lambda.
I checked this with an example:
https://gist.github.com/retronym/e343d211f7536d06f1fef4b499a0a177
Fixes SD-193
|
|
|
|
|
|
|
|
| |
Instead, we follow the example set by javac, and predicate serializability
of bot anon-class and invokedynamic-based lambdas on whether or not the
SAM type extends java.io.Serializable.
Fixes https://github.com/scala/scala-dev/issues/120
|
|
|
|
|
| |
Also test roundtripping serialization of a lambda that targets a
SAM that's not FunctionN (it should make no difference).
|
|
To support serialization, we use the alternative lambda metafactory
that lets us specify that our anonymous functions should extend the
marker interface `scala.Serializable`. They will also have a
`writeObject` method added that implements the serialization proxy
pattern using `j.l.invoke.SerializedLamba`.
To support deserialization, we synthesize a `$deserializeLamba$`
method in each class with lambdas. This will be called reflectively by
`SerializedLambda#readResolve`. This method in turn delegates to
`LambdaDeserializer`, currently defined [1] in `scala-java8-compat`,
that uses `LambdaMetafactory` to spin up the anonymous class and
instantiate it with the deserialized environment.
Note: `LambdaDeserializer` can reuses the anonymous class on subsequent
deserializations of a given lambda, in the same spirit as an
invokedynamic call site only spins up the class on the first time
it is run. But first we'll need to host a cache in a static field
of each lambda hosting class. This is noted as a TODO and a failing
test, and will be updated in the next commit.
`LambdaDeserializer` will be moved into our standard library in
the 2.12.x branch, where we can introduce dependencies on the
Java 8 standard library.
The enclosed test cases must be manually run with indylambda enabled.
Once we enable indylambda by default on 2.12.x, the test will
actually test the new feature.
```
% echo $INDYLAMBDA
-Ydelambdafy:method -Ybackend:GenBCode -target:jvm-1.8 -classpath .:scala-java8-compat_2.11-0.5.0-SNAPSHOT.jar
% qscala $INDYLAMBDA -e "println((() => 42).getClass)"
class Main$$anon$1$$Lambda$1/1183231938
% qscala $INDYLAMBDA -e "assert(classOf[scala.Serializable].isInstance(() => 42))"
% qscalac $INDYLAMBDA test/files/run/lambda-serialization.scala && qscala $INDYLAMBDA Test
```
This commit contains a few minor refactorings to the code that
generates the invokedynamic instruction to use more meaningful
names and to reuse Java signature generation code in ASM rather
than the DIY approach.
[1] https://github.com/scala/scala-java8-compat/pull/37
|