Skip to content

Commit 5d6cc45

Browse files
committed
Merge pull request #1281 from dotty-staging/fix-lamda-lift
Fixes to lambdalift that prevent memory leaks.
2 parents a77bf9f + 3b0cb48 commit 5d6cc45

File tree

3 files changed

+27
-6
lines changed

3 files changed

+27
-6
lines changed

src/dotty/tools/dotc/transform/ElimStaticThis.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ class ElimStaticThis extends MiniPhaseTransform {
2727
override def transformIdent(tree: tpd.Ident)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
2828
if (ctx.owner.enclosingMethod.is(JavaStatic)) {
2929
tree.tpe match {
30-
case TermRef(thiz: ThisType, _) =>
31-
assert(thiz.underlying.typeSymbol.is(ModuleClass))
30+
case TermRef(thiz: ThisType, _) if thiz.underlying.typeSymbol.is(ModuleClass) =>
3231
ref(thiz.underlying.typeSymbol.sourceModule).select(tree.symbol)
32+
case TermRef(thiz: ThisType, _) =>
33+
assert(tree.symbol.is(Flags.JavaStatic))
34+
tree
3335
case _ => tree
3436
}
3537
}

src/dotty/tools/dotc/transform/LambdaLift.scala

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,21 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
249249
else if (sym is Method) markCalled(sym, enclosure)
250250
else if (sym.isTerm) markFree(sym, enclosure)
251251
}
252-
if (sym.maybeOwner.isClass) narrowTo(sym.owner.asClass)
252+
def captureImplicitThis(x: Type): Unit = {
253+
x match {
254+
case tr@TermRef(x, _) if (!tr.termSymbol.isStatic) => captureImplicitThis(x)
255+
case x: ThisType if (!x.tref.typeSymbol.isStaticOwner) => narrowTo(x.tref.typeSymbol.asClass)
256+
case _ =>
257+
}
258+
}
259+
captureImplicitThis(tree.tpe)
253260
case tree: Select =>
254261
if (sym.is(Method) && isLocal(sym)) markCalled(sym, enclosure)
255262
case tree: This =>
256263
narrowTo(tree.symbol.asClass)
257264
case tree: DefDef =>
258265
if (sym.owner.isTerm && !sym.is(Label))
259-
liftedOwner(sym) = sym.enclosingClass.topLevelClass
266+
liftedOwner(sym) = sym.enclosingPackageClass
260267
// this will make methods in supercall constructors of top-level classes owned
261268
// by the enclosing package, which means they will be static.
262269
// On the other hand, all other methods will be indirectly owned by their
@@ -362,8 +369,9 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
362369
// though the second condition seems weird, it's not true for symbols which are defined in some
363370
// weird combinations of super calls.
364371
(encClass, EmptyFlags)
365-
} else
366-
(topClass, JavaStatic)
372+
} else if (encClass.is(ModuleClass, butNot = Package) && encClass.isStatic) // needed to not cause deadlocks in classloader. see t5375.scala
373+
(encClass, EmptyFlags)
374+
else (topClass, JavaStatic)
367375
}
368376
else (lOwner, EmptyFlags)
369377
local.copySymDenotation(

tests/run/t5375.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
/** Hello fellow compiler developer.
2+
if you are wondering why does test suite hang on this test
3+
then it's likely that the lambda inside map has been compiled into static method
4+
unfotrunatelly, as it is executed inside static object initializer,
5+
it is executed inside class-loader, in a synchronized block that is not source defined.
6+
7+
If the lambda will be static Test$#foo, calling it through a different thread would require grabbing the
8+
lock inside classloader. Unlike if it not static and is called through This(Test).foo, no lock is grabbed.
9+
10+
@DarkDimius
11+
*/
112
object Test extends dotty.runtime.LegacyApp {
213
val foos = (1 to 1000).toSeq
314
try

0 commit comments

Comments
 (0)