@@ -9,7 +9,7 @@ import core.Contexts.*
99import core .Decorators .*
1010import core .DenotTransformers .IdentityDenotTransformer
1111import core .Flags .*
12- import core .NameKinds .{ExpandedName , LazyBitMapName , LazyLocalInitName , LazyLocalName }
12+ import core .NameKinds .{ExpandedName , LazyBitMapName , LazyLocalInitName , LazyLocalName , LazyVarHandleName }
1313import core .StdNames .nme
1414import core .Symbols .*
1515import core .Types .*
@@ -28,8 +28,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
2828 * The map contains the list of the offset trees.
2929 */
3030 class OffsetInfo (var defs : List [Tree ], var ord : Int = 0 )
31+ class VarHandleInfo (var defs : List [Tree ])
3132
3233 private val appendOffsetDefs = mutable.Map .empty[Symbol , OffsetInfo ]
34+ private val appendVarHandleDefs = mutable.Map .empty[Symbol , VarHandleInfo ]
3335
3436 override def phaseName : String = LazyVals .name
3537
@@ -109,12 +111,19 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
109111 */
110112 override def transformTemplate (template : Template )(using Context ): Tree = {
111113 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+ }
118127 }
119128
120129 private def addInFront (prefix : List [Tree ], stats : List [Tree ]) = stats match {
@@ -328,20 +337,24 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
328337 * @param memberDef the transformed lazy field member definition
329338 * @param claz the class containing this lazy val field
330339 * @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
332341 * @param thiz a reference to the transformed class
333342 */
334343 def mkThreadSafeDef (memberDef : ValOrDefDef ,
335344 claz : ClassSymbol ,
336345 target : Symbol ,
337- offset : Tree ,
346+ varHandle : Tree ,
338347 thiz : Tree )(using Context ): (DefDef , DefDef ) = {
339348 val tp = memberDef.tpe.widenDealias.resultType.widenDealias
340349 val waiting = ref(defn.LazyValsWaitingState )
341350 val controlState = ref(defn.LazyValsControlState )
342351 val evaluating = Select (ref(defn.LazyValsModule ), lazyNme.RLazyVals .evaluating)
343352 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+ )
345358 val accessorMethodSymbol = memberDef.symbol.asTerm
346359 val lazyInitMethodName = LazyLocalInitName .fresh(memberDef.name.asTermName)
347360 val lazyInitMethodSymbol = newSymbol(claz, lazyInitMethodName, Synthetic | Method | Private , MethodType (Nil )(_ => Nil , _ => defn.ObjectType ))
@@ -383,12 +396,12 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
383396 val lockRel = {
384397 val lockSymb = newSymbol(lazyInitMethodSymbol, lazyNme.lock, Synthetic , waiting.typeOpt)
385398 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 ,
387400 ref(lockSymb).select(lazyNme.RLazyVals .waitingRelease).ensureApplied)
388401 }
389402 // finally block
390403 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,
392405 lockRel,
393406 unitLiteral
394407 )
@@ -409,7 +422,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
409422 )
410423 // if CAS(_, null, Evaluating)
411424 If (
412- objCasFlag .appliedTo(thiz, offset , nullLiteral, evaluating),
425+ casFlag .appliedTo(thiz, nullLiteral, evaluating),
413426 Block (ValDef (resSymb, nullLiteral) :: ValDef (resSymbNullable, nullLiteral) :: evaluate :: Nil , // var result: AnyRef = null
414427 Return (ref(resSymbNullable), lazyInitMethodSymbol)),
415428 unitLiteral
@@ -425,7 +438,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
425438 ref(current).select(defn.Object_eq ).appliedTo(evaluating),
426439 // if is Evaluating then CAS(_, Evaluating, new Waiting)
427440 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 ,
429442 unitLiteral
430443 ),
431444 // if not Evaluating
@@ -461,7 +474,6 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
461474 val claz = x.symbol.owner.asClass
462475 val thizClass = Literal (Constant (claz.info))
463476
464- def offsetName (id : Int ) = s " ${StdNames .nme.LAZY_FIELD_OFFSET }${if (x.symbol.owner.is(Module )) " _m_" else " " }$id" .toTermName
465477 val containerName = LazyLocalName .fresh(x.name.asTermName)
466478 val containerSymbol = newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags | Private , defn.ObjectType , coord = x.symbol.coord).enteredAfter(this )
467479 containerSymbol.addAnnotation(Annotation (defn.VolatileAnnot , containerSymbol.span)) // private @volatile var _x: AnyRef
@@ -471,23 +483,23 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
471483 Select (ref(defn.LazyValsModule ), lazyNme.RLazyVals .getOffsetStatic)
472484 val containerTree = ValDef (containerSymbol, nullLiteral)
473485
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 =
490+ ref(defn.MethodHandlesClass ).select(defn.MethodHandles_lookup ).appliedToNone
491+ .select(defn.MethodHandlesLookup_FindVarHandle ).appliedTo(
492+ thizClass, Literal (Constant (containerName.mangledString)), Literal (Constant (defn.ObjectType ))
493+ )
494+ val varHandleTree = ValDef (varHandleSymbol, getVarHandle)
495+ val varHandle = ref(varHandleSymbol)
486496
497+ val varHandleInfo = appendVarHandleDefs.getOrElseUpdate(claz, new VarHandleInfo (Nil ))
498+ varHandleInfo.defs = varHandleTree :: varHandleInfo.defs
487499 val swapOver =
488500 This (claz)
489501
490- val (accessorDef, initMethodDef) = mkThreadSafeDef(x, claz, containerSymbol, offset , swapOver)
502+ val (accessorDef, initMethodDef) = mkThreadSafeDef(x, claz, containerSymbol, varHandle , swapOver)
491503 Thicket (containerTree, accessorDef, initMethodDef)
492504 }
493505
@@ -666,7 +678,6 @@ object LazyVals {
666678 val waitingRelease : TermName = " countDown" .toTermName
667679 val evaluating : TermName = " Evaluating" .toTermName
668680 val nullValue : TermName = " NullValue" .toTermName
669- val objCas : TermName = " objCAS" .toTermName
670681 val get : TermName = N .get.toTermName
671682 val setFlag : TermName = N .setFlag.toTermName
672683 val wait4Notification : TermName = N .wait4Notification.toTermName
@@ -687,5 +698,6 @@ object LazyVals {
687698 val current : TermName = " current" .toTermName
688699 val lock : TermName = " lock" .toTermName
689700 val discard : TermName = " discard" .toTermName
701+ val compareAndSet : TermName = " compareAndSet" .toTermName
690702 }
691703}
0 commit comments