Skip to content

Commit 691ab95

Browse files
committed
Clear temp var for captured var expr to permit GC
1 parent 48abca8 commit 691ab95

File tree

3 files changed

+67
-6
lines changed

3 files changed

+67
-6
lines changed

compiler/src/dotty/tools/dotc/transform/CapturedVars.scala

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import core.Decorators._
1010
import core.StdNames.nme
1111
import core.Names._
1212
import core.NameKinds.TempResultName
13+
import core.Constants._
1314
import ast.Trees._
1415
import util.Store
1516
import collection.mutable
@@ -45,6 +46,9 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisPhase =
4546

4647
val boxedRefClasses: collection.Set[Symbol] =
4748
refClassKeys.flatMap(k => Set(refClass(k), volatileRefClass(k)))
49+
50+
val objectRefClasses: collection.Set[Symbol] =
51+
Set(refClass(defn.ObjectClass), volatileRefClass(defn.ObjectClass))
4852
}
4953

5054
private var myRefInfo: RefInfo = null
@@ -138,17 +142,21 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisPhase =
138142
* Also: If the ref type lhs is followed by a cast (can be an artifact of nested translation),
139143
* drop the cast.
140144
*/
141-
override def transformAssign(tree: Assign)(using Context): Tree = {
145+
override def transformAssign(tree: Assign)(using Context): Tree =
142146
def recur(lhs: Tree): Tree = lhs match {
143147
case TypeApply(Select(qual, nme.asInstanceOf_), _) =>
144148
val Select(_, nme.elem) = qual
145149
recur(qual)
146150
case Select(_, nme.elem) if refInfo.boxedRefClasses.contains(lhs.symbol.maybeOwner) =>
147-
val tempDef = transformFollowing(SyntheticValDef(TempResultName.fresh(), tree.rhs))
148-
transformFollowing(Block(tempDef :: Nil, cpy.Assign(tree)(lhs, ref(tempDef.symbol))))
151+
val tempDef = transformFollowing {
152+
ValDef(newSymbol(ctx.owner, TempResultName.fresh(), Mutable | Synthetic, tree.rhs.tpe.widen, coord = tree.rhs.span), tree.rhs)
153+
}
154+
val update = cpy.Assign(tree)(lhs, ref(tempDef.symbol))
155+
def reset = cpy.Assign(tree)(ref(tempDef.symbol), nullLiteral.cast(tempDef.symbol.info))
156+
val res = if (refInfo.objectRefClasses(lhs.symbol.maybeOwner)) reset else Literal(Constant(()))
157+
transformFollowing(Block(tempDef :: update :: Nil, res))
149158
case _ =>
150159
tree
151160
}
152161
recur(tree.lhs)
153-
}
154162
}

tests/run/i14198.scala

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
import java.lang.ref.WeakReference
3+
import java.util.concurrent.atomic.AtomicReference
4+
5+
final class Mark
6+
7+
object Test {
8+
9+
def main(args: Array[String]): Unit = {
10+
myTest()
11+
}
12+
13+
final def myAssert(cond: => Boolean): Unit = {
14+
assert(cond)
15+
}
16+
17+
def myTest(): Unit = {
18+
val ref = new AtomicReference[WeakReference[AnyRef]]
19+
var mark: AnyRef = null
20+
assert(ref.compareAndSet(null, new WeakReference(new Mark)))
21+
mark = ref.get().get()
22+
myAssert(mark ne null) // in theory this could fail, but it isn't
23+
mark = null
24+
System.gc()
25+
var n = 10
26+
while (n > 0 && ref.get().get() != null) {
27+
System.gc()
28+
Thread.`yield`()
29+
//print(".")
30+
n -= 1
31+
}
32+
assert(ref.get().get() == null)
33+
}
34+
}

tests/run/liftedTry.scala

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,34 @@ object Test {
1616
assert(x == 1)
1717
assert(foo(2) == 2)
1818
assert(foo(try raise(3) catch handle) == 3)
19-
Tr.foo
19+
assert(Tr.foo == 3)
2020
}
2121
}
2222

2323
object Tr {
2424
def fun(a: Int => Unit) = a(2)
2525
def foo: Int = {
2626
var s = 1
27-
s = try {fun(s = _); 3} catch{ case ex: Throwable => val x = 4; s = x; 5 }
27+
s = try {fun(s = _); 3} catch { case ex: Throwable => val x = 4; s = x; 5 }
2828
s
2929
}
3030
}
31+
32+
/* was:
33+
Caused by: java.lang.VerifyError: Inconsistent stackmap frames at branch target 33
34+
Exception Details:
35+
Location:
36+
Tr$.foo()I @30: goto
37+
Reason:
38+
Current frame's stack size doesn't match stackmap.
39+
Current Frame:
40+
bci: @30
41+
flags: { }
42+
locals: { 'Tr$', 'scala/runtime/IntRef', 'java/lang/Throwable', integer }
43+
stack: { integer }
44+
Stackmap Frame:
45+
bci: @33
46+
flags: { }
47+
locals: { 'Tr$', 'scala/runtime/IntRef' }
48+
stack: { top, integer }
49+
*/

0 commit comments

Comments
 (0)