Skip to content

Commit afb62ff

Browse files
committed
Extract MethodHandles.lookup() into a local scope in the static constructor
1 parent 754410e commit afb62ff

File tree

2 files changed

+55
-15
lines changed

2 files changed

+55
-15
lines changed

compiler/src/dotty/tools/dotc/transform/LazyVals.scala

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ 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])
31+
class VarHandleInfo(var methodHandlesLookupDef: Tree, var varHandleDefs: List[Tree])
3232

3333
private val appendOffsetDefs = mutable.Map.empty[Symbol, OffsetInfo]
3434
private val appendVarHandleDefs = mutable.Map.empty[Symbol, VarHandleInfo]
@@ -122,7 +122,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
122122
appendVarHandleDefs.get(cls) match {
123123
case None => template
124124
case Some(data) =>
125-
cpy.Template(template)(body = addInFront(data.defs, template.body))
125+
cpy.Template(template)(body = addInFront(data.methodHandlesLookupDef +: data.varHandleDefs, template.body))
126126
}
127127
}
128128

@@ -475,22 +475,28 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
475475
containerSymbol.addAnnotation(Annotation(defn.VolatileAnnot, containerSymbol.span)) // private @volatile var _x: AnyRef
476476
containerSymbol.addAnnotations(x.symbol.annotations) // pass annotations from original definition
477477
containerSymbol.removeAnnotation(defn.ScalaStaticAnnot)
478-
val getOffset =
479-
Select(ref(defn.LazyValsModule), lazyNme.RLazyVals.getOffsetStatic)
480478
val containerTree = ValDef(containerSymbol, nullLiteral)
481479

480+
val varHandleInfo = appendVarHandleDefs.getOrElseUpdate(claz, new VarHandleInfo(EmptyTree, Nil))
481+
varHandleInfo.methodHandlesLookupDef match
482+
case EmptyTree =>
483+
val lookupSym: TermSymbol = newSymbol(claz, (s"${claz.name}${lazyNme.methodHandleLookup}").toTermName, Synthetic, defn.MethodHandlesLookupClass.typeRef).enteredAfter(this)
484+
lookupSym.addAnnotation(Annotation(defn.ScalaStaticAnnot, lookupSym.span))
485+
varHandleInfo.methodHandlesLookupDef =
486+
ValDef(lookupSym, Apply(Select(ref(defn.MethodHandlesClass), defn.MethodHandles_lookup.name), Nil))
487+
case _ =>
488+
482489
// create a VarHandle for this lazy val
483490
val varHandleSymbol: TermSymbol = newSymbol(claz, s"$containerName${lazyNme.lzyHandleSuffix}".toTermName, Synthetic, defn.VarHandleClass.typeRef).enteredAfter(this)
484491
varHandleSymbol.addAnnotation(Annotation(defn.ScalaStaticAnnot, varHandleSymbol.span))
485492
val getVarHandle = Apply(
486-
Select(Apply(Select(ref(defn.MethodHandlesClass), defn.MethodHandles_lookup.name), Nil), defn.MethodHandlesLookup_FindVarHandle.name),
493+
Select(ref(varHandleInfo.methodHandlesLookupDef.symbol), defn.MethodHandlesLookup_FindVarHandle.name),
487494
List(thizClass, Literal(Constant(containerName.toString)), Literal(Constant(defn.ObjectType)))
488495
)
489496
val varHandleTree = ValDef(varHandleSymbol, getVarHandle)
490497
val varHandle = ref(varHandleSymbol)
491498

492-
val varHandleInfo = appendVarHandleDefs.getOrElseUpdate(claz, new VarHandleInfo(Nil))
493-
varHandleInfo.defs = varHandleTree :: varHandleInfo.defs
499+
varHandleInfo.varHandleDefs = varHandleTree :: varHandleInfo.varHandleDefs
494500
val swapOver =
495501
This(claz)
496502

@@ -696,8 +702,11 @@ object LazyVals {
696702
val lock: TermName = "lock".toTermName
697703
val discard: TermName = "discard".toTermName
698704
val lzyHandleSuffix: String = "$$lzyHandle"
705+
val methodHandleLookup: String = "$$methodHandleLookup"
699706
}
700707

701708
extension (sym: Symbol) def isVarHandleForLazy(using Context) =
702709
sym.name.endsWith(lazyNme.lzyHandleSuffix)
710+
extension (sym: Symbol) def isMethodLookupForLazy(using Context) =
711+
sym.name.endsWith(lazyNme.methodHandleLookup)
703712
}

compiler/src/dotty/tools/dotc/transform/MoveStatics.scala

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,18 @@ import SymDenotations.SymDenotation
1212
import Names.Name
1313
import StdNames.nme
1414
import NameOps.*
15-
import LazyVals.isVarHandleForLazy
15+
import LazyVals.{isVarHandleForLazy, isMethodLookupForLazy}
1616

1717
import ast.*
1818

1919
import scala.collection.mutable
2020

2121
import MegaPhase.*
2222

23-
/** Move static methods from companion to the class itself */
23+
/** Move static methods from companion to the class itself. Also create the static constructor.
24+
* VarHandles generated by the compiler (more in LazyVals.scala) are left in the original class.
25+
* MethodSymbols.lookup() generated by the compiler is extracted to be a local static constructor value.
26+
*/
2427
class MoveStatics extends MiniPhase with SymTransformer {
2528
import ast.tpd.*
2629

@@ -30,7 +33,8 @@ class MoveStatics extends MiniPhase with SymTransformer {
3033

3134
def transformSym(sym: SymDenotation)(using Context): SymDenotation =
3235
if (sym.hasAnnotation(defn.ScalaStaticAnnot) && sym.owner.is(Flags.Module) && sym.owner.companionClass.exists &&
33-
(sym.is(Flags.Method) || !(sym.isMutableVarOrAccessor && sym.owner.companionClass.is(Flags.Trait)) && !sym.symbol.isVarHandleForLazy)) {
36+
(sym.is(Flags.Method) || !(sym.isMutableVarOrAccessor && sym.owner.companionClass.is(Flags.Trait)) &&
37+
!sym.symbol.isVarHandleForLazy && !sym.symbol.isMethodLookupForLazy)) {
3438
sym.owner.asClass.delete(sym.symbol)
3539
sym.owner.companionClass.asClass.enter(sym.symbol)
3640
sym.copySymDenotation(owner = sym.owner.companionClass)
@@ -42,7 +46,11 @@ class MoveStatics extends MiniPhase with SymTransformer {
4246
val (classes, others) = trees.partition(x => x.isInstanceOf[TypeDef] && x.symbol.isClass)
4347
val pairs = classes.groupBy(_.symbol.name.stripModuleClassSuffix).asInstanceOf[Map[Name, List[TypeDef]]]
4448

45-
def rebuild(orig: TypeDef, newBody: List[Tree]): Tree = {
49+
/** Rebuilds a template with static ValDefs from `newBody`` initialized in a static constructor.
50+
* `localStaticDefs`, used for initialisation of other static values,
51+
* are moved entirely into the static constructor.
52+
*/
53+
def rebuild(orig: TypeDef, newBody: List[Tree], localStaticDefs: List[ValDef]): Tree = {
4654
val staticFields = newBody.filter(x => x.isInstanceOf[ValDef] && x.symbol.hasAnnotation(defn.ScalaStaticAnnot)).asInstanceOf[List[ValDef]]
4755
val newBodyWithStaticConstr =
4856
if (staticFields.nonEmpty) {
@@ -51,8 +59,24 @@ class MoveStatics extends MiniPhase with SymTransformer {
5159
staticCostructor.addAnnotation(Annotation(defn.ScalaStaticAnnot, staticCostructor.span))
5260
staticCostructor.entered
5361

54-
val staticAssigns = staticFields.map(x => Assign(ref(x.symbol), x.rhs.changeOwner(x.symbol, staticCostructor)))
55-
tpd.DefDef(staticCostructor, Block(staticAssigns, tpd.unitLiteral)) :: newBody
62+
val symbolRemap = localStaticDefs.map { x =>
63+
x.symbol.owner.asClass.delete(x.symbol)
64+
x.changeOwner(x.symbol.owner, staticCostructor)
65+
(x.symbol, x.symbol.copy(owner = staticCostructor))
66+
}.toMap
67+
68+
val localValDefs = localStaticDefs.map ( vDef =>
69+
val newSymbol = symbolRemap(vDef.symbol)
70+
ValDef(newSymbol.asTerm, vDef.rhs.changeOwner(vDef.symbol, newSymbol))
71+
)
72+
73+
val localValDefMapper = new TreeMap:
74+
override def transform(tree: Tree)(using Context): Tree = tree match
75+
case ident @ Ident(tp) if symbolRemap.contains(ident.symbol) => ref(symbolRemap(ident.symbol))
76+
case _ => super.transform(tree)
77+
78+
val staticAssigns = staticFields.map(x => Assign(ref(x.symbol), localValDefMapper.transform(x.rhs).changeOwner(x.symbol, staticCostructor)))
79+
tpd.DefDef(staticCostructor, Block(localValDefs ++ staticAssigns, tpd.unitLiteral)) :: newBody
5680
}
5781
else newBody
5882

@@ -69,9 +93,12 @@ class MoveStatics extends MiniPhase with SymTransformer {
6993

7094
val staticDefs = mutable.ListBuffer[Tree]()
7195
val staticTiedDefs = mutable.ListBuffer[Tree]()
96+
val localStaticDefs = mutable.ListBuffer[ValDef]()
7297
val remainingDefs = mutable.ListBuffer[Tree]()
7398

7499
moduleTmpl.body.foreach {
100+
case valDef: ValDef if valDef.symbol.isMethodLookupForLazy && valDef.symbol.isScalaStatic =>
101+
localStaticDefs.addOne(valDef)
75102
case memberDef: MemberDef if memberDef.symbol.isScalaStatic =>
76103
if memberDef.symbol.isVarHandleForLazy then
77104
staticTiedDefs.addOne(memberDef)
@@ -80,7 +107,7 @@ class MoveStatics extends MiniPhase with SymTransformer {
80107
case other => remainingDefs.addOne(other)
81108
}
82109

83-
rebuild(companion, companionTmpl.body ++ staticDefs) :: rebuild(module, staticTiedDefs.toList ++ remainingDefs.toList) :: Nil
110+
rebuild(companion, companionTmpl.body ++ staticDefs, Nil) :: rebuild(module, staticTiedDefs.toList ++ remainingDefs.toList, localStaticDefs.toList) :: Nil
84111
}
85112
}
86113
val newPairs =
@@ -89,7 +116,11 @@ class MoveStatics extends MiniPhase with SymTransformer {
89116
if (classes.tail.isEmpty) {
90117
val classDef = classes.head
91118
val tmpl = classDef.rhs.asInstanceOf[Template]
92-
rebuild(classDef, tmpl.body) :: Nil
119+
val (localStaticDefs, remainingDefs) = tmpl.body.partition {
120+
case valDef: ValDef => valDef.symbol.isMethodLookupForLazy && valDef.symbol.isScalaStatic
121+
case _ => false
122+
}
123+
rebuild(classDef, remainingDefs, localStaticDefs.asInstanceOf[List[ValDef]]) :: Nil
93124
}
94125
else move(classes.head, classes.tail.head)
95126
Trees.flatten(newPairs.toList.flatten ++ others)

0 commit comments

Comments
 (0)