1- package dotty .tools .dotc
2- package transform
1+ package dotty .tools .dotc .transform
32
4- import dotty . tools . dotc . core . Annotations . Annotation
3+ import java . util . IdentityHashMap
54
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 ._
165import dotty .tools .dotc .ast .tpd
6+ import dotty .tools .dotc .core .Annotations .Annotation
177import 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 ._
2010import 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 ._
2219
23- import java . util . IdentityHashMap
20+ import scala . collection . mutable
2421
2522class LazyVals extends MiniPhase with IdentityDenotTransformer {
2623 import LazyVals ._
@@ -41,10 +38,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
4138
4239 def transformer : LazyVals = new LazyVals
4340
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
4643
47- val containerFlagsMask : FlagSet = Flags . Method | Flags . Lazy | Flags . Accessor | Flags . Module
44+ val containerFlagsMask : FlagSet = Method | Lazy | Accessor | Module
4845
4946 /** A map of lazy values to the fields they should null after initialization. */
5047 private [this ] var lazyValNullables : IdentityHashMap [Symbol , mutable.ListBuffer [Symbol ]] = _
@@ -72,22 +69,22 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
7269
7370 def transformLazyVal (tree : ValOrDefDef )(implicit ctx : Context ): Tree = {
7471 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
7875 tree
7976 else {
8077 val isField = sym.owner.isClass
8178 if (isField) {
8279 if (sym.isVolatile ||
83- (sym.is(Flags . Module )/* || ctx.scala2Mode*/ ) &&
80+ (sym.is(Module )/* || ctx.scala2Mode*/ ) &&
8481 // TODO assume @volatile once LazyVals uses static helper constructs instead of
8582 // ones in the companion object.
86- ! sym.is(Flags . Synthetic ))
83+ ! sym.is(Synthetic ))
8784 // module class is user-defined.
8885 // Should be threadsafe, to mimic safety guaranteed by global object
8986 transformMemberDefVolatile(tree)
90- else if (sym.is(Flags . Module )) // synthetic module
87+ else if (sym.is(Module )) // synthetic module
9188 transformSyntheticModule(tree)
9289 else
9390 transformMemberDefNonVolatile(tree)
@@ -123,7 +120,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
123120 def transformSyntheticModule (tree : ValOrDefDef )(implicit ctx : Context ): Thicket = {
124121 val sym = tree.symbol
125122 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 )
127124 val field = ValDef (holderSymbol, tree.rhs.changeOwnerAfter(sym, holderSymbol, this ))
128125 val getter = DefDef (sym.asTerm, ref(holderSymbol))
129126 Thicket (field, getter)
@@ -187,8 +184,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
187184 // need to bring containers to start of method
188185 val (holders, stats) =
189186 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
192189 // but just to be more safe
193190 }
194191 holders::: stats
@@ -198,7 +195,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
198195 val nullConst = Literal (Constant (null ))
199196 nullables.map { field =>
200197 assert(field.isField)
201- field.setFlag(Flags . Mutable )
198+ field.setFlag(Mutable )
202199 ref(field).becomes(nullConst)
203200 }
204201 }
@@ -252,10 +249,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
252249 def transformMemberDefNonVolatile (x : ValOrDefDef )(implicit ctx : Context ): Thicket = {
253250 val claz = x.symbol.owner.asClass
254251 val tpe = x.tpe.widen.resultType.widen
255- assert(! (x.symbol is Flags . Mutable ))
252+ assert(! (x.symbol is Mutable ))
256253 val containerName = LazyLocalName .fresh(x.name.asTermName)
257254 val containerSymbol = ctx.newSymbol(claz, containerName,
258- x.symbol.flags &~ containerFlagsMask | containerFlags | Flags . Private ,
255+ x.symbol.flags &~ containerFlagsMask | containerFlags | Private ,
259256 tpe, coord = x.symbol.coord
260257 ).enteredAfter(this )
261258
@@ -266,7 +263,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
266263 }
267264 else {
268265 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 )
270267 val flag = ValDef (flagSymbol, Literal (Constant (false )))
271268 Thicket (containerTree, flag, mkNonThreadSafeDef(x.symbol, flagSymbol, containerSymbol, x.rhs))
272269 }
@@ -275,34 +272,31 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
275272 /** Create a threadsafe lazy accessor equivalent to such code
276273 * ```
277274 * 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+ * }
302295 * }
296+ * } else /* if (state == <state-1> || state == <state-2>) */ {
297+ * LazyVals.wait4Notification(this, bitmap_offset, flag, <field-id>)
303298 * }
304- * nullable = null
305- * result
299+ * }
306300 * }
307301 * ```
308302 */
@@ -317,77 +311,66 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
317311 stateMask : Tree ,
318312 casFlag : Tree ,
319313 setFlagState : Tree ,
320- waitOnLock : Tree ,
321- nullables : List [Symbol ])(implicit ctx : Context ): DefDef = {
314+ waitOnLock : Tree )(implicit ctx : Context ): DefDef = {
322315 val initState = Literal (Constant (0 ))
323316 val computeState = Literal (Constant (1 ))
324- val notifyState = Literal (Constant (2 ))
325317 val computedState = Literal (Constant (3 ))
326- val flagSymbol = ctx.newSymbol(methodSymbol, lazyNme.flag, containerFlags, defn.LongType )
327- val flagDef = ValDef (flagSymbol, Literal (Constant (0L )))
328318
329- val thiz = This (claz)(ctx.fresh.setOwner(claz))
319+ val thiz = This (claz)
320+ val fieldId = Literal (Constant (ord))
330321
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)
333325
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)
338329
339330 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))
369340 }
370341
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+ )
376350 }
377351
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+ )
379357
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+ )
382367
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)
387370 }
388371
389372 def transformMemberDefVolatile (x : ValOrDefDef )(implicit ctx : Context ): Thicket = {
390- assert(! (x.symbol is Flags . Mutable ))
373+ assert(! (x.symbol is Mutable ))
391374
392375 val tpe = x.tpe.widen.resultType.widen
393376 val claz = x.symbol.owner.asClass
@@ -398,9 +381,9 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
398381 var flag : Tree = EmptyTree
399382 var ord = 0
400383
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
402385
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
404387 appendOffsetDefs.get(claz) match {
405388 case Some (info) =>
406389 val flagsPerLong = (64 / dotty.runtime.LazyVals .BITS_PER_LAZY_VAL ).toInt
@@ -410,10 +393,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
410393 val offsetById = offsetName(id)
411394 if (ord != 0 ) { // there are unused bits in already existing flag
412395 offsetSymbol = claz.info.decl(offsetById)
413- .suchThat(sym => (sym is Flags . Synthetic ) && sym.isTerm)
396+ .suchThat(sym => (sym is Synthetic ) && sym.isTerm)
414397 .symbol.asTerm
415398 } 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 )
417400 offsetSymbol.addAnnotation(Annotation (defn.ScalaStaticAnnot ))
418401 val flagName = (StdNames .nme.BITMAP_PREFIX + id.toString).toTermName
419402 val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType ).enteredAfter(this )
@@ -423,7 +406,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
423406 }
424407
425408 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 )
427410 offsetSymbol.addAnnotation(Annotation (defn.ScalaStaticAnnot ))
428411 val flagName = (StdNames .nme.BITMAP_PREFIX + " 0" ).toTermName
429412 val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType ).enteredAfter(this )
@@ -443,9 +426,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
443426 val wait = Select (ref(helperModule), lazyNme.RLazyVals .wait4Notification)
444427 val state = Select (ref(helperModule), lazyNme.RLazyVals .state)
445428 val cas = Select (ref(helperModule), lazyNme.RLazyVals .cas)
446- val nullables = nullableFor(x.symbol)
447429
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)
449431 if (flag eq EmptyTree )
450432 Thicket (containerTree, accessor)
451433 else Thicket (containerTree, flag, accessor)
@@ -465,6 +447,7 @@ object LazyVals {
465447 val getOffset : TermName = N .getOffset.toTermName
466448 }
467449 val flag : TermName = " flag" .toTermName
450+ val state : TermName = " state" .toTermName
468451 val result : TermName = " result" .toTermName
469452 val value : TermName = " value" .toTermName
470453 val initialized : TermName = " initialized" .toTermName
0 commit comments