1
- package dotty .tools .dotc
2
- package transform
1
+ package dotty .tools .dotc .transform
3
2
4
- import dotty . tools . dotc . core . Annotations . Annotation
3
+ import java . util . IdentityHashMap
5
4
6
- import scala .collection .mutable
7
- import core ._
8
- import Contexts ._
9
- import Symbols ._
10
- import Decorators ._
11
- import NameKinds ._
12
- import Types ._
13
- import Flags .FlagSet
14
- import StdNames .nme
15
- import dotty .tools .dotc .transform .MegaPhase ._
16
5
import dotty .tools .dotc .ast .tpd
6
+ import dotty .tools .dotc .core .Annotations .Annotation
17
7
import dotty .tools .dotc .core .Constants .Constant
18
- import dotty .tools .dotc .core .Types . MethodType
19
- import SymUtils ._
8
+ import dotty .tools .dotc .core .Contexts . Context
9
+ import dotty . tools . dotc . core . Decorators ._
20
10
import dotty .tools .dotc .core .DenotTransformers .IdentityDenotTransformer
21
- import Erasure .Boxing .adaptToType
11
+ import dotty .tools .dotc .core .Flags ._
12
+ import dotty .tools .dotc .core .NameKinds .{LazyBitMapName , LazyLocalInitName , LazyLocalName }
13
+ import dotty .tools .dotc .core .StdNames .nme
14
+ import dotty .tools .dotc .core .Symbols ._
15
+ import dotty .tools .dotc .core .Types ._
16
+ import dotty .tools .dotc .core .{Names , StdNames }
17
+ import dotty .tools .dotc .transform .MegaPhase .MiniPhase
18
+ import dotty .tools .dotc .transform .SymUtils ._
22
19
23
- import java . util . IdentityHashMap
20
+ import scala . collection . mutable
24
21
25
22
class LazyVals extends MiniPhase with IdentityDenotTransformer {
26
23
import LazyVals ._
@@ -41,10 +38,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
41
38
42
39
def transformer : LazyVals = new LazyVals
43
40
44
- val containerFlags : FlagSet = Flags . Synthetic | Flags . Mutable | Flags . Lazy
45
- val initFlags : FlagSet = Flags . Synthetic | Flags . Method
41
+ val containerFlags : FlagSet = Synthetic | Mutable | Lazy
42
+ val initFlags : FlagSet = Synthetic | Method
46
43
47
- val containerFlagsMask : FlagSet = Flags . Method | Flags . Lazy | Flags . Accessor | Flags . Module
44
+ val containerFlagsMask : FlagSet = Method | Lazy | Accessor | Module
48
45
49
46
/** A map of lazy values to the fields they should null after initialization. */
50
47
private [this ] var lazyValNullables : IdentityHashMap [Symbol , mutable.ListBuffer [Symbol ]] = _
@@ -72,22 +69,22 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
72
69
73
70
def transformLazyVal (tree : ValOrDefDef )(implicit ctx : Context ): Tree = {
74
71
val sym = tree.symbol
75
- if (! (sym is Flags . Lazy ) ||
76
- sym.owner.is(Flags . Trait ) || // val is accessor, lazy field will be implemented in subclass
77
- (sym.isStatic && sym.is(Flags . Module , butNot = Flags . Method ))) // static module vals are implemented in the JVM by lazy loading
72
+ if (! (sym is Lazy ) ||
73
+ sym.owner.is(Trait ) || // val is accessor, lazy field will be implemented in subclass
74
+ (sym.isStatic && sym.is(Module , butNot = Method ))) // static module vals are implemented in the JVM by lazy loading
78
75
tree
79
76
else {
80
77
val isField = sym.owner.isClass
81
78
if (isField) {
82
79
if (sym.isVolatile ||
83
- (sym.is(Flags . Module )/* || ctx.scala2Mode*/ ) &&
80
+ (sym.is(Module )/* || ctx.scala2Mode*/ ) &&
84
81
// TODO assume @volatile once LazyVals uses static helper constructs instead of
85
82
// ones in the companion object.
86
- ! sym.is(Flags . Synthetic ))
83
+ ! sym.is(Synthetic ))
87
84
// module class is user-defined.
88
85
// Should be threadsafe, to mimic safety guaranteed by global object
89
86
transformMemberDefVolatile(tree)
90
- else if (sym.is(Flags . Module )) // synthetic module
87
+ else if (sym.is(Module )) // synthetic module
91
88
transformSyntheticModule(tree)
92
89
else
93
90
transformMemberDefNonVolatile(tree)
@@ -123,7 +120,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
123
120
def transformSyntheticModule (tree : ValOrDefDef )(implicit ctx : Context ): Thicket = {
124
121
val sym = tree.symbol
125
122
val holderSymbol = ctx.newSymbol(sym.owner, LazyLocalName .fresh(sym.asTerm.name),
126
- Flags . Synthetic , sym.info.widen.resultType).enteredAfter(this )
123
+ Synthetic , sym.info.widen.resultType).enteredAfter(this )
127
124
val field = ValDef (holderSymbol, tree.rhs.changeOwnerAfter(sym, holderSymbol, this ))
128
125
val getter = DefDef (sym.asTerm, ref(holderSymbol))
129
126
Thicket (field, getter)
@@ -187,8 +184,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
187
184
// need to bring containers to start of method
188
185
val (holders, stats) =
189
186
trees.partition {
190
- _.symbol.flags.&~ (Flags . Touched ) == containerFlags
191
- // Filtering out Flags. Touched is not required currently, as there are no LazyTypes involved here
187
+ _.symbol.flags.&~ (Touched ) == containerFlags
188
+ // Filtering out Touched is not required currently, as there are no LazyTypes involved here
192
189
// but just to be more safe
193
190
}
194
191
holders::: stats
@@ -198,7 +195,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
198
195
val nullConst = Literal (Constant (null ))
199
196
nullables.map { field =>
200
197
assert(field.isField)
201
- field.setFlag(Flags . Mutable )
198
+ field.setFlag(Mutable )
202
199
ref(field).becomes(nullConst)
203
200
}
204
201
}
@@ -252,10 +249,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
252
249
def transformMemberDefNonVolatile (x : ValOrDefDef )(implicit ctx : Context ): Thicket = {
253
250
val claz = x.symbol.owner.asClass
254
251
val tpe = x.tpe.widen.resultType.widen
255
- assert(! (x.symbol is Flags . Mutable ))
252
+ assert(! (x.symbol is Mutable ))
256
253
val containerName = LazyLocalName .fresh(x.name.asTermName)
257
254
val containerSymbol = ctx.newSymbol(claz, containerName,
258
- x.symbol.flags &~ containerFlagsMask | containerFlags | Flags . Private ,
255
+ x.symbol.flags &~ containerFlagsMask | containerFlags | Private ,
259
256
tpe, coord = x.symbol.coord
260
257
).enteredAfter(this )
261
258
@@ -266,7 +263,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
266
263
}
267
264
else {
268
265
val flagName = LazyBitMapName .fresh(x.name.asTermName)
269
- val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags . Private , defn.BooleanType ).enteredAfter(this )
266
+ val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Private , defn.BooleanType ).enteredAfter(this )
270
267
val flag = ValDef (flagSymbol, Literal (Constant (false )))
271
268
Thicket (containerTree, flag, mkNonThreadSafeDef(x.symbol, flagSymbol, containerSymbol, x.rhs))
272
269
}
@@ -275,34 +272,31 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
275
272
/** Create a threadsafe lazy accessor equivalent to such code
276
273
* ```
277
274
* def methodSymbol(): Int = {
278
- * val result: Int = 0
279
- * val retry: Boolean = true
280
- * var flag: Long = 0L
281
- * while retry do {
282
- * flag = dotty.runtime.LazyVals.get(this, $claz.$OFFSET)
283
- * dotty.runtime.LazyVals.STATE(flag, 0) match {
284
- * case 0 =>
285
- * if dotty.runtime.LazyVals.CAS(this, $claz.$OFFSET, flag, 1, $ord) {
286
- * try {result = rhs} catch {
287
- * case x: Throwable =>
288
- * dotty.runtime.LazyVals.setFlag(this, $claz.$OFFSET, 0, $ord)
289
- * throw x
290
- * }
291
- * $target = result
292
- * dotty.runtime.LazyVals.setFlag(this, $claz.$OFFSET, 3, $ord)
293
- * retry = false
294
- * }
295
- * case 1 =>
296
- * dotty.runtime.LazyVals.wait4Notification(this, $claz.$OFFSET, flag, $ord)
297
- * case 2 =>
298
- * dotty.runtime.LazyVals.wait4Notification(this, $claz.$OFFSET, flag, $ord)
299
- * case 3 =>
300
- * retry = false
301
- * result = $target
275
+ * while (true) {
276
+ * val flag = LazyVals.get(this, bitmap_offset)
277
+ * val state = LazyVals.STATE(flag, <field-id>)
278
+ *
279
+ * if (state == <state-3>) {
280
+ * return value_0
281
+ * } else if (state == <state-0>) {
282
+ * if (LazyVals.CAS(this, bitmap_offset, flag, <state-1>, <field-id>)) {
283
+ * try {
284
+ * val result = <RHS>
285
+ * value_0 = result
286
+ * nullable = null
287
+ * LazyVals.setFlag(this, bitmap_offset, <state-3>, <field-id>)
288
+ * return result
289
+ * }
290
+ * catch {
291
+ * case ex =>
292
+ * LazyVals.setFlag(this, bitmap_offset, <state-0>, <field-id>)
293
+ * throw ex
294
+ * }
302
295
* }
296
+ * } else /* if (state == <state-1> || state == <state-2>) */ {
297
+ * LazyVals.wait4Notification(this, bitmap_offset, flag, <field-id>)
303
298
* }
304
- * nullable = null
305
- * result
299
+ * }
306
300
* }
307
301
* ```
308
302
*/
@@ -317,77 +311,66 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
317
311
stateMask : Tree ,
318
312
casFlag : Tree ,
319
313
setFlagState : Tree ,
320
- waitOnLock : Tree ,
321
- nullables : List [Symbol ])(implicit ctx : Context ): DefDef = {
314
+ waitOnLock : Tree )(implicit ctx : Context ): DefDef = {
322
315
val initState = Literal (Constant (0 ))
323
316
val computeState = Literal (Constant (1 ))
324
- val notifyState = Literal (Constant (2 ))
325
317
val computedState = Literal (Constant (3 ))
326
- val flagSymbol = ctx.newSymbol(methodSymbol, lazyNme.flag, containerFlags, defn.LongType )
327
- val flagDef = ValDef (flagSymbol, Literal (Constant (0L )))
328
318
329
- val thiz = This (claz)(ctx.fresh.setOwner(claz))
319
+ val thiz = This (claz)
320
+ val fieldId = Literal (Constant (ord))
330
321
331
- val resultSymbol = ctx.newSymbol(methodSymbol, lazyNme.result, containerFlags, tp)
332
- val resultDef = ValDef (resultSymbol, defaultValue(tp))
322
+ val flagSymbol = ctx.newSymbol(methodSymbol, lazyNme.flag, Synthetic , defn.LongType )
323
+ val flagDef = ValDef (flagSymbol, getFlag.appliedTo(thiz, offset))
324
+ val flagRef = ref(flagSymbol)
333
325
334
- val retrySymbol = ctx.newSymbol(methodSymbol, lazyNme.retry, containerFlags, defn.BooleanType )
335
- val retryDef = ValDef (retrySymbol, Literal (Constant (true )))
336
-
337
- val whileCond = ref(retrySymbol)
326
+ val stateSymbol = ctx.newSymbol(methodSymbol, lazyNme.state, Synthetic , defn.LongType )
327
+ val stateDef = ValDef (stateSymbol, stateMask.appliedTo(ref(flagSymbol), Literal (Constant (ord))))
328
+ val stateRef = ref(stateSymbol)
338
329
339
330
val compute = {
340
- val handlerSymbol = ctx.newSymbol(methodSymbol, nme.ANON_FUN , Flags .Synthetic ,
341
- MethodType (List (nme.x_1), List (defn.ThrowableType ), defn.IntType ))
342
- val caseSymbol = ctx.newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME , Flags .Synthetic , defn.ThrowableType )
343
- val triggerRetry = setFlagState.appliedTo(thiz, offset, initState, Literal (Constant (ord)))
344
- val complete = setFlagState.appliedTo(thiz, offset, computedState, Literal (Constant (ord)))
345
-
346
- val handler = CaseDef (Bind (caseSymbol, ref(caseSymbol)), EmptyTree ,
347
- Block (List (triggerRetry), Throw (ref(caseSymbol))
348
- ))
349
-
350
- val compute = ref(resultSymbol).becomes(rhs)
351
- val tr = Try (compute, List (handler), EmptyTree )
352
- val assign = ref(target).becomes(ref(resultSymbol))
353
- val noRetry = ref(retrySymbol).becomes(Literal (Constant (false )))
354
- val body = If (casFlag.appliedTo(thiz, offset, ref(flagSymbol), computeState, Literal (Constant (ord))),
355
- Block (tr :: assign :: complete :: noRetry :: Nil , Literal (Constant (()))),
356
- Literal (Constant (())))
357
-
358
- CaseDef (initState, EmptyTree , body)
359
- }
360
-
361
- val waitFirst = {
362
- val wait = waitOnLock.appliedTo(thiz, offset, ref(flagSymbol), Literal (Constant (ord)))
363
- CaseDef (computeState, EmptyTree , wait)
364
- }
365
-
366
- val waitSecond = {
367
- val wait = waitOnLock.appliedTo(thiz, offset, ref(flagSymbol), Literal (Constant (ord)))
368
- CaseDef (notifyState, EmptyTree , wait)
331
+ val resultSymbol = ctx.newSymbol(methodSymbol, lazyNme.result, Synthetic , tp)
332
+ val resultRef = ref(resultSymbol)
333
+ val stats = (
334
+ ValDef (resultSymbol, rhs) ::
335
+ ref(target).becomes(resultRef) ::
336
+ (nullOut(nullableFor(methodSymbol)) :+
337
+ setFlagState.appliedTo(thiz, offset, computedState, fieldId))
338
+ )
339
+ Block (stats, Return (resultRef, methodSymbol))
369
340
}
370
341
371
- val computed = {
372
- val noRetry = ref(retrySymbol).becomes(Literal (Constant (false )))
373
- val result = ref(resultSymbol).becomes(ref(target))
374
- val body = Block (noRetry :: result :: Nil , Literal (Constant (())))
375
- CaseDef (computedState, EmptyTree , body)
342
+ val retryCase = {
343
+ val caseSymbol = ctx.newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME , Synthetic , defn.ThrowableType )
344
+ val triggerRetry = setFlagState.appliedTo(thiz, offset, initState, fieldId)
345
+ CaseDef (
346
+ Bind (caseSymbol, ref(caseSymbol)),
347
+ EmptyTree ,
348
+ Block (List (triggerRetry), Throw (ref(caseSymbol)))
349
+ )
376
350
}
377
351
378
- val default = CaseDef (Underscore (defn.LongType ), EmptyTree , Literal (Constant (())))
352
+ val initialize = If (
353
+ casFlag.appliedTo(thiz, offset, flagRef, computeState, fieldId),
354
+ Try (compute, List (retryCase), EmptyTree ),
355
+ unitLiteral
356
+ )
379
357
380
- val cases = Match (stateMask.appliedTo(ref(flagSymbol), Literal (Constant (ord))),
381
- List (compute, waitFirst, waitSecond, computed, default)) // todo: annotate with @switch
358
+ val condition = If (
359
+ stateRef.equal(computedState),
360
+ Return (ref(target), methodSymbol),
361
+ If (
362
+ stateRef.equal(initState),
363
+ initialize,
364
+ waitOnLock.appliedTo(thiz, offset, flagRef, fieldId)
365
+ )
366
+ )
382
367
383
- val whileBody = Block (ref(flagSymbol).becomes(getFlag.appliedTo(thiz, offset)) :: Nil , cases)
384
- val cycle = WhileDo (whileCond, whileBody)
385
- val setNullables = nullOut(nullables)
386
- DefDef (methodSymbol, Block (resultDef :: retryDef :: flagDef :: cycle :: setNullables, ref(resultSymbol)))
368
+ val loop = WhileDo (EmptyTree , Block (List (flagDef, stateDef), condition))
369
+ DefDef (methodSymbol, loop)
387
370
}
388
371
389
372
def transformMemberDefVolatile (x : ValOrDefDef )(implicit ctx : Context ): Thicket = {
390
- assert(! (x.symbol is Flags . Mutable ))
373
+ assert(! (x.symbol is Mutable ))
391
374
392
375
val tpe = x.tpe.widen.resultType.widen
393
376
val claz = x.symbol.owner.asClass
@@ -398,9 +381,9 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
398
381
var flag : Tree = EmptyTree
399
382
var ord = 0
400
383
401
- def offsetName (id : Int ) = (StdNames .nme.LAZY_FIELD_OFFSET + (if (x.symbol.owner.is(Flags . Module )) " _m_" else " " ) + id.toString).toTermName
384
+ def offsetName (id : Int ) = (StdNames .nme.LAZY_FIELD_OFFSET + (if (x.symbol.owner.is(Module )) " _m_" else " " ) + id.toString).toTermName
402
385
403
- // compute or create appropriate offsetSymol , bitmap and bits used by current ValDef
386
+ // compute or create appropriate offsetSymbol , bitmap and bits used by current ValDef
404
387
appendOffsetDefs.get(claz) match {
405
388
case Some (info) =>
406
389
val flagsPerLong = (64 / dotty.runtime.LazyVals .BITS_PER_LAZY_VAL ).toInt
@@ -410,10 +393,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
410
393
val offsetById = offsetName(id)
411
394
if (ord != 0 ) { // there are unused bits in already existing flag
412
395
offsetSymbol = claz.info.decl(offsetById)
413
- .suchThat(sym => (sym is Flags . Synthetic ) && sym.isTerm)
396
+ .suchThat(sym => (sym is Synthetic ) && sym.isTerm)
414
397
.symbol.asTerm
415
398
} else { // need to create a new flag
416
- offsetSymbol = ctx.newSymbol(claz, offsetById, Flags . Synthetic , defn.LongType ).enteredAfter(this )
399
+ offsetSymbol = ctx.newSymbol(claz, offsetById, Synthetic , defn.LongType ).enteredAfter(this )
417
400
offsetSymbol.addAnnotation(Annotation (defn.ScalaStaticAnnot ))
418
401
val flagName = (StdNames .nme.BITMAP_PREFIX + id.toString).toTermName
419
402
val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType ).enteredAfter(this )
@@ -423,7 +406,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
423
406
}
424
407
425
408
case None =>
426
- offsetSymbol = ctx.newSymbol(claz, offsetName(0 ), Flags . Synthetic , defn.LongType ).enteredAfter(this )
409
+ offsetSymbol = ctx.newSymbol(claz, offsetName(0 ), Synthetic , defn.LongType ).enteredAfter(this )
427
410
offsetSymbol.addAnnotation(Annotation (defn.ScalaStaticAnnot ))
428
411
val flagName = (StdNames .nme.BITMAP_PREFIX + " 0" ).toTermName
429
412
val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType ).enteredAfter(this )
@@ -443,9 +426,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
443
426
val wait = Select (ref(helperModule), lazyNme.RLazyVals .wait4Notification)
444
427
val state = Select (ref(helperModule), lazyNme.RLazyVals .state)
445
428
val cas = Select (ref(helperModule), lazyNme.RLazyVals .cas)
446
- val nullables = nullableFor(x.symbol)
447
429
448
- val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait, nullables )
430
+ val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait)
449
431
if (flag eq EmptyTree )
450
432
Thicket (containerTree, accessor)
451
433
else Thicket (containerTree, flag, accessor)
@@ -465,6 +447,7 @@ object LazyVals {
465
447
val getOffset : TermName = N .getOffset.toTermName
466
448
}
467
449
val flag : TermName = " flag" .toTermName
450
+ val state : TermName = " state" .toTermName
468
451
val result : TermName = " result" .toTermName
469
452
val value : TermName = " value" .toTermName
470
453
val initialized : TermName = " initialized" .toTermName
0 commit comments