aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2016-05-27 19:07:30 +0200
committerodersky <odersky@gmail.com>2016-05-27 19:07:30 +0200
commit5d6cc456564d54c21da583ed425e73a99a014a9c (patch)
tree3c91c40f9443212e4f3972a86d7a11718dfab3c9
parenta77bf9f325daf54c158c654965917ba5f3d0b30f (diff)
parent3b0cb481e379ee07ce33d80a1bee5ff67c32eb40 (diff)
downloaddotty-5d6cc456564d54c21da583ed425e73a99a014a9c.tar.gz
dotty-5d6cc456564d54c21da583ed425e73a99a014a9c.tar.bz2
dotty-5d6cc456564d54c21da583ed425e73a99a014a9c.zip
Merge pull request #1281 from dotty-staging/fix-lamda-lift
Fixes to lambdalift that prevent memory leaks.
-rw-r--r--src/dotty/tools/dotc/transform/ElimStaticThis.scala6
-rw-r--r--src/dotty/tools/dotc/transform/LambdaLift.scala16
-rw-r--r--tests/run/t5375.scala11
3 files changed, 27 insertions, 6 deletions
diff --git a/src/dotty/tools/dotc/transform/ElimStaticThis.scala b/src/dotty/tools/dotc/transform/ElimStaticThis.scala
index 70a610188..3afcfa685 100644
--- a/src/dotty/tools/dotc/transform/ElimStaticThis.scala
+++ b/src/dotty/tools/dotc/transform/ElimStaticThis.scala
@@ -27,9 +27,11 @@ class ElimStaticThis extends MiniPhaseTransform {
override def transformIdent(tree: tpd.Ident)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
if (ctx.owner.enclosingMethod.is(JavaStatic)) {
tree.tpe match {
- case TermRef(thiz: ThisType, _) =>
- assert(thiz.underlying.typeSymbol.is(ModuleClass))
+ case TermRef(thiz: ThisType, _) if thiz.underlying.typeSymbol.is(ModuleClass) =>
ref(thiz.underlying.typeSymbol.sourceModule).select(tree.symbol)
+ case TermRef(thiz: ThisType, _) =>
+ assert(tree.symbol.is(Flags.JavaStatic))
+ tree
case _ => tree
}
}
diff --git a/src/dotty/tools/dotc/transform/LambdaLift.scala b/src/dotty/tools/dotc/transform/LambdaLift.scala
index 3ef684e55..5fbe0343f 100644
--- a/src/dotty/tools/dotc/transform/LambdaLift.scala
+++ b/src/dotty/tools/dotc/transform/LambdaLift.scala
@@ -249,14 +249,21 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
else if (sym is Method) markCalled(sym, enclosure)
else if (sym.isTerm) markFree(sym, enclosure)
}
- if (sym.maybeOwner.isClass) narrowTo(sym.owner.asClass)
+ def captureImplicitThis(x: Type): Unit = {
+ x match {
+ case tr@TermRef(x, _) if (!tr.termSymbol.isStatic) => captureImplicitThis(x)
+ case x: ThisType if (!x.tref.typeSymbol.isStaticOwner) => narrowTo(x.tref.typeSymbol.asClass)
+ case _ =>
+ }
+ }
+ captureImplicitThis(tree.tpe)
case tree: Select =>
if (sym.is(Method) && isLocal(sym)) markCalled(sym, enclosure)
case tree: This =>
narrowTo(tree.symbol.asClass)
case tree: DefDef =>
if (sym.owner.isTerm && !sym.is(Label))
- liftedOwner(sym) = sym.enclosingClass.topLevelClass
+ liftedOwner(sym) = sym.enclosingPackageClass
// this will make methods in supercall constructors of top-level classes owned
// by the enclosing package, which means they will be static.
// On the other hand, all other methods will be indirectly owned by their
@@ -362,8 +369,9 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
// though the second condition seems weird, it's not true for symbols which are defined in some
// weird combinations of super calls.
(encClass, EmptyFlags)
- } else
- (topClass, JavaStatic)
+ } else if (encClass.is(ModuleClass, butNot = Package) && encClass.isStatic) // needed to not cause deadlocks in classloader. see t5375.scala
+ (encClass, EmptyFlags)
+ else (topClass, JavaStatic)
}
else (lOwner, EmptyFlags)
local.copySymDenotation(
diff --git a/tests/run/t5375.scala b/tests/run/t5375.scala
index 8c2c06fde..d8413c1a3 100644
--- a/tests/run/t5375.scala
+++ b/tests/run/t5375.scala
@@ -1,3 +1,14 @@
+/** Hello fellow compiler developer.
+ if you are wondering why does test suite hang on this test
+ then it's likely that the lambda inside map has been compiled into static method
+ unfotrunatelly, as it is executed inside static object initializer,
+ it is executed inside class-loader, in a synchronized block that is not source defined.
+
+ If the lambda will be static Test$#foo, calling it through a different thread would require grabbing the
+ lock inside classloader. Unlike if it not static and is called through This(Test).foo, no lock is grabbed.
+
+ @DarkDimius
+*/
object Test extends dotty.runtime.LegacyApp {
val foos = (1 to 1000).toSeq
try