diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2015-06-22 15:08:32 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2015-06-22 17:49:19 +0200 |
commit | 5be0722abc913deea1a0bc3e433f1bf4c29f4e09 (patch) | |
tree | 6f6f5d090531ab29ea60debc851a8f995d2e9d31 /src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala | |
parent | d159f1420e51fb17e38c0de3690c5d27c870e9ac (diff) | |
download | scala-5be0722abc913deea1a0bc3e433f1bf4c29f4e09.tar.gz scala-5be0722abc913deea1a0bc3e433f1bf4c29f4e09.tar.bz2 scala-5be0722abc913deea1a0bc3e433f1bf4c29f4e09.zip |
Rewrite closure invocations to the lambda body method
When an indylambda closure is allocated and invoked within the same
method, rewrite the invocation to the implementation method.
This works for any indylambda / SAM type, not only Scala functions.
However, the Scala compiler (under -Xexperimental) currently desugars
function literals for non-FunctionN types to an anonymous class during
typer.
No testing yet, waiting for FunctionN to become SAMs first.
The feature requires scala-java8-compat to be on the classpath and a
number of compiler flags:
-Ydelambdafy:method -Ybackend:GenBCode -Yopt:closure-elimination -target:jvm-1.8
➜ scala git:(opt/closureInlining) ant -Dscala-java8-compat.package=1 -Dlocker.skip=1
➜ scala git:(opt/closureInlining) cd sandbox
➜ sandbox git:(opt/closureInlining) cat Fun.java
public interface Fun<T> {
T apply(T x);
}
➜ sandbox git:(opt/closureInlining) javac Fun.java
➜ sandbox git:(opt/closureInlining) cat Test.scala
class C {
val z = "too"
def f = {
val kap = "me! me!"
val f: Tuple2[String, String] => String = (o => z + kap + o.toString)
f(("a", "b"))
}
def g = {
val f: Int => String = x => x.toString
f(10)
}
def h = {
val f: Fun[Int] = x => x + 100 // Java SAM, requires -Xexperimental, will create an anonymous class in typer
f(10)
}
def i = {
val l = 10l
val f: (Long, String) => String = (x, s) => s + l + z + x
f(20l, "n")
}
def j = {
val f: Int => Int = x => x + 101 // specialized
f(33)
}
}
➜ sandbox git:(opt/closureInlining) ../build/quick/bin/scalac -target:jvm-1.8 -Yopt:closure-elimination -Ydelambdafy:method -Ybackend:GenBCode -Xexperimental -cp ../build/quick/scala-java8-compat:. Test.scala
➜ sandbox git:(opt/closureInlining) asm -a C.class
➜ sandbox git:(opt/closureInlining) cat C.asm
[...]
public g()Ljava/lang/String;
L0
INVOKEDYNAMIC apply()Lscala/compat/java8/JFunction1; [
// handle kind 0x6 : INVOKESTATIC
java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
// arguments:
(Ljava/lang/Object;)Ljava/lang/Object;,
// handle kind 0x6 : INVOKESTATIC
C.C$$$anonfun$2$adapted(Ljava/lang/Object;)Ljava/lang/String;,
(Ljava/lang/Object;)Ljava/lang/String;,
3,
1,
Lscala/Serializable;.class,
0
]
CHECKCAST scala/Function1
L1
ASTORE 1
L2
ALOAD 1
BIPUSH 10
INVOKESTATIC scala/runtime/BoxesRunTime.boxToInteger (I)Ljava/lang/Integer;
ASTORE 2
POP
ALOAD 2
INVOKESTATIC C.C$$$anonfun$2$adapted (Ljava/lang/Object;)Ljava/lang/String;
CHECKCAST java/lang/String
L3
ARETURN
[...]
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala index c6ee36d7b2..455117d837 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala @@ -216,12 +216,17 @@ abstract class GenBCode extends BCodeSyncAndTry { class Worker2 { def runGlobalOptimizations(): Unit = { import scala.collection.convert.decorateAsScala._ - q2.asScala foreach { - case Item2(_, _, plain, _, _) => - // skip mirror / bean: wd don't inline into tem, and they are not used in the plain class - if (plain != null) callGraph.addClass(plain) + if (settings.YoptBuildCallGraph) { + q2.asScala foreach { + case Item2(_, _, plain, _, _) => + // skip mirror / bean: wd don't inline into tem, and they are not used in the plain class + if (plain != null) callGraph.addClass(plain) + } } - bTypes.inliner.runInliner() + if (settings.YoptInlinerEnabled) + bTypes.inliner.runInliner() + if (settings.YoptClosureElimination) + closureOptimizer.rewriteClosureApplyInvocations() } def localOptimizations(classNode: ClassNode): Unit = { @@ -229,7 +234,7 @@ abstract class GenBCode extends BCodeSyncAndTry { } def run() { - if (settings.YoptInlinerEnabled) runGlobalOptimizations() + runGlobalOptimizations() while (true) { val item = q2.poll |