aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2015-02-07 17:28:32 +0100
committerodersky <odersky@gmail.com>2015-02-07 17:28:32 +0100
commita759714a730f89ddab28a7bb40aab1b8363b3276 (patch)
treec6a7d65b264bf432a280d3070ba32cbd28060d4f
parent3ce904f018929b69c4208931decfc1710995765c (diff)
parent76ce7c7b1275bded2ca59052b99d743b5c993d6d (diff)
downloaddotty-a759714a730f89ddab28a7bb40aab1b8363b3276.tar.gz
dotty-a759714a730f89ddab28a7bb40aab1b8363b3276.tar.bz2
dotty-a759714a730f89ddab28a7bb40aab1b8363b3276.zip
Merge pull request #346 from dotty-staging/local-lazy-vals
Bring back lazy vals. Changed encoding scheme of local(non-field) lazy vals
-rw-r--r--src/dotty/runtime/LazyHolders.scala44
-rw-r--r--src/dotty/tools/dotc/Compiler.scala5
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--src/dotty/tools/dotc/transform/Getters.scala2
-rw-r--r--src/dotty/tools/dotc/transform/LazyVals.scala83
-rw-r--r--tests/pos/lazyValsSepComp.scala16
6 files changed, 98 insertions, 53 deletions
diff --git a/src/dotty/runtime/LazyHolders.scala b/src/dotty/runtime/LazyHolders.scala
index 86c5d34ec..1e31cda66 100644
--- a/src/dotty/runtime/LazyHolders.scala
+++ b/src/dotty/runtime/LazyHolders.scala
@@ -3,38 +3,42 @@ package dotty.runtime
/**
* Classes used as holders for local lazy vals
*/
-class LazyInt(init: => Int) {
- lazy val value = init
+class LazyInt {
+ var value: Int = _
+ @volatile var initialized: Boolean = false
}
-class LazyLong(init: => Long) {
- lazy val value = init
+class LazyLong {
+ var value: Long = _
+ @volatile var initialized: Boolean = false
}
-class LazyBoolean(init: => Boolean) {
- lazy val value = init
+class LazyBoolean {
+ var value: Boolean = _
+ @volatile var initialized: Boolean = false
}
-class LazyDouble(init: => Double) {
- lazy val value = init
+class LazyDouble {
+ var value: Double = _
+ @volatile var initialized: Boolean = false
}
-class LazyFloat(init: => Float) {
- lazy val value = init
+class LazyByte {
+ var value: Byte = _
+ @volatile var initialized: Boolean = false
}
-class LazyByte(init: => Byte) {
- lazy val value = init
+class LazyRef {
+ var value: AnyRef = _
+ @volatile var initialized: Boolean = false
}
-class LazyRef(init: => AnyRef) {
- lazy val value = init
+class LazyShort {
+ var value: Short = _
+ @volatile var initialized: Boolean = false
}
-class LazyShort(init: => Short) {
- lazy val value = init
-}
-
-class LazyChar(init: => Char) {
- lazy val value = init
+class LazyChar {
+ var value: Char = _
+ @volatile var initialized: Boolean = false
}
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index c5c1d8713..721b52b2e 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -52,7 +52,8 @@ class Compiler {
List(new PatternMatcher,
new ExplicitOuter,
new Splitter),
- List(new ElimByName,
+ List(new LazyVals,
+ new ElimByName,
new SeqLiterals,
new InterceptedMethods,
new Literalize,
@@ -60,7 +61,7 @@ class Compiler {
new ResolveSuper),
List(new Erasure),
List(new Mixin,
- new Memoize, // TODO: Make LazyVals a part of this phase
+ new Memoize,
new CapturedVars,
new Constructors),
List(new LambdaLift,
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index 382ae47de..b7cc1e03f 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -226,6 +226,7 @@ object StdNames {
val FAKE_LOCAL_THIS: N = "this$"
val IMPLCLASS_CONSTRUCTOR: N = "$init$"
val LAZY_LOCAL: N = "$lzy"
+ val LAZY_LOCAL_INIT: N = "$lzyINIT"
val LAZY_FIELD_OFFSET: N = "OFFSET$"
val LAZY_SLOW_SUFFIX: N = "$lzycompute"
val LOCAL_SUFFIX: N = "$$local"
diff --git a/src/dotty/tools/dotc/transform/Getters.scala b/src/dotty/tools/dotc/transform/Getters.scala
index e018a45cc..918a92a04 100644
--- a/src/dotty/tools/dotc/transform/Getters.scala
+++ b/src/dotty/tools/dotc/transform/Getters.scala
@@ -58,7 +58,7 @@ class Getters extends MiniPhaseTransform with SymTransformer { thisTransform =>
}
else d
}
- private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic
+ private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic | Lazy
override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree =
if (tree.symbol is Method) DefDef(tree.symbol.asTerm, tree.rhs) else tree
diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala
index 7b6135dc0..dde086089 100644
--- a/src/dotty/tools/dotc/transform/LazyVals.scala
+++ b/src/dotty/tools/dotc/transform/LazyVals.scala
@@ -12,23 +12,34 @@ import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform
import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.ast.{untpd, tpd}
import dotty.tools.dotc.core.Constants.Constant
-import dotty.tools.dotc.core.Types.MethodType
+import dotty.tools.dotc.core.Types.{ExprType, NoType, MethodType}
import dotty.tools.dotc.core.Names.Name
-import dotty.runtime.LazyVals
+import dotty.runtime.{LazyVals => RLazyVals} // dotty deviation
import SymUtils._
import scala.collection.mutable.ListBuffer
import dotty.tools.dotc.core.Denotations.SingleDenotation
import dotty.tools.dotc.core.SymDenotations.SymDenotation
-import dotty.tools.dotc.core.DenotTransformers.{IdentityDenotTransformer, DenotTransformer}
+import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, IdentityDenotTransformer, DenotTransformer}
-class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer {
+class LazyVals extends MiniPhaseTransform with SymTransformer {
import tpd._
- def transformer = new LazyValsTransform
+ def transformSym(d: SymDenotation)(implicit ctx: Context): SymDenotation = {
+ if(d is(Flags.Lazy, butNot = Flags.ModuleVal | Flags.Method)) {
+ // Method flag is set on lazy vals coming from Unpickler. They are already methods and shouldn't be transformed twice
+ d.copySymDenotation(
+ initFlags = d.flags | Flags.Method,
+ info = ExprType(d.info))
+ }
+ else d
+ }
+
+ def transformer = new LazyVals
- val containerFlags = Flags.Synthetic | Flags.Mutable
+ val containerFlags = Flags.Synthetic | Flags.Mutable | Flags.Lazy
+ val initFlags = Flags.Synthetic | Flags.Method
/** this map contains mutable state of transformation: OffsetDefs to be appended to companion object definitions,
* and number of bits currently used */
@@ -72,9 +83,9 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
* dotty.runtime(eg dotty.runtime.LazyInt)
*/
def transformLocalValDef(x: ValDef)(implicit ctx: Context) = x match {
- case x@ValDef(name, tpt, rhs) =>
- val valueInitter = rhs
+ case x@ValDef(name, tpt, valueInitter) =>
val holderName = ctx.freshName(name.toString + StdNames.nme.LAZY_LOCAL).toTermName
+ val initName = ctx.freshName(name.toString + StdNames.nme.LAZY_LOCAL_INIT).toTermName
val tpe = x.tpe.widen
val holderType =
@@ -88,21 +99,35 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
else if (tpe isRef defn.ShortClass) "LazyShort"
else "LazyRef"
+
val holderImpl = ctx.requiredClass("dotty.runtime." + holderType)
- val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.symbol.coord)
- val holderTree = ValDef(holderSymbol, New(holderImpl.typeRef, List(valueInitter.changeOwner(x.symbol, holderSymbol))))
+ val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.pos)
+ val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType(Nil, tpe), coord = x.pos)
+ val result = ref(holderSymbol).select("value".toTermName)
+ val flag = ref(holderSymbol).select("initialized".toTermName)
+ val initer = valueInitter.changeOwner(x.symbol, initSymbol)
+ val initBody =
+ ref(holderSymbol).select(defn.Object_synchronized).appliedToType(tpe).appliedTo(
+ mkNonThreadSafeDef(result, flag, initer).ensureConforms(tpe))
+ val initTree = DefDef(initSymbol, initBody)
+ val holderTree = ValDef(holderSymbol, New(holderImpl.typeRef, List()))
val methodBody = {
- val prefix = ref(holderSymbol).select("value".toTermName)
- if (holderType != "LazyRef") prefix
- else prefix.select(defn.Any_asInstanceOf).appliedToType(tpe)
+ tpd.If(flag, EmptyTree, ref(initSymbol))
+ result.ensureConforms(tpe)
}
val methodTree = DefDef(x.symbol.asTerm, methodBody)
ctx.debuglog(s"found a lazy val ${x.show},\n rewrote with ${holderTree.show}")
- Thicket(holderTree, methodTree)
+ Thicket(holderTree, initTree, methodTree)
}
- /** Create non-threadsafe lazy accessor equivalent to such code
+
+ override def transformStats(trees: List[tpd.Tree])(implicit ctx: Context, info: TransformerInfo): List[tpd.Tree] = {
+ val (holders, stats) = trees.partition { _.symbol.flags == containerFlags}
+ holders:::stats
+ }
+
+ /** Create non-threadsafe lazy accessor equivalent to such code
* def methodSymbol() = {
* if (flag) target
* else {
@@ -113,13 +138,11 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
* }
*/
- def mkNonThreadSafeDef(target: Symbol, flag: Symbol, rhs: Tree)(implicit ctx: Context) = {
- val cond = ref(flag)
- val exp = ref(target)
- val setFlag = Assign(cond, Literal(Constants.Constant(true)))
- val setTarget = Assign(exp, rhs)
- val init = Block(List(setFlag, setTarget), exp)
- If(cond, exp, init)
+ def mkNonThreadSafeDef(target: Tree, flag: Tree, rhs: Tree)(implicit ctx: Context) = {
+ val setFlag = Assign(flag, Literal(Constants.Constant(true)))
+ val setTarget = Assign(target, rhs)
+ val init = Block(List(setFlag, setTarget), target)
+ If(flag, target, init)
}
/** Create non-threadsafe lazy accessor for not-nullable types equivalent to such code
@@ -155,7 +178,7 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
val flagName = ctx.freshName(name.toString + StdNames.nme.BITMAP_PREFIX).toTermName
val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags, defn.BooleanType)
val flag = ValDef(flagSymbol, Literal(Constants.Constant(false)))
- val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(containerSymbol, flagSymbol, rhs))
+ val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), rhs))
Thicket(List(containerTree, flag, slowPath))
}
@@ -266,7 +289,7 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
val thiz = This(claz)(ctx.fresh.setOwner(claz))
val companion = claz.companionModule
val helperModule = ctx.requiredModule("dotty.runtime.LazyVals")
- val getOffset = Select(ref(helperModule), LazyVals.Names.getOffset.toTermName)
+ val getOffset = Select(ref(helperModule), RLazyVals.Names.getOffset.toTermName)
var offsetSymbol: TermSymbol = null
var flag: Tree = EmptyTree
var ord = 0
@@ -274,7 +297,7 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
// compute or create appropriate offsetSymol, bitmap and bits used by current ValDef
appendOffsetDefs.get(companion.name.moduleClassName) match {
case Some(info) =>
- val flagsPerLong = 64 / LazyVals.BITS_PER_LAZY_VAL
+ val flagsPerLong = 64 / RLazyVals.BITS_PER_LAZY_VAL
info.ord += 1
ord = info.ord % flagsPerLong
val id = info.ord / flagsPerLong
@@ -305,11 +328,11 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
val containerTree = ValDef(containerSymbol, initValue(tpe))
val offset = Select(ref(companion), offsetSymbol.name)
- val getFlag = Select(ref(helperModule), LazyVals.Names.get.toTermName)
- val setFlag = Select(ref(helperModule), LazyVals.Names.setFlag.toTermName)
- val wait = Select(ref(helperModule), LazyVals.Names.wait4Notification.toTermName)
- val state = Select(ref(helperModule), LazyVals.Names.state.toTermName)
- val cas = Select(ref(helperModule), LazyVals.Names.cas.toTermName)
+ val getFlag = Select(ref(helperModule), RLazyVals.Names.get.toTermName)
+ val setFlag = Select(ref(helperModule), RLazyVals.Names.setFlag.toTermName)
+ val wait = Select(ref(helperModule), RLazyVals.Names.wait4Notification.toTermName)
+ val state = Select(ref(helperModule), RLazyVals.Names.state.toTermName)
+ val cas = Select(ref(helperModule), RLazyVals.Names.cas.toTermName)
val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, rhs, tpe, offset, getFlag, state, cas, setFlag, wait)
if(flag eq EmptyTree)
diff --git a/tests/pos/lazyValsSepComp.scala b/tests/pos/lazyValsSepComp.scala
new file mode 100644
index 000000000..337447280
--- /dev/null
+++ b/tests/pos/lazyValsSepComp.scala
@@ -0,0 +1,16 @@
+package dotty.tools
+package io
+
+import java.io.{ InputStream }
+import java.util.jar.JarEntry
+import dotty.tools.dotc.core.Definitions
+import language.postfixOps
+import dotty.tools.dotc.core.Contexts._
+
+
+/** A test to trigger issue with separate compilation between Dotty and Scalac and lazy vals */
+object Foo {
+ val definitions: Definitions = null
+ def defn = definitions
+ def go = defn.FunctionClass(0)
+}