@@ -39,7 +39,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
39
39
40
40
/** List of names of phases that should have finished processing of tree
41
41
* before this phase starts processing same tree */
42
- override def runsAfter = Set (Mixin .name)
42
+ override def runsAfter = Set (Mixin .name, CollectNullableFields .name )
43
43
44
44
override def changesMembers = true // the phase adds lazy val accessors
45
45
@@ -50,6 +50,15 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
50
50
51
51
val containerFlagsMask = Flags .Method | Flags .Lazy | Flags .Accessor | Flags .Module
52
52
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
+
53
62
override def transformDefDef (tree : tpd.DefDef )(implicit ctx : Context ): tpd.Tree =
54
63
transformLazyVal(tree)
55
64
@@ -150,7 +159,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
150
159
val initBody =
151
160
adaptToType(
152
161
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 )),
154
163
tpe)
155
164
val initTree = DefDef (initSymbol, initBody)
156
165
val holderTree = ValDef (holderSymbol, New (holderImpl.typeRef, List ()))
@@ -176,37 +185,50 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
176
185
holders::: stats
177
186
}
178
187
188
+ private def nullOut (nullables : List [Symbol ])(implicit ctx : Context ): List [Tree ] = {
189
+ val nullConst = Literal (Constants .Constant (null ))
190
+ nullables.map { sym =>
191
+ val field = if (sym.isGetter) sym.field else sym
192
+ field.setFlag(Flags .Mutable )
193
+ ref(field).becomes(nullConst)
194
+ }
195
+ }
196
+
179
197
/** Create non-threadsafe lazy accessor equivalent to such code
180
198
* def methodSymbol() = {
181
199
* if (flag) target
182
200
* else {
183
201
* target = rhs
184
202
* flag = true
203
+ * nullable = null
185
204
* target
186
205
* }
187
206
* }
188
207
*/
189
208
190
- def mkNonThreadSafeDef (target : Tree , flag : Tree , rhs : Tree )(implicit ctx : Context ) = {
209
+ def mkNonThreadSafeDef (target : Tree , flag : Tree , rhs : Tree , nullables : List [ Symbol ] )(implicit ctx : Context ) = {
191
210
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)
211
+ val setNullables = nullOut(nullables)
212
+ val setTargetAndNullable = if (isWildcardArg(rhs)) setNullables else target.becomes(rhs) :: setNullables
213
+ val init = Block (setFlag :: setTargetAndNullable, target.ensureApplied)
194
214
If (flag.ensureApplied, target.ensureApplied, init)
195
215
}
196
216
197
217
/** Create non-threadsafe lazy accessor for not-nullable types equivalent to such code
198
218
* def methodSymbol() = {
199
219
* if (target eq null) {
200
220
* target = rhs
221
+ * nullable = null
201
222
* target
202
223
* } else target
203
224
* }
204
225
*/
205
- def mkDefNonThreadSafeNonNullable (target : Symbol , rhs : Tree )(implicit ctx : Context ) = {
226
+ def mkDefNonThreadSafeNonNullable (target : Symbol , rhs : Tree , nullables : List [ Symbol ] )(implicit ctx : Context ) = {
206
227
val cond = ref(target).select(nme.eq).appliedTo(Literal (Constant (null )))
207
228
val exp = ref(target)
208
229
val setTarget = exp.becomes(rhs)
209
- val init = Block (List (setTarget), exp)
230
+ val setNullables = nullOut(nullables)
231
+ val init = Block (setTarget :: setNullables, exp)
210
232
If (cond, init, exp)
211
233
}
212
234
@@ -222,14 +244,14 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
222
244
223
245
val containerTree = ValDef (containerSymbol, defaultValue(tpe))
224
246
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))
247
+ val slowPath = DefDef (x.symbol.asTerm, mkDefNonThreadSafeNonNullable(containerSymbol, x.rhs, nullableFor(x.symbol) ))
226
248
Thicket (containerTree, slowPath)
227
249
}
228
250
else {
229
251
val flagName = LazyBitMapName .fresh(x.name.asTermName)
230
252
val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags .Private , defn.BooleanType ).enteredAfter(this )
231
253
val flag = ValDef (flagSymbol, Literal (Constants .Constant (false )))
232
- val slowPath = DefDef (x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs))
254
+ val slowPath = DefDef (x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs, nullableFor(x.symbol) ))
233
255
Thicket (containerTree, flag, slowPath)
234
256
}
235
257
}
@@ -263,10 +285,23 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
263
285
* result = $target
264
286
* }
265
287
* }
288
+ * nullable = null
266
289
* result
267
290
* }
268
291
*/
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 ) = {
292
+ def mkThreadSafeDef (methodSymbol : TermSymbol ,
293
+ claz : ClassSymbol ,
294
+ ord : Int ,
295
+ target : Symbol ,
296
+ rhs : Tree ,
297
+ tp : Types .Type ,
298
+ offset : Tree ,
299
+ getFlag : Tree ,
300
+ stateMask : Tree ,
301
+ casFlag : Tree ,
302
+ setFlagState : Tree ,
303
+ waitOnLock : Tree ,
304
+ nullables : List [Symbol ])(implicit ctx : Context ) = {
270
305
val initState = Literal (Constants .Constant (0 ))
271
306
val computeState = Literal (Constants .Constant (1 ))
272
307
val notifyState = Literal (Constants .Constant (2 ))
@@ -330,7 +365,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
330
365
331
366
val whileBody = List (ref(flagSymbol).becomes(getFlag.appliedTo(thiz, offset)), cases)
332
367
val cycle = WhileDo (methodSymbol, whileCond, whileBody)
333
- DefDef (methodSymbol, Block (resultDef :: retryDef :: flagDef :: cycle :: Nil , ref(resultSymbol)))
368
+ val setNullables = nullOut(nullables)
369
+ DefDef (methodSymbol, Block (resultDef :: retryDef :: flagDef :: cycle :: setNullables, ref(resultSymbol)))
334
370
}
335
371
336
372
def transformMemberDefVolatile (x : ValOrDefDef )(implicit ctx : Context ) = {
@@ -391,7 +427,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
391
427
val state = Select (ref(helperModule), lazyNme.RLazyVals .state)
392
428
val cas = Select (ref(helperModule), lazyNme.RLazyVals .cas)
393
429
394
- val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait)
430
+ val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait, nullableFor(x.symbol) )
395
431
if (flag eq EmptyTree )
396
432
Thicket (containerTree, accessor)
397
433
else Thicket (containerTree, flag, accessor)
0 commit comments