summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2015-05-12 15:28:35 +1000
committerJason Zaugg <jzaugg@gmail.com>2015-05-17 19:30:10 +1000
commitafa2ff9f76123ab982dc5bb2f1110bb58e75c68c (patch)
tree90f720ed31e91d64beaa3031de7394fd545c27ea /test
parent6ad9b44b27ede70ec723204bd80361d60f448c1a (diff)
downloadscala-afa2ff9f76123ab982dc5bb2f1110bb58e75c68c.tar.gz
scala-afa2ff9f76123ab982dc5bb2f1110bb58e75c68c.tar.bz2
scala-afa2ff9f76123ab982dc5bb2f1110bb58e75c68c.zip
[indylambda] Support lambda {de}serialization
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
Diffstat (limited to 'test')
-rw-r--r--test/files/run/lambda-serialization.scala35
1 files changed, 35 insertions, 0 deletions
diff --git a/test/files/run/lambda-serialization.scala b/test/files/run/lambda-serialization.scala
new file mode 100644
index 0000000000..46b26d7c5e
--- /dev/null
+++ b/test/files/run/lambda-serialization.scala
@@ -0,0 +1,35 @@
+import java.io.{ByteArrayInputStream, ObjectInputStream, ObjectOutputStream, ByteArrayOutputStream}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ roundTrip
+ }
+
+ def roundTrip(): Unit = {
+ val c = new Capture("Capture")
+ val lambda = (p: Param) => ("a", p, c)
+ val reconstituted1 = serializeDeserialize(lambda).asInstanceOf[Object => Any]
+ val p = new Param
+ assert(reconstituted1.apply(p) == ("a", p, c))
+ val reconstituted2 = serializeDeserialize(lambda).asInstanceOf[Object => Any]
+ assert(reconstituted1.getClass == reconstituted2.getClass)
+
+ val reconstituted3 = serializeDeserialize(reconstituted1)
+ assert(reconstituted3.apply(p) == ("a", p, c))
+
+ val specializedLambda = (p: Int) => List(p, c).length
+ assert(serializeDeserialize(specializedLambda).apply(42) == 2)
+ assert(serializeDeserialize(serializeDeserialize(specializedLambda)).apply(42) == 2)
+ }
+
+ def serializeDeserialize[T <: AnyRef](obj: T) = {
+ val buffer = new ByteArrayOutputStream
+ val out = new ObjectOutputStream(buffer)
+ out.writeObject(obj)
+ val in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray))
+ in.readObject.asInstanceOf[T]
+ }
+}
+
+case class Capture(s: String) extends Serializable
+class Param