Skip to content

Update scala modules sbt plugin to 1.0.3 #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

lrytz
Copy link

@lrytz lrytz commented May 13, 2015

No description provided.

retronym and others added 2 commits May 13, 2015 16:01
Java support serialization of lambdas by using the serialization
proxy pattern. Deserialization of a lambda uses `LambdaMetafactory`
to create a new anonymous subclass.

More details of the scheme are documented:

  https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/SerializedLambda.html

From those docs:

> SerializedLambda has a readResolve method that looks for a
> (possibly private) static method called $deserializeLambda$
> in the capturing class, invokes that with itself as the first
> argument, and returns the result. Lambda classes implementing
> $deserializeLambda$ are responsible for validating that the
> properties of the SerializedLambda are consistent with a lambda
> actually captured by that class.

The Java compiler generates code in `$deserializeLambda$` that
switches on the implementation method name and signature to locate
an invokedynamic instruction generated for the particular lambda
expression. Then, the `SerializedLambda` is further unpacked,
validating that this implementation method still represents the
same functional interface as it did when it was serialized.
(The source may have been recompiled in the interim.)

In Java, serializable lambda expressions are the exception rather than
the rule. In Scala, however, the serializability of `FunctionN` means
that we would end up generating a large amount of code to support
deserialization.

Instead, we are pursuing an alternative approach in which the
`$deserializeLambda$` method is a simple forwarder to the generic
deserializer added here.

This is capable of deserializing lambdas created by the Java compiler,
although this is not its intended use case. The enclosed tests use
Java lambdas.

This generic deserializer also works by calling `LambdaMetafactory`,
but it does so explicitly, rather than implicitly during linkage
of the `invokedynamic` instruction.

We have to mimic the caching property of `invokedynamic` instruction
to ensure we reuse the classes when constructing. The cache here
uses weak references to keys and values to avoid retention of `Class`
or `ClassLoader` instances.

If the name or signature of the implementation method has changed,
we fail during deserialization with an `IllegalArgumentError.`

However, we do not fail fast in a few cases that Java would, as we
cannot reflect on the "current" functional interface supported by
this implementation method. We just instantiate using the "previous"
functional interface class/method.

This might:

1. fail inside `LambdaMetafactory` if the new implementation
method is not compatible with the old functional interface.

2. pass through `LambdaMetafactory` by chance, but fail
when instantiating the class in other cases. For example:

```
% tail sandbox/test{1,2}.scala
==> sandbox/test1.scala <==
class C {
  def test: (String => String) = {
    val s: String = ""
    (t) => s + t
  }
}

==> sandbox/test2.scala <==
class C {
  def test: (String, String) => String = {
    (s, t) => s + t
  }
}
% (for i in 1 2; do scalac -Ydelambdafy:method -Xprint:delambdafy sandbox/test$i.scala 2>&1 ; done) | grep 'def $anon'
    final <static> <artifact> private[this] def $anonfun$1(t: String, s$1: String): String = s$1.+(t);
    final <static> <artifact> private[this] def $anonfun$1(s: String, t: String): String = s.+(t);
```

3. Silently create an instance of the old functional interface.
For example, imagine switching from `FuncInterface1` to
`FuncInterface2` where these were identical other than the name.

I don't believe that these are showstoppers.
@retronym retronym force-pushed the topic/lambda-deserialize branch 2 times, most recently from 6472976 to 921b212 Compare May 20, 2015 23:06
@retronym
Copy link
Owner

scala#38

@retronym retronym closed this May 22, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants