Skip to content

Commit 2e4c035

Browse files
committed
Desugar mixed in module var and accessor in refchecks
Rather than leaving it until mixin. The current code in mixin is used for both lazy val and modules, and puts the "slow path" code that uses the monitor into a dedicated method (`moduleName$lzyCompute`). I tracked this back to a3d4d17. I can't tell from that commit whether the performance sensititivity was related to modules or lazy vals, from the commit message I'd say the latter. As the initialization code for a module is just a constructor call, rather than an arbitraryly large chunk of code for a lazy initializer, this commit opts to inline the `lzycompute` method.
1 parent 3d62009 commit 2e4c035

File tree

6 files changed

+61
-58
lines changed

6 files changed

+61
-58
lines changed

src/compiler/scala/tools/nsc/ast/TreeGen.scala

+5
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
5858
def lhsRef = if (lhs.owner.isClass) Select(This(lhs.owner), lhs) else Ident(lhs)
5959
Block(Assign(lhsRef, rhs) :: Nil, lhsRef)
6060
}
61+
def mkDoubleCheckedLockAssignAndReturn(lhs: Symbol, rhs: Tree): Tree = {
62+
val Block(List(assign @ Assign(moduleVarRef, _)), returnTree) = gen.mkAssignAndReturn(lhs, rhs)
63+
val cond = Apply(Select(moduleVarRef, Object_eq), List(Literal(Constant(null))))
64+
If(cond, gen.mkSynchronizedCheck(This(lhs.owner), cond, List(assign), List(returnTree)), returnTree)
65+
}
6166

6267
def newModule(accessor: Symbol, tpe: Type) = {
6368
val ps = tpe.typeSymbol.primaryConstructor.info.paramTypes

src/compiler/scala/tools/nsc/transform/Mixin.scala

+1-34
Original file line numberDiff line numberDiff line change
@@ -861,16 +861,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
861861
typedPos(init.head.pos)(mkFastPathLazyBody(clazz, lzyVal, cond, syncBody, nulls, retVal))
862862
}
863863

864-
def mkInnerClassAccessorDoubleChecked(attrThis: Tree, rhs: Tree, moduleSym: Symbol, args: List[Tree]): Tree =
865-
rhs match {
866-
case Block(List(assign), returnTree) =>
867-
val Assign(moduleVarRef, _) = assign
868-
val cond = Apply(Select(moduleVarRef, Object_eq), List(NULL))
869-
mkFastPathBody(clazz, moduleSym, cond, List(assign), List(NULL), returnTree, attrThis, args)
870-
case _ =>
871-
abort(s"Invalid getter $rhs for module in $clazz")
872-
}
873-
874864
def mkCheckedAccessor(clazz: Symbol, retVal: Tree, offset: Int, pos: Position, fieldSym: Symbol): Tree = {
875865
val sym = fieldSym.getterIn(fieldSym.owner)
876866
val bitmapSym = bitmapFor(clazz, offset, sym)
@@ -926,18 +916,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
926916
deriveDefDef(stat)(rhs => Block(List(rhs, localTyper.typed(mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)))), UNIT))
927917
else stat
928918
}
929-
else if (sym.isModule && (!clazz.isTrait || clazz.isImplClass) && !sym.isBridge) {
930-
deriveDefDef(stat)(rhs =>
931-
typedPos(stat.pos)(
932-
mkInnerClassAccessorDoubleChecked(
933-
// Martin to Hubert: I think this can be replaced by selfRef(tree.pos)
934-
// @PP: It does not seem so, it crashes for me trying to bootstrap.
935-
if (clazz.isImplClass) gen.mkAttributedIdent(stat.vparamss.head.head.symbol) else gen.mkAttributedThis(clazz),
936-
rhs, sym, stat.vparamss.head
937-
)
938-
)
939-
)
940-
}
941919
else stat
942920
}
943921
stats map {
@@ -1082,18 +1060,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
10821060
})
10831061
}
10841062
else if (sym.isModule && !(sym hasFlag LIFTED | BRIDGE)) {
1085-
// add modules
1086-
val vsym = sym.owner.newModuleVarSymbol(sym)
1087-
addDef(position(sym), ValDef(vsym))
1088-
1089-
// !!! TODO - unravel the enormous duplication between this code and
1090-
// eliminateModuleDefs in RefChecks.
1091-
val rhs = gen.newModule(sym, vsym.tpe)
1092-
val assignAndRet = gen.mkAssignAndReturn(vsym, rhs)
1093-
val attrThis = gen.mkAttributedThis(clazz)
1094-
val rhs1 = mkInnerClassAccessorDoubleChecked(attrThis, assignAndRet, sym, List())
1095-
1096-
addDefDef(sym, rhs1)
1063+
// Moved to Refchecks
10971064
}
10981065
else if (!sym.isMethod) {
10991066
// add fields

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

+33-22
Original file line numberDiff line numberDiff line change
@@ -1188,26 +1188,6 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
11881188
// set NoType so it will be ignored.
11891189
val cdef = ClassDef(module.moduleClass, impl) setType NoType
11901190

1191-
// Create the module var unless the immediate owner is a class and
1192-
// the module var already exists there. See SI-5012, SI-6712.
1193-
def findOrCreateModuleVar() = {
1194-
val vsym = (
1195-
if (site.isTerm) NoSymbol
1196-
else site.info decl nme.moduleVarName(moduleName)
1197-
)
1198-
vsym orElse (site newModuleVarSymbol module)
1199-
}
1200-
def newInnerObject() = {
1201-
// Create the module var unless it is already in the module owner's scope.
1202-
// The lookup is on module.enclClass and not module.owner lest there be a
1203-
// nullary method between us and the class; see SI-5012.
1204-
val moduleVar = findOrCreateModuleVar()
1205-
val rhs = gen.newModule(module, moduleVar.tpe)
1206-
val body = if (site.isTrait) rhs else gen.mkAssignAndReturn(moduleVar, rhs)
1207-
val accessor = DefDef(module, body.changeOwner(moduleVar -> module))
1208-
1209-
ValDef(moduleVar) :: accessor :: Nil
1210-
}
12111191
def matchingInnerObject() = {
12121192
val newFlags = (module.flags | STABLE) & ~MODULE
12131193
val newInfo = NullaryMethodType(module.moduleClass.tpe)
@@ -1219,10 +1199,40 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
12191199
if (module.isStatic)
12201200
if (module.isOverridingSymbol) matchingInnerObject() else Nil
12211201
else
1222-
newInnerObject()
1202+
newInnerObject(site, module)
12231203
)
12241204
transformTrees(newTrees map localTyper.typedPos(moduleDef.pos))
12251205
}
1206+
def newInnerObject(site: Symbol, module: Symbol): List[Tree] = {
1207+
// Create the module var unless the immediate owner is a class and
1208+
// the module var already exists there. See SI-5012, SI-6712.
1209+
def findOrCreateModuleVar() = {
1210+
val vsym = (
1211+
if (site.isTerm) NoSymbol
1212+
else site.info decl nme.moduleVarName(module.name.toTermName)
1213+
)
1214+
vsym orElse (site newModuleVarSymbol module)
1215+
}
1216+
// Create the module var unless it is already in the module owner's scope.
1217+
// The lookup is on module.enclClass and not module.owner lest there be a
1218+
// nullary method between us and the class; see SI-5012.
1219+
val moduleVar = findOrCreateModuleVar()
1220+
val rhs = gen.newModule(module, moduleVar.tpe)
1221+
val body = if (site.isTrait) rhs else if (site.isTerm) gen.mkAssignAndReturn(moduleVar, rhs) else gen.mkDoubleCheckedLockAssignAndReturn(moduleVar, rhs)
1222+
val accessor = if (module.owner == site) module else site.newMethod(module.name.toTermName, site.pos, STABLE).setInfo(moduleVar.tpe)
1223+
val accessorDef = DefDef(accessor, body.changeOwner(moduleVar -> accessor))
1224+
1225+
ValDef(moduleVar) :: accessorDef :: Nil
1226+
}
1227+
1228+
def mixinModuleDefs(clazz: Symbol): List[Tree] = {
1229+
val res = for {
1230+
mixinClass <- clazz.mixinClasses.iterator
1231+
module <- mixinClass.info.decls.iterator.filter(_.isModule)
1232+
newMember <- {module.makeNotPrivate(module.owner); newInnerObject(clazz, module)}
1233+
} yield transform(localTyper.typedPos(clazz.pos)(newMember))
1234+
res.toList
1235+
}
12261236

12271237
def transformStat(tree: Tree, index: Int): List[Tree] = tree match {
12281238
case t if treeInfo.isSelfConstrCall(t) =>
@@ -1651,11 +1661,12 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
16511661
// SI-7870 default getters for constructors live in the companion module
16521662
checkOverloadedRestrictions(currentOwner, currentOwner.companionModule)
16531663
val bridges = addVarargBridges(currentOwner)
1664+
val moduleDesugared = if (currentOwner.isTrait) Nil else mixinModuleDefs(currentOwner)
16541665
checkAllOverrides(currentOwner)
16551666
checkAnyValSubclass(currentOwner)
16561667
if (currentOwner.isDerivedValueClass)
16571668
currentOwner.primaryConstructor makeNotPrivate NoSymbol // SI-6601, must be done *after* pickler!
1658-
if (bridges.nonEmpty) deriveTemplate(tree)(_ ::: bridges) else tree
1669+
if (bridges.nonEmpty || moduleDesugared.nonEmpty) deriveTemplate(tree)(_ ::: bridges ::: moduleDesugared) else tree
16591670

16601671
case dc@TypeTreeWithDeferredRefCheck() => abort("adapt should have turned dc: TypeTreeWithDeferredRefCheck into tpt: TypeTree, with tpt.original == dc")
16611672
case tpt@TypeTree() =>

src/reflect/scala/reflect/internal/Symbols.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
323323
def newModuleVarSymbol(accessor: Symbol): TermSymbol = {
324324
val newName = nme.moduleVarName(accessor.name.toTermName)
325325
val newFlags = MODULEVAR | ( if (this.isClass) PrivateLocal | SYNTHETIC else 0 )
326-
val newInfo = accessor.tpe.finalResultType
326+
val newInfo = thisType.memberType(accessor).finalResultType
327327
val mval = newVariable(newName, accessor.pos.focus, newFlags.toLong) addAnnotation VolatileAttr
328328

329329
if (this.isClass)

src/reflect/scala/reflect/internal/transform/Erasure.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ trait Erasure {
123123
case tref @ TypeRef(pre, sym, args) =>
124124
if (sym == ArrayClass)
125125
if (unboundedGenericArrayLevel(tp) == 1) ObjectTpe
126-
else if (args.head.typeSymbol.isBottomClass) arrayType(ObjectTpe)
126+
else if (args.head.typeSymbol.isBottomClass) arrayType(ObjectTpe)
127127
else typeRef(apply(pre), sym, args map applyInArray)
128128
else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass) ObjectTpe
129129
else if (sym == UnitClass) BoxedUnitTpe
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
trait T1 { def a: Any }
2+
3+
trait T2 extends T1 { object a; object b; private object c; def usec: Any = c}
4+
trait T3 extends T2
5+
6+
class C1 extends T1 { object a; object b }
7+
class C2 extends C1
8+
class C3 extends T2
9+
class C4 extends T3
10+
11+
object Test {
12+
def main(args: Array[String]): Unit = {
13+
val (c1, c2, c3, c4) = (new C1, new C2, new C3, new C4)
14+
c1.a; c1.b; (c1: T1).a
15+
c2.a; c2.b; (c2: T1).a
16+
c3.a; c3.b; (c3: T1).a; c3.usec
17+
c4.a; c4.b; (c4: T1).a; c4.usec
18+
}
19+
20+
}

0 commit comments

Comments
 (0)