@@ -39,7 +39,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
3939
4040 /** List of names of phases that should have finished processing of tree
4141 * before this phase starts processing same tree */
42- override def runsAfter = Set (Mixin .name)
42+ override def runsAfter = Set (Mixin .name, CollectNullableFields .name )
4343
4444 override def changesMembers = true // the phase adds lazy val accessors
4545
@@ -50,6 +50,18 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
5050
5151 val containerFlagsMask = Flags .Method | Flags .Lazy | Flags .Accessor | Flags .Module
5252
53+ /** A map of lazy values to the fields they should null after initialization. */
54+ private [this ] var lazyValNullables : Map [Symbol , List [Symbol ]] = _
55+ private def nullableFor (sym : Symbol )(implicit ctx : Context ) =
56+ if (sym.is(Flags .Module )) Nil
57+ else lazyValNullables.getOrElse(sym, Nil )
58+
59+
60+ override def prepareForUnit (tree : Tree )(implicit ctx : Context ) = {
61+ lazyValNullables = ctx.collectNullableFieldsPhase.asInstanceOf [CollectNullableFields ].lazyValNullables
62+ ctx
63+ }
64+
5365 override def transformDefDef (tree : tpd.DefDef )(implicit ctx : Context ): tpd.Tree =
5466 transformLazyVal(tree)
5567
@@ -150,7 +162,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
150162 val initBody =
151163 adaptToType(
152164 ref(holderSymbol).select(defn.Object_synchronized ).appliedTo(
153- adaptToType(mkNonThreadSafeDef(result, flag, initer), defn.ObjectType )),
165+ adaptToType(mkNonThreadSafeDef(result, flag, initer, nullables = Nil ), defn.ObjectType )),
154166 tpe)
155167 val initTree = DefDef (initSymbol, initBody)
156168 val holderTree = ValDef (holderSymbol, New (holderImpl.typeRef, List ()))
@@ -176,37 +188,51 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
176188 holders::: stats
177189 }
178190
191+ private def nullOut (nullables : List [Symbol ])(implicit ctx : Context ): List [Tree ] = {
192+ val nullConst = Literal (Constants .Constant (null ))
193+ nullables.map { sym =>
194+ val field = if (sym.isGetter) sym.field else sym
195+ assert(field.isField)
196+ field.setFlag(Flags .Mutable )
197+ ref(field).becomes(nullConst)
198+ }
199+ }
200+
179201 /** Create non-threadsafe lazy accessor equivalent to such code
180202 * def methodSymbol() = {
181203 * if (flag) target
182204 * else {
183205 * target = rhs
184206 * flag = true
207+ * nullable = null
185208 * target
186209 * }
187210 * }
188211 */
189212
190- def mkNonThreadSafeDef (target : Tree , flag : Tree , rhs : Tree )(implicit ctx : Context ) = {
213+ def mkNonThreadSafeDef (target : Tree , flag : Tree , rhs : Tree , nullables : List [ Symbol ] )(implicit ctx : Context ) = {
191214 val setFlag = flag.becomes(Literal (Constants .Constant (true )))
192- val setTargets = if (isWildcardArg(rhs)) Nil else target.becomes(rhs) :: Nil
193- val init = Block (setFlag :: setTargets, target.ensureApplied)
215+ val setNullables = nullOut(nullables)
216+ val setTargetAndNullable = if (isWildcardArg(rhs)) setNullables else target.becomes(rhs) :: setNullables
217+ val init = Block (setFlag :: setTargetAndNullable, target.ensureApplied)
194218 If (flag.ensureApplied, target.ensureApplied, init)
195219 }
196220
197221 /** Create non-threadsafe lazy accessor for not-nullable types equivalent to such code
198222 * def methodSymbol() = {
199223 * if (target eq null) {
200224 * target = rhs
225+ * nullable = null
201226 * target
202227 * } else target
203228 * }
204229 */
205- def mkDefNonThreadSafeNonNullable (target : Symbol , rhs : Tree )(implicit ctx : Context ) = {
230+ def mkDefNonThreadSafeNonNullable (target : Symbol , rhs : Tree , nullables : List [ Symbol ] )(implicit ctx : Context ) = {
206231 val cond = ref(target).select(nme.eq).appliedTo(Literal (Constant (null )))
207232 val exp = ref(target)
208233 val setTarget = exp.becomes(rhs)
209- val init = Block (List (setTarget), exp)
234+ val setNullables = nullOut(nullables)
235+ val init = Block (setTarget :: setNullables, exp)
210236 If (cond, init, exp)
211237 }
212238
@@ -222,14 +248,14 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
222248
223249 val containerTree = ValDef (containerSymbol, defaultValue(tpe))
224250 if (x.tpe.isNotNull && tpe <:< defn.ObjectType ) { // can use 'null' value instead of flag
225- val slowPath = DefDef (x.symbol.asTerm, mkDefNonThreadSafeNonNullable(containerSymbol, x.rhs))
251+ val slowPath = DefDef (x.symbol.asTerm, mkDefNonThreadSafeNonNullable(containerSymbol, x.rhs, nullableFor(x.symbol) ))
226252 Thicket (containerTree, slowPath)
227253 }
228254 else {
229255 val flagName = LazyBitMapName .fresh(x.name.asTermName)
230256 val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags .Private , defn.BooleanType ).enteredAfter(this )
231257 val flag = ValDef (flagSymbol, Literal (Constants .Constant (false )))
232- val slowPath = DefDef (x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs))
258+ val slowPath = DefDef (x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs, nullableFor(x.symbol) ))
233259 Thicket (containerTree, flag, slowPath)
234260 }
235261 }
@@ -263,10 +289,23 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
263289 * result = $target
264290 * }
265291 * }
292+ * nullable = null
266293 * result
267294 * }
268295 */
269- def mkThreadSafeDef (methodSymbol : TermSymbol , claz : ClassSymbol , ord : Int , target : Symbol , rhs : Tree , tp : Types .Type , offset : Tree , getFlag : Tree , stateMask : Tree , casFlag : Tree , setFlagState : Tree , waitOnLock : Tree )(implicit ctx : Context ) = {
296+ def mkThreadSafeDef (methodSymbol : TermSymbol ,
297+ claz : ClassSymbol ,
298+ ord : Int ,
299+ target : Symbol ,
300+ rhs : Tree ,
301+ tp : Types .Type ,
302+ offset : Tree ,
303+ getFlag : Tree ,
304+ stateMask : Tree ,
305+ casFlag : Tree ,
306+ setFlagState : Tree ,
307+ waitOnLock : Tree ,
308+ nullables : List [Symbol ])(implicit ctx : Context ) = {
270309 val initState = Literal (Constants .Constant (0 ))
271310 val computeState = Literal (Constants .Constant (1 ))
272311 val notifyState = Literal (Constants .Constant (2 ))
@@ -330,7 +369,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
330369
331370 val whileBody = List (ref(flagSymbol).becomes(getFlag.appliedTo(thiz, offset)), cases)
332371 val cycle = WhileDo (methodSymbol, whileCond, whileBody)
333- DefDef (methodSymbol, Block (resultDef :: retryDef :: flagDef :: cycle :: Nil , ref(resultSymbol)))
372+ val setNullables = nullOut(nullables)
373+ DefDef (methodSymbol, Block (resultDef :: retryDef :: flagDef :: cycle :: setNullables, ref(resultSymbol)))
334374 }
335375
336376 def transformMemberDefVolatile (x : ValOrDefDef )(implicit ctx : Context ) = {
@@ -390,8 +430,9 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
390430 val wait = Select (ref(helperModule), lazyNme.RLazyVals .wait4Notification)
391431 val state = Select (ref(helperModule), lazyNme.RLazyVals .state)
392432 val cas = Select (ref(helperModule), lazyNme.RLazyVals .cas)
433+ val nullables = nullableFor(x.symbol)
393434
394- val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait)
435+ val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait, nullables )
395436 if (flag eq EmptyTree )
396437 Thicket (containerTree, accessor)
397438 else Thicket (containerTree, flag, accessor)
0 commit comments