@@ -28,8 +28,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
28
28
* The map contains the list of the offset trees.
29
29
*/
30
30
class OffsetInfo (var defs : List [Tree ], var ord : Int = 0 )
31
+ class VarHandleInfo (var defs : List [Tree ])
31
32
32
33
private val appendOffsetDefs = mutable.Map .empty[Symbol , OffsetInfo ]
34
+ private val appendVarHandleDefs = mutable.Map .empty[Symbol , VarHandleInfo ]
33
35
34
36
override def phaseName : String = LazyVals .name
35
37
@@ -109,12 +111,19 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
109
111
*/
110
112
override def transformTemplate (template : Template )(using Context ): Tree = {
111
113
val cls = ctx.owner.asClass
112
- appendOffsetDefs.get(cls) match {
113
- case None => template
114
- case Some (data) =>
115
- data.defs.foreach(defin => defin.symbol.addAnnotation(Annotation (defn.ScalaStaticAnnot , defin.symbol.span)))
116
- cpy.Template (template)(body = addInFront(data.defs, template.body))
117
- }
114
+ if ctx.settings.YlegacyLazyVals .value then
115
+ appendOffsetDefs.get(cls) match {
116
+ case None => template
117
+ case Some (data) =>
118
+ data.defs.foreach(defin => defin.symbol.addAnnotation(Annotation (defn.ScalaStaticAnnot , defin.symbol.span)))
119
+ cpy.Template (template)(body = addInFront(data.defs, template.body))
120
+ }
121
+ else
122
+ appendVarHandleDefs.get(cls) match {
123
+ case None => template
124
+ case Some (data) =>
125
+ cpy.Template (template)(body = addInFront(data.defs, template.body))
126
+ }
118
127
}
119
128
120
129
private def addInFront (prefix : List [Tree ], stats : List [Tree ]) = stats match {
@@ -328,20 +337,20 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
328
337
* @param memberDef the transformed lazy field member definition
329
338
* @param claz the class containing this lazy val field
330
339
* @param target the target synthetic field
331
- * @param offset the offset of the field in the storage allocation of the class
340
+ * @param varHandle the VarHandle of the field
332
341
* @param thiz a reference to the transformed class
333
342
*/
334
343
def mkThreadSafeDef (memberDef : ValOrDefDef ,
335
344
claz : ClassSymbol ,
336
345
target : Symbol ,
337
- offset : Tree ,
346
+ varHandle : Tree ,
338
347
thiz : Tree )(using Context ): (DefDef , DefDef ) = {
339
348
val tp = memberDef.tpe.widenDealias.resultType.widenDealias
340
349
val waiting = ref(defn.LazyValsWaitingState )
341
350
val controlState = ref(defn.LazyValsControlState )
342
351
val evaluating = Select (ref(defn.LazyValsModule ), lazyNme.RLazyVals .evaluating)
343
352
val nullValue = Select (ref(defn.LazyValsModule ), lazyNme.RLazyVals .nullValue)
344
- val objCasFlag = Select (ref(defn.LazyValsModule ), lazyNme.RLazyVals .objCas )
353
+ val objCas2Flag = Select (ref(defn.LazyValsModule ), lazyNme.RLazyVals .objCas2 )
345
354
val accessorMethodSymbol = memberDef.symbol.asTerm
346
355
val lazyInitMethodName = LazyLocalInitName .fresh(memberDef.name.asTermName)
347
356
val lazyInitMethodSymbol = newSymbol(claz, lazyInitMethodName, Synthetic | Method | Private , MethodType (Nil )(_ => Nil , _ => defn.ObjectType ))
@@ -383,12 +392,12 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
383
392
val lockRel = {
384
393
val lockSymb = newSymbol(lazyInitMethodSymbol, lazyNme.lock, Synthetic , waiting.typeOpt)
385
394
Block (ValDef (lockSymb, ref(target).cast(waiting.typeOpt))
386
- :: objCasFlag .appliedTo(thiz, offset , ref(lockSymb), ref(resSymb)) :: Nil ,
395
+ :: objCas2Flag .appliedTo(thiz, varHandle , ref(lockSymb), ref(resSymb)) :: Nil ,
387
396
ref(lockSymb).select(lazyNme.RLazyVals .waitingRelease).ensureApplied)
388
397
}
389
398
// finally block
390
399
val fin = If (
391
- objCasFlag .appliedTo(thiz, offset , evaluating, ref(resSymb)).select(nme.UNARY_! ).appliedToNone,
400
+ objCas2Flag .appliedTo(thiz, varHandle , evaluating, ref(resSymb)).select(nme.UNARY_! ).appliedToNone,
392
401
lockRel,
393
402
unitLiteral
394
403
)
@@ -409,7 +418,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
409
418
)
410
419
// if CAS(_, null, Evaluating)
411
420
If (
412
- objCasFlag .appliedTo(thiz, offset , nullLiteral, evaluating),
421
+ objCas2Flag .appliedTo(thiz, varHandle , nullLiteral, evaluating),
413
422
Block (ValDef (resSymb, nullLiteral) :: ValDef (resSymbNullable, nullLiteral) :: evaluate :: Nil , // var result: AnyRef = null
414
423
Return (ref(resSymbNullable), lazyInitMethodSymbol)),
415
424
unitLiteral
@@ -425,7 +434,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
425
434
ref(current).select(defn.Object_eq ).appliedTo(evaluating),
426
435
// if is Evaluating then CAS(_, Evaluating, new Waiting)
427
436
Block (
428
- objCasFlag .appliedTo(thiz, offset , ref(current), Select (New (waiting), StdNames .nme.CONSTRUCTOR ).ensureApplied) :: Nil ,
437
+ objCas2Flag .appliedTo(thiz, varHandle , ref(current), Select (New (waiting), StdNames .nme.CONSTRUCTOR ).ensureApplied) :: Nil ,
429
438
unitLiteral
430
439
),
431
440
// if not Evaluating
@@ -461,7 +470,6 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
461
470
val claz = x.symbol.owner.asClass
462
471
val thizClass = Literal (Constant (claz.info))
463
472
464
- def offsetName (id : Int ) = s " ${StdNames .nme.LAZY_FIELD_OFFSET }${if (x.symbol.owner.is(Module )) " _m_" else " " }$id" .toTermName
465
473
val containerName = LazyLocalName .fresh(x.name.asTermName)
466
474
val containerSymbol = newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags | Private , defn.ObjectType , coord = x.symbol.coord).enteredAfter(this )
467
475
containerSymbol.addAnnotation(Annotation (defn.VolatileAnnot , containerSymbol.span)) // private @volatile var _x: AnyRef
@@ -471,23 +479,22 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
471
479
Select (ref(defn.LazyValsModule ), lazyNme.RLazyVals .getOffsetStatic)
472
480
val containerTree = ValDef (containerSymbol, nullLiteral)
473
481
474
- // create an offset for this lazy val
475
- val offsetSymbol : TermSymbol = appendOffsetDefs.get(claz) match
476
- case Some (info) =>
477
- newSymbol(claz, offsetName(info.defs.size), Synthetic , defn.LongType ).enteredAfter(this )
478
- case None =>
479
- newSymbol(claz, offsetName(0 ), Synthetic , defn.LongType ).enteredAfter(this )
480
- offsetSymbol.addAnnotation(Annotation (defn.ScalaStaticAnnot , offsetSymbol.span))
481
- val fieldTree = thizClass.select(lazyNme.RLazyVals .getDeclaredField).appliedTo(Literal (Constant (containerName.mangledString)))
482
- val offsetTree = ValDef (offsetSymbol, getOffset.appliedTo(fieldTree))
483
- val offsetInfo = appendOffsetDefs.getOrElseUpdate(claz, new OffsetInfo (Nil ))
484
- offsetInfo.defs = offsetTree :: offsetInfo.defs
485
- val offset = ref(offsetSymbol)
482
+ // create a VarHandle for this lazy val
483
+ val varHandleSymbol : TermSymbol = newSymbol(claz, s " $containerName${lazyNme.lzyHandleSuffix}" .toTermName, Synthetic , defn.VarHandleClass .typeRef).enteredAfter(this )
484
+ varHandleSymbol.addAnnotation(Annotation (defn.ScalaStaticAnnot , varHandleSymbol.span))
485
+ val getVarHandle = Apply (
486
+ Select (Apply (Select (ref(defn.MethodHandlesClass ), defn.MethodHandles_lookup .name), Nil ), defn.MethodHandlesLookup_FindVarHandle .name),
487
+ List (thizClass, Literal (Constant (containerName.toString)), Literal (Constant (defn.ObjectType )))
488
+ )
489
+ val varHandleTree = ValDef (varHandleSymbol, getVarHandle)
490
+ val varHandle = ref(varHandleSymbol)
486
491
492
+ val varHandleInfo = appendVarHandleDefs.getOrElseUpdate(claz, new VarHandleInfo (Nil ))
493
+ varHandleInfo.defs = varHandleTree :: varHandleInfo.defs
487
494
val swapOver =
488
495
This (claz)
489
496
490
- val (accessorDef, initMethodDef) = mkThreadSafeDef(x, claz, containerSymbol, offset , swapOver)
497
+ val (accessorDef, initMethodDef) = mkThreadSafeDef(x, claz, containerSymbol, varHandle , swapOver)
491
498
Thicket (containerTree, accessorDef, initMethodDef)
492
499
}
493
500
@@ -667,6 +674,7 @@ object LazyVals {
667
674
val evaluating : TermName = " Evaluating" .toTermName
668
675
val nullValue : TermName = " NullValue" .toTermName
669
676
val objCas : TermName = " objCAS" .toTermName
677
+ val objCas2 : TermName = " objCAS2" .toTermName
670
678
val get : TermName = N .get.toTermName
671
679
val setFlag : TermName = N .setFlag.toTermName
672
680
val wait4Notification : TermName = N .wait4Notification.toTermName
@@ -687,5 +695,9 @@ object LazyVals {
687
695
val current : TermName = " current" .toTermName
688
696
val lock : TermName = " lock" .toTermName
689
697
val discard : TermName = " discard" .toTermName
698
+ val lzyHandleSuffix : String = " $$lzyHandle"
690
699
}
700
+
701
+ extension (sym : Symbol ) def isVarHandleForLazy (using Context ) =
702
+ sym.name.endsWith(lazyNme.lzyHandleSuffix)
691
703
}
0 commit comments