@@ -10,14 +10,16 @@ import core.Decorators._
1010import core .StdNames .nme
1111import core .Names ._
1212import core .NameKinds .TempResultName
13+ import core .Constants ._
1314import ast .Trees ._
1415import util .Store
1516import collection .mutable
1617
1718/** This phase translates variables that are captured in closures to
1819 * heap-allocated refs.
1920 */
20- class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisPhase =>
21+ class CapturedVars extends MiniPhase with IdentityDenotTransformer :
22+ thisPhase =>
2123 import ast .tpd ._
2224
2325 /** the following two members override abstract members in Transform */
@@ -45,6 +47,9 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisPhase =
4547
4648 val boxedRefClasses : collection.Set [Symbol ] =
4749 refClassKeys.flatMap(k => Set (refClass(k), volatileRefClass(k)))
50+
51+ val objectRefClasses : collection.Set [Symbol ] =
52+ Set (refClass(defn.ObjectClass ), volatileRefClass(defn.ObjectClass ))
4853 }
4954
5055 private var myRefInfo : RefInfo = null
@@ -123,32 +128,44 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisPhase =
123128 }
124129
125130 /** If assignment is to a boxed ref type, e.g.
126- *
127- * intRef.elem = expr
128- *
129- * rewrite using a temporary var to
130- *
131- * val ev$n = expr
132- * intRef.elem = ev$n
133- *
134- * That way, we avoid the problem that `expr` might contain a `try` that would
135- * run on a non-empty stack (which is illegal under JVM rules). Note that LiftTry
136- * has already run before, so such `try`s would not be eliminated.
137- *
138- * Also: If the ref type lhs is followed by a cast (can be an artifact of nested translation),
139- * drop the cast.
140- */
141- override def transformAssign (tree : Assign )(using Context ): Tree = {
142- def recur (lhs : Tree ): Tree = lhs match {
143- case TypeApply (Select (qual, nme.asInstanceOf_), _) =>
144- val Select (_, nme.elem) = qual
131+ *
132+ * intRef.elem = expr
133+ *
134+ * rewrite using a temporary var to
135+ *
136+ * val ev$n = expr
137+ * intRef.elem = ev$n
138+ *
139+ * That way, we avoid the problem that `expr` might contain a `try` that would
140+ * run on a non-empty stack (which is illegal under JVM rules). Note that LiftTry
141+ * has already run before, so such `try`s would not be eliminated.
142+ *
143+ * If the ref type lhs is followed by a cast (can be an artifact of nested translation),
144+ * drop the cast.
145+ *
146+ * If the ref type is `ObjectRef` or `VolatileObjectRef`, immediately assign `null`
147+ * to the temporary to make the underlying target of the reference available for
148+ * garbage collection. Nullification is omitted if the `expr` is already `null`.
149+ *
150+ * var ev$n: RHS = expr
151+ * objRef.elem = ev$n
152+ * ev$n = null.asInstanceOf[RHS]
153+ */
154+ override def transformAssign (tree : Assign )(using Context ): Tree =
155+ def absolved : Boolean = tree.rhs match
156+ case Literal (Constant (null )) | Typed (Literal (Constant (null )), _) => true
157+ case _ => false
158+ def recur (lhs : Tree ): Tree = lhs match
159+ case TypeApply (Select (qual@ Select (_, nme.elem), nme.asInstanceOf_), _) =>
145160 recur(qual)
146161 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))))
162+ val tempDef = transformFollowing {
163+ ValDef (newSymbol(ctx.owner, TempResultName .fresh(), Mutable | Synthetic , tree.rhs.tpe.widen, coord = tree.rhs.span), tree.rhs)
164+ }
165+ val update = cpy.Assign (tree)(lhs, ref(tempDef.symbol))
166+ def reset = cpy.Assign (tree)(ref(tempDef.symbol), nullLiteral.cast(tempDef.symbol.info))
167+ val res = if refInfo.objectRefClasses(lhs.symbol.maybeOwner) && ! absolved then reset else unitLiteral
168+ transformFollowing(Block (tempDef :: update :: Nil , res))
149169 case _ =>
150170 tree
151- }
152171 recur(tree.lhs)
153- }
154- }
0 commit comments