@@ -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,15 @@ 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 ) = lazyValNullables.getOrElse(sym, Nil )
56+
57+ override def prepareForUnit (tree : Tree )(implicit ctx : Context ) = {
58+ lazyValNullables = ctx.collectNullableFieldsPhase.asInstanceOf [CollectNullableFields ].lazyValNullables
59+ ctx
60+ }
61+
5362 override def transformDefDef (tree : tpd.DefDef )(implicit ctx : Context ): tpd.Tree =
5463 transformLazyVal(tree)
5564
@@ -150,7 +159,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
150159 val initBody =
151160 adaptToType(
152161 ref(holderSymbol).select(defn.Object_synchronized ).appliedTo(
153- adaptToType(mkNonThreadSafeDef(result, flag, initer), defn.ObjectType )),
162+ adaptToType(mkNonThreadSafeDef(result, flag, initer, nullableFor(x.symbol) ), defn.ObjectType )),
154163 tpe)
155164 val initTree = DefDef (initSymbol, initBody)
156165 val holderTree = ValDef (holderSymbol, New (holderImpl.typeRef, List ()))
@@ -176,37 +185,46 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
176185 holders::: stats
177186 }
178187
188+ private def nullOut (nullables : List [Symbol ])(implicit ctx : Context ): List [Tree ] = {
189+ val nullConst = Literal (Constants .Constant (null ))
190+ nullables.map(sym => ref(sym).becomes(nullConst))
191+ }
192+
179193 /** Create non-threadsafe lazy accessor equivalent to such code
180194 * def methodSymbol() = {
181195 * if (flag) target
182196 * else {
183197 * target = rhs
184198 * flag = true
199+ * nullable = null
185200 * target
186201 * }
187202 * }
188203 */
189204
190- def mkNonThreadSafeDef (target : Tree , flag : Tree , rhs : Tree )(implicit ctx : Context ) = {
205+ def mkNonThreadSafeDef (target : Tree , flag : Tree , rhs : Tree , nullables : List [ Symbol ] )(implicit ctx : Context ) = {
191206 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)
207+ val setNullables = nullOut(nullables)
208+ val setTargetAndNullable = if (isWildcardArg(rhs)) setNullables else target.becomes(rhs) :: setNullables
209+ val init = Block (setFlag :: setTargetAndNullable, target.ensureApplied)
194210 If (flag.ensureApplied, target.ensureApplied, init)
195211 }
196212
197213 /** Create non-threadsafe lazy accessor for not-nullable types equivalent to such code
198214 * def methodSymbol() = {
199215 * if (target eq null) {
200216 * target = rhs
217+ * nullable = null
201218 * target
202219 * } else target
203220 * }
204221 */
205- def mkDefNonThreadSafeNonNullable (target : Symbol , rhs : Tree )(implicit ctx : Context ) = {
222+ def mkDefNonThreadSafeNonNullable (target : Symbol , rhs : Tree , nullables : List [ Symbol ] )(implicit ctx : Context ) = {
206223 val cond = ref(target).select(nme.eq).appliedTo(Literal (Constant (null )))
207224 val exp = ref(target)
208225 val setTarget = exp.becomes(rhs)
209- val init = Block (List (setTarget), exp)
226+ val setNullables = nullOut(nullables)
227+ val init = Block (setTarget :: setNullables, exp)
210228 If (cond, init, exp)
211229 }
212230
@@ -222,14 +240,14 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
222240
223241 val containerTree = ValDef (containerSymbol, defaultValue(tpe))
224242 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))
243+ val slowPath = DefDef (x.symbol.asTerm, mkDefNonThreadSafeNonNullable(containerSymbol, x.rhs, nullableFor(x.symbol) ))
226244 Thicket (containerTree, slowPath)
227245 }
228246 else {
229247 val flagName = LazyBitMapName .fresh(x.name.asTermName)
230248 val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags .Private , defn.BooleanType ).enteredAfter(this )
231249 val flag = ValDef (flagSymbol, Literal (Constants .Constant (false )))
232- val slowPath = DefDef (x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs))
250+ val slowPath = DefDef (x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs, nullableFor(x.symbol) ))
233251 Thicket (containerTree, flag, slowPath)
234252 }
235253 }
@@ -263,10 +281,23 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
263281 * result = $target
264282 * }
265283 * }
284+ * nullable = null
266285 * result
267286 * }
268287 */
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 ) = {
288+ def mkThreadSafeDef (methodSymbol : TermSymbol ,
289+ claz : ClassSymbol ,
290+ ord : Int ,
291+ target : Symbol ,
292+ rhs : Tree ,
293+ tp : Types .Type ,
294+ offset : Tree ,
295+ getFlag : Tree ,
296+ stateMask : Tree ,
297+ casFlag : Tree ,
298+ setFlagState : Tree ,
299+ waitOnLock : Tree ,
300+ nullables : List [Symbol ])(implicit ctx : Context ) = {
270301 val initState = Literal (Constants .Constant (0 ))
271302 val computeState = Literal (Constants .Constant (1 ))
272303 val notifyState = Literal (Constants .Constant (2 ))
@@ -330,7 +361,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
330361
331362 val whileBody = List (ref(flagSymbol).becomes(getFlag.appliedTo(thiz, offset)), cases)
332363 val cycle = WhileDo (methodSymbol, whileCond, whileBody)
333- DefDef (methodSymbol, Block (resultDef :: retryDef :: flagDef :: cycle :: Nil , ref(resultSymbol)))
364+ val setNullables = nullOut(nullables)
365+ DefDef (methodSymbol, Block (resultDef :: retryDef :: flagDef :: cycle :: setNullables, ref(resultSymbol)))
334366 }
335367
336368 def transformMemberDefVolatile (x : ValOrDefDef )(implicit ctx : Context ) = {
@@ -391,7 +423,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
391423 val state = Select (ref(helperModule), lazyNme.RLazyVals .state)
392424 val cas = Select (ref(helperModule), lazyNme.RLazyVals .cas)
393425
394- val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait)
426+ val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait, nullableFor(x.symbol) )
395427 if (flag eq EmptyTree )
396428 Thicket (containerTree, accessor)
397429 else Thicket (containerTree, flag, accessor)
0 commit comments