From 8f47f1694a283c0dc280913eb0c6a895ebd7ef1e Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Wed, 1 Jul 2015 15:32:33 +0200 Subject: [PATCH 1/2] #676 generate less code for lazy vals Modules which are entirely synthetic now are eager This fix additionally makes inner objects of other objects remain static classes, instead of becoming lazy vals. --- src/dotty/tools/dotc/transform/LazyVals.scala | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala index b57e4c5926e3..eac2828049bc 100644 --- a/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/src/dotty/tools/dotc/transform/LazyVals.scala @@ -46,18 +46,38 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { * before this phase starts processing same tree */ override def runsAfter = Set(classOf[Mixin]) - override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = { - if (!(tree.symbol is Flags.Lazy) || tree.symbol.owner.is(Flags.Trait)) tree - else { - val isField = tree.symbol.owner.isClass - - if (isField) { - if (tree.symbol.isVolatile || tree.symbol.is(Flags.Module)) transformMemberDefVolatile(tree) - else transformMemberDefNonVolatile(tree) - } - else transformLocalDef(tree) + override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = + transformLazyVal(tree) + + + override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + transformLazyVal(tree) + } + + def transformLazyVal(tree: ValOrDefDef)(implicit ctx: Context, info: TransformerInfo): Tree = { + val sym = tree.symbol + if (!(sym is Flags.Lazy) || sym.owner.is(Flags.Trait) || (sym.isStatic && sym.is(Flags.Module))) tree + else { + + val isField = sym.owner.isClass + + if (isField) { + if (sym.isVolatile || + (sym.is(Flags.Module) && !sym.is(Flags.Synthetic))) // companion class is synthesized. Should be threadsafe to + // make inner lazy vals thread safe + transformMemberDefVolatile(tree) + else if (sym.is(Flags.Module)) { // synthetic module + val holderSymbol = ctx.newSymbol(sym.owner, sym.asTerm.name ++ nme.LAZY_LOCAL, + Flags.Synthetic, sym.info.widen.resultType).enteredAfter(this) + val field = ValDef(holderSymbol, tree.rhs.changeOwnerAfter(sym, holderSymbol, this)) + val getter = DefDef(sym.asTerm, ref(holderSymbol)) + Thicket(field, getter) + } + else transformMemberDefNonVolatile(tree) } + else transformLocalDef(tree) } + } /** Append offset fields to companion objects @@ -82,7 +102,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { * with a LazyHolder from * dotty.runtime(eg dotty.runtime.LazyInt) */ - def transformLocalDef(x: DefDef)(implicit ctx: Context) = { + def transformLocalDef(x: ValOrDefDef)(implicit ctx: Context) = { val valueInitter = x.rhs val holderName = ctx.freshName(x.name ++ StdNames.nme.LAZY_LOCAL).toTermName val initName = ctx.freshName(x.name ++ StdNames.nme.LAZY_LOCAL_INIT).toTermName @@ -172,7 +192,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { If(cond, init, exp) } - def transformMemberDefNonVolatile(x: DefDef)(implicit ctx: Context) = { + def transformMemberDefNonVolatile(x: ValOrDefDef)(implicit ctx: Context) = { val claz = x.symbol.owner.asClass val tpe = x.tpe.widen.resultType.widen assert(!(x.mods is Flags.Mutable)) @@ -293,7 +313,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { DefDef(methodSymbol, Block(resultDef :: retryDef :: flagDef :: cycle :: Nil, ref(resultSymbol))) } - def transformMemberDefVolatile(x: DefDef)(implicit ctx: Context) = { + def transformMemberDefVolatile(x: ValOrDefDef)(implicit ctx: Context) = { assert(!(x.mods is Flags.Mutable)) val tpe = x.tpe.widen.resultType.widen From 688feee9def94a0aef478b38ebc5188070f9690f Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 13 Jul 2015 12:52:08 +0200 Subject: [PATCH 2/2] Address review comments. --- src/dotty/tools/dotc/transform/LazyVals.scala | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala index eac2828049bc..83668cdab36a 100644 --- a/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/src/dotty/tools/dotc/transform/LazyVals.scala @@ -63,15 +63,12 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { if (isField) { if (sym.isVolatile || - (sym.is(Flags.Module) && !sym.is(Flags.Synthetic))) // companion class is synthesized. Should be threadsafe to - // make inner lazy vals thread safe + (sym.is(Flags.Module) && !sym.is(Flags.Synthetic))) + // module class is user-defined. + // Should be threadsafe, to mimic safety guaranteed by global object transformMemberDefVolatile(tree) else if (sym.is(Flags.Module)) { // synthetic module - val holderSymbol = ctx.newSymbol(sym.owner, sym.asTerm.name ++ nme.LAZY_LOCAL, - Flags.Synthetic, sym.info.widen.resultType).enteredAfter(this) - val field = ValDef(holderSymbol, tree.rhs.changeOwnerAfter(sym, holderSymbol, this)) - val getter = DefDef(sym.asTerm, ref(holderSymbol)) - Thicket(field, getter) + transformSyntheticModule(tree) } else transformMemberDefNonVolatile(tree) } @@ -98,6 +95,19 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { case _ => prefix ::: stats } + /** Make an eager val that would implement synthetic module. + * Eager val ensures thread safety and has less code generated. + * + */ + def transformSyntheticModule(tree: ValOrDefDef)(implicit ctx: Context) = { + val sym = tree.symbol + val holderSymbol = ctx.newSymbol(sym.owner, sym.asTerm.name ++ nme.LAZY_LOCAL, + Flags.Synthetic, sym.info.widen.resultType).enteredAfter(this) + val field = ValDef(holderSymbol, tree.rhs.changeOwnerAfter(sym, holderSymbol, this)) + val getter = DefDef(sym.asTerm, ref(holderSymbol)) + Thicket(field, getter) + } + /** Replace a local lazy val inside a method, * with a LazyHolder from * dotty.runtime(eg dotty.runtime.LazyInt)