@@ -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,46 @@ 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 => ref(sym).becomes(nullConst))
191
+ }
192
+
179
193
/** Create non-threadsafe lazy accessor equivalent to such code
180
194
* def methodSymbol() = {
181
195
* if (flag) target
182
196
* else {
183
197
* target = rhs
184
198
* flag = true
199
+ * nullable = null
185
200
* target
186
201
* }
187
202
* }
188
203
*/
189
204
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 ) = {
191
206
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)
194
210
If (flag.ensureApplied, target.ensureApplied, init)
195
211
}
196
212
197
213
/** Create non-threadsafe lazy accessor for not-nullable types equivalent to such code
198
214
* def methodSymbol() = {
199
215
* if (target eq null) {
200
216
* target = rhs
217
+ * nullable = null
201
218
* target
202
219
* } else target
203
220
* }
204
221
*/
205
- def mkDefNonThreadSafeNonNullable (target : Symbol , rhs : Tree )(implicit ctx : Context ) = {
222
+ def mkDefNonThreadSafeNonNullable (target : Symbol , rhs : Tree , nullables : List [ Symbol ] )(implicit ctx : Context ) = {
206
223
val cond = ref(target).select(nme.eq).appliedTo(Literal (Constant (null )))
207
224
val exp = ref(target)
208
225
val setTarget = exp.becomes(rhs)
209
- val init = Block (List (setTarget), exp)
226
+ val setNullables = nullOut(nullables)
227
+ val init = Block (setTarget :: setNullables, exp)
210
228
If (cond, init, exp)
211
229
}
212
230
@@ -222,14 +240,14 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
222
240
223
241
val containerTree = ValDef (containerSymbol, defaultValue(tpe))
224
242
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) ))
226
244
Thicket (containerTree, slowPath)
227
245
}
228
246
else {
229
247
val flagName = LazyBitMapName .fresh(x.name.asTermName)
230
248
val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags .Private , defn.BooleanType ).enteredAfter(this )
231
249
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) ))
233
251
Thicket (containerTree, flag, slowPath)
234
252
}
235
253
}
@@ -263,10 +281,23 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
263
281
* result = $target
264
282
* }
265
283
* }
284
+ * nullable = null
266
285
* result
267
286
* }
268
287
*/
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 ) = {
270
301
val initState = Literal (Constants .Constant (0 ))
271
302
val computeState = Literal (Constants .Constant (1 ))
272
303
val notifyState = Literal (Constants .Constant (2 ))
@@ -330,7 +361,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
330
361
331
362
val whileBody = List (ref(flagSymbol).becomes(getFlag.appliedTo(thiz, offset)), cases)
332
363
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)))
334
366
}
335
367
336
368
def transformMemberDefVolatile (x : ValOrDefDef )(implicit ctx : Context ) = {
@@ -391,7 +423,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
391
423
val state = Select (ref(helperModule), lazyNme.RLazyVals .state)
392
424
val cas = Select (ref(helperModule), lazyNme.RLazyVals .cas)
393
425
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) )
395
427
if (flag eq EmptyTree )
396
428
Thicket (containerTree, accessor)
397
429
else Thicket (containerTree, flag, accessor)
0 commit comments