@@ -9,7 +9,7 @@ import core.Contexts.*
9
9
import core .Decorators .*
10
10
import core .DenotTransformers .IdentityDenotTransformer
11
11
import core .Flags .*
12
- import core .NameKinds .{ExpandedName , LazyBitMapName , LazyLocalInitName , LazyLocalName }
12
+ import core .NameKinds .{ExpandedName , LazyBitMapName , LazyLocalInitName , LazyLocalName , LazyVarHandleName }
13
13
import core .StdNames .nme
14
14
import core .Symbols .*
15
15
import core .Types .*
@@ -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,24 @@ 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 casFlag =
354
+ typer.Applications .retypeSignaturePolymorphicFn( // must be retyped to avoid wrapping into Array[Object]
355
+ Select (varHandle, lazyNme.compareAndSet),
356
+ MethodType (List (defn.ObjectType ,defn.ObjectType ,defn.ObjectType ), defn.BooleanType )
357
+ )
345
358
val accessorMethodSymbol = memberDef.symbol.asTerm
346
359
val lazyInitMethodName = LazyLocalInitName .fresh(memberDef.name.asTermName)
347
360
val lazyInitMethodSymbol = newSymbol(claz, lazyInitMethodName, Synthetic | Method | Private , MethodType (Nil )(_ => Nil , _ => defn.ObjectType ))
@@ -383,12 +396,12 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
383
396
val lockRel = {
384
397
val lockSymb = newSymbol(lazyInitMethodSymbol, lazyNme.lock, Synthetic , waiting.typeOpt)
385
398
Block (ValDef (lockSymb, ref(target).cast(waiting.typeOpt))
386
- :: objCasFlag .appliedTo(thiz, offset , ref(lockSymb), ref(resSymb)) :: Nil ,
399
+ :: casFlag .appliedTo(thiz, ref(lockSymb), ref(resSymb)) :: Nil ,
387
400
ref(lockSymb).select(lazyNme.RLazyVals .waitingRelease).ensureApplied)
388
401
}
389
402
// finally block
390
403
val fin = If (
391
- objCasFlag .appliedTo(thiz, offset , evaluating, ref(resSymb)).select(nme.UNARY_! ).appliedToNone,
404
+ casFlag .appliedTo(thiz, evaluating, ref(resSymb)).select(nme.UNARY_! ).appliedToNone,
392
405
lockRel,
393
406
unitLiteral
394
407
)
@@ -409,7 +422,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
409
422
)
410
423
// if CAS(_, null, Evaluating)
411
424
If (
412
- objCasFlag .appliedTo(thiz, offset , nullLiteral, evaluating),
425
+ casFlag .appliedTo(thiz, nullLiteral, evaluating),
413
426
Block (ValDef (resSymb, nullLiteral) :: ValDef (resSymbNullable, nullLiteral) :: evaluate :: Nil , // var result: AnyRef = null
414
427
Return (ref(resSymbNullable), lazyInitMethodSymbol)),
415
428
unitLiteral
@@ -425,7 +438,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
425
438
ref(current).select(defn.Object_eq ).appliedTo(evaluating),
426
439
// if is Evaluating then CAS(_, Evaluating, new Waiting)
427
440
Block (
428
- objCasFlag .appliedTo(thiz, offset , ref(current), Select (New (waiting), StdNames .nme.CONSTRUCTOR ).ensureApplied) :: Nil ,
441
+ casFlag .appliedTo(thiz, ref(current), Select (New (waiting), StdNames .nme.CONSTRUCTOR ).ensureApplied) :: Nil ,
429
442
unitLiteral
430
443
),
431
444
// if not Evaluating
@@ -461,7 +474,6 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
461
474
val claz = x.symbol.owner.asClass
462
475
val thizClass = Literal (Constant (claz.info))
463
476
464
- def offsetName (id : Int ) = s " ${StdNames .nme.LAZY_FIELD_OFFSET }${if (x.symbol.owner.is(Module )) " _m_" else " " }$id" .toTermName
465
477
val containerName = LazyLocalName .fresh(x.name.asTermName)
466
478
val containerSymbol = newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags | Private , defn.ObjectType , coord = x.symbol.coord).enteredAfter(this )
467
479
containerSymbol.addAnnotation(Annotation (defn.VolatileAnnot , containerSymbol.span)) // private @volatile var _x: AnyRef
@@ -471,23 +483,22 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
471
483
Select (ref(defn.LazyValsModule ), lazyNme.RLazyVals .getOffsetStatic)
472
484
val containerTree = ValDef (containerSymbol, nullLiteral)
473
485
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)
486
+ // create a VarHandle for this lazy val
487
+ val varHandleSymbol : TermSymbol = newSymbol(claz, LazyVarHandleName (containerName), Private | Synthetic , defn.VarHandleClass .typeRef).enteredAfter(this )
488
+ varHandleSymbol.addAnnotation(Annotation (defn.ScalaStaticAnnot , varHandleSymbol.span))
489
+ val getVarHandle = Apply (
490
+ Select (Apply (Select (ref(defn.MethodHandlesClass ), defn.MethodHandles_lookup .name), Nil ), defn.MethodHandlesLookup_FindVarHandle .name),
491
+ List (thizClass, Literal (Constant (containerName.mangledString)), Literal (Constant (defn.ObjectType )))
492
+ )
493
+ val varHandleTree = ValDef (varHandleSymbol, getVarHandle)
494
+ val varHandle = ref(varHandleSymbol)
486
495
496
+ val varHandleInfo = appendVarHandleDefs.getOrElseUpdate(claz, new VarHandleInfo (Nil ))
497
+ varHandleInfo.defs = varHandleTree :: varHandleInfo.defs
487
498
val swapOver =
488
499
This (claz)
489
500
490
- val (accessorDef, initMethodDef) = mkThreadSafeDef(x, claz, containerSymbol, offset , swapOver)
501
+ val (accessorDef, initMethodDef) = mkThreadSafeDef(x, claz, containerSymbol, varHandle , swapOver)
491
502
Thicket (containerTree, accessorDef, initMethodDef)
492
503
}
493
504
@@ -666,7 +677,6 @@ object LazyVals {
666
677
val waitingRelease : TermName = " countDown" .toTermName
667
678
val evaluating : TermName = " Evaluating" .toTermName
668
679
val nullValue : TermName = " NullValue" .toTermName
669
- val objCas : TermName = " objCAS" .toTermName
670
680
val get : TermName = N .get.toTermName
671
681
val setFlag : TermName = N .setFlag.toTermName
672
682
val wait4Notification : TermName = N .wait4Notification.toTermName
@@ -687,5 +697,7 @@ object LazyVals {
687
697
val current : TermName = " current" .toTermName
688
698
val lock : TermName = " lock" .toTermName
689
699
val discard : TermName = " discard" .toTermName
700
+ val compareAndSet : TermName = " compareAndSet" .toTermName
690
701
}
702
+
691
703
}
0 commit comments