@@ -10,7 +10,7 @@ import Symbols._
10
10
import Decorators ._
11
11
import NameKinds ._
12
12
import Types ._
13
- import Flags .FlagSet
13
+ import Flags ._
14
14
import StdNames .nme
15
15
import dotty .tools .dotc .transform .MegaPhase ._
16
16
import dotty .tools .dotc .ast .tpd
@@ -275,34 +275,31 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
275
275
/** Create a threadsafe lazy accessor equivalent to such code
276
276
* ```
277
277
* 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
278
+ * while (true) {
279
+ * val flag = LazyVals.get(this, bitmap_offset)
280
+ * val state = LazyVals.STATE(flag, <field-id>)
281
+ *
282
+ * if (state == <state-3>) {
283
+ * return value_0
284
+ * } else if (state == <state-0>) {
285
+ * if (LazyVals.CAS(this, bitmap_offset, flag, <state-1>, <field-id>)) {
286
+ * try {
287
+ * val result = <RHS>
288
+ * value_0 = result
289
+ * nullable = null
290
+ * LazyVals.setFlag(this, bitmap_offset, <state-3>, <field-id>)
291
+ * return result
292
+ * }
293
+ * catch {
294
+ * case ex =>
295
+ * LazyVals.setFlag(this, bitmap_offset, <state-0>, <field-id>)
296
+ * throw ex
297
+ * }
302
298
* }
299
+ * } else /* if (state == <state-1> || state == <state-2>) */ {
300
+ * LazyVals.wait4Notification(this, bitmap_offset, flag, <field-id>)
303
301
* }
304
- * nullable = null
305
- * result
302
+ * }
306
303
* }
307
304
* ```
308
305
*/
@@ -321,69 +318,59 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
321
318
nullables : List [Symbol ])(implicit ctx : Context ): DefDef = {
322
319
val initState = Literal (Constant (0 ))
323
320
val computeState = Literal (Constant (1 ))
324
- val notifyState = Literal (Constant (2 ))
325
321
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
322
329
323
val thiz = This (claz)(ctx.fresh.setOwner(claz))
324
+ val fieldId = Literal (Constant (ord))
330
325
331
- val resultSymbol = ctx.newSymbol(methodSymbol, lazyNme.result, containerFlags, tp)
332
- val resultDef = ValDef (resultSymbol, defaultValue(tp))
333
-
334
- val retrySymbol = ctx.newSymbol(methodSymbol, lazyNme.retry, containerFlags, defn.BooleanType )
335
- val retryDef = ValDef (retrySymbol, Literal (Constant (true )))
326
+ val flagSymbol = ctx.newSymbol(methodSymbol, lazyNme.flag, Synthetic , defn.LongType )
327
+ val flagDef = ValDef (flagSymbol, getFlag.appliedTo(thiz, offset))
328
+ val flagRef = ref(flagSymbol)
336
329
337
- val whileCond = ref(retrySymbol)
330
+ val stateSymbol = ctx.newSymbol(methodSymbol, lazyNme.state, Synthetic , defn.LongType )
331
+ val stateDef = ValDef (stateSymbol, stateMask.appliedTo(ref(flagSymbol), Literal (Constant (ord))))
332
+ val stateRef = ref(stateSymbol)
338
333
339
334
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)
335
+ val resultSymbol = ctx.newSymbol(methodSymbol, lazyNme.result, Synthetic , tp)
336
+ val resultRef = ref(resultSymbol)
337
+ val stats = (
338
+ ValDef (resultSymbol, rhs) ::
339
+ ref(target).becomes(resultRef) ::
340
+ (nullOut(nullableFor(methodSymbol)) :+
341
+ setFlagState.appliedTo(thiz, offset, computedState, fieldId))
342
+ )
343
+ Block (stats, Return (resultRef, methodSymbol))
364
344
}
365
345
366
- val waitSecond = {
367
- val wait = waitOnLock.appliedTo(thiz, offset, ref(flagSymbol), Literal (Constant (ord)))
368
- CaseDef (notifyState, EmptyTree , wait)
369
- }
370
-
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)
346
+ val retryCase = {
347
+ val caseSymbol = ctx.newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME , Flags .Synthetic , defn.ThrowableType )
348
+ val triggerRetry = setFlagState.appliedTo(thiz, offset, initState, fieldId)
349
+ CaseDef (
350
+ Bind (caseSymbol, ref(caseSymbol)),
351
+ EmptyTree ,
352
+ Block (List (triggerRetry), Throw (ref(caseSymbol)))
353
+ )
376
354
}
377
355
378
- val default = CaseDef (Underscore (defn.LongType ), EmptyTree , Literal (Constant (())))
356
+ val initialize = If (
357
+ casFlag.appliedTo(thiz, offset, flagRef, computeState, fieldId),
358
+ Try (compute, List (retryCase), EmptyTree ),
359
+ unitLiteral
360
+ )
379
361
380
- val cases = Match (stateMask.appliedTo(ref(flagSymbol), Literal (Constant (ord))),
381
- List (compute, waitFirst, waitSecond, computed, default)) // todo: annotate with @switch
362
+ val condition = If (
363
+ stateRef.equal(computedState),
364
+ Return (ref(target), methodSymbol),
365
+ If (
366
+ stateRef.equal(initState),
367
+ initialize,
368
+ waitOnLock.appliedTo(thiz, offset, flagRef, fieldId)
369
+ )
370
+ )
382
371
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)))
372
+ val loop = WhileDo (EmptyTree , Block (List (flagDef, stateDef), condition))
373
+ DefDef (methodSymbol, loop)
387
374
}
388
375
389
376
def transformMemberDefVolatile (x : ValOrDefDef )(implicit ctx : Context ): Thicket = {
@@ -465,6 +452,7 @@ object LazyVals {
465
452
val getOffset : TermName = N .getOffset.toTermName
466
453
}
467
454
val flag : TermName = " flag" .toTermName
455
+ val state : TermName = " state" .toTermName
468
456
val result : TermName = " result" .toTermName
469
457
val value : TermName = " value" .toTermName
470
458
val initialized : TermName = " initialized" .toTermName
0 commit comments