aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/runtime/LazyHolders.scala40
-rw-r--r--src/dotty/runtime/LazyVals.scala79
-rw-r--r--src/dotty/tools/dotc/Compiler.scala12
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala2
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--src/dotty/tools/dotc/transform/CreateCompanionObjects.scala2
-rw-r--r--src/dotty/tools/dotc/transform/LazyVals.scala377
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala8
-rw-r--r--test/test/transform/LazyValsTest.scala350
9 files changed, 864 insertions, 7 deletions
diff --git a/src/dotty/runtime/LazyHolders.scala b/src/dotty/runtime/LazyHolders.scala
new file mode 100644
index 000000000..86c5d34ec
--- /dev/null
+++ b/src/dotty/runtime/LazyHolders.scala
@@ -0,0 +1,40 @@
+package dotty.runtime
+
+/**
+ * Classes used as holders for local lazy vals
+ */
+class LazyInt(init: => Int) {
+ lazy val value = init
+}
+
+class LazyLong(init: => Long) {
+ lazy val value = init
+}
+
+class LazyBoolean(init: => Boolean) {
+ lazy val value = init
+}
+
+class LazyDouble(init: => Double) {
+ lazy val value = init
+}
+
+class LazyFloat(init: => Float) {
+ lazy val value = init
+}
+
+class LazyByte(init: => Byte) {
+ lazy val value = init
+}
+
+class LazyRef(init: => AnyRef) {
+ lazy val value = init
+}
+
+class LazyShort(init: => Short) {
+ lazy val value = init
+}
+
+class LazyChar(init: => Char) {
+ lazy val value = init
+}
diff --git a/src/dotty/runtime/LazyVals.scala b/src/dotty/runtime/LazyVals.scala
new file mode 100644
index 000000000..4130d4d60
--- /dev/null
+++ b/src/dotty/runtime/LazyVals.scala
@@ -0,0 +1,79 @@
+package dotty.runtime
+
+import scala.annotation.tailrec
+
+/**
+ * Helper methods used in thread-safe lazy vals.
+ */
+object LazyVals {
+ private val unsafe = scala.concurrent.util.Unsafe.instance
+
+ final val BITS_PER_LAZY_VAL = 2
+ final val LAZY_VAL_MASK = 3
+
+ @inline def STATE(cur: Long, ord: Long) = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK
+ @inline def CAS(t: Object, offset: Long, e: Long, v: Long, ord: Int) = {
+ val mask = ~(LAZY_VAL_MASK << ord * BITS_PER_LAZY_VAL)
+ val n = (e & mask) | (v << (ord * BITS_PER_LAZY_VAL))
+ compareAndSet(t, offset, e, n)
+ }
+ @inline def setFlag(t: Object, offset: Long, v: Int, ord: Int) = {
+ var retry = true
+ while (retry) {
+ val cur = get(t, offset)
+ if (STATE(cur, ord) == 1) retry = CAS(t, offset, cur, v, ord)
+ else {
+ // cur == 2, somebody is waiting on monitor
+ if (CAS(t, offset, cur, v, ord)) {
+ val monitor = getMonitor(t, ord)
+ monitor.synchronized {
+ monitor.notifyAll()
+ }
+ retry = false
+ }
+ }
+ }
+ }
+ @inline def wait4Notification(t: Object, offset: Long, cur: Long, ord: Int) = {
+ var retry = true
+ while (retry) {
+ val cur = get(t, offset)
+ val state = STATE(cur, ord)
+ if (state == 1) CAS(t, offset, cur, 2, ord)
+ else if (state == 2) {
+ val monitor = getMonitor(t, ord)
+ monitor.synchronized {
+ monitor.wait()
+ }
+ }
+ else retry = false
+ }
+ }
+
+ @inline def compareAndSet(t: Object, off: Long, e: Long, v: Long) = unsafe.compareAndSwapLong(t, off, e, v)
+ @inline def get(t: Object, off: Long) = unsafe.getLongVolatile(t, off)
+
+ val processors: Int = java.lang.Runtime.getRuntime.availableProcessors()
+ val base: Int = 8 * processors * processors
+ val monitors: Array[Object] = (0 to base).map {
+ x => new Object()
+ }.toArray
+
+ @inline def getMonitor(obj: Object, fieldId: Int = 0) = {
+ var id = (java.lang.System.identityHashCode(obj) + fieldId) % base
+ if (id < 0) id += base
+ monitors(id)
+ }
+
+ @inline def getOffset(obj: Object, name: String) = unsafe.objectFieldOffset(obj.getClass.getDeclaredField(name))
+
+ object Names {
+ final val state = "STATE"
+ final val cas = "CAS"
+ final val setFlag = "setFlag"
+ final val wait4Notification = "wait4Notification"
+ final val compareAndSet = "compareAndSet"
+ final val get = "get"
+ final val getOffset = "getOffset"
+ }
+}
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 84e11e7ed..132a25d0b 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -8,15 +8,19 @@ import Symbols._
import typer.{FrontEnd, Typer, Mode, ImportInfo}
import reporting.ConsoleReporter
import dotty.tools.dotc.core.Phases.Phase
+import dotty.tools.dotc.transform.{LazyValsCreateCompanionObjects, LazyValTranformContext}
+import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer}
+import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer
class Compiler {
- def phases: List[Phase] = List(
- new FrontEnd,
- new transform.SamplePhase)
+
+ def phases: List[Phase] = List(new FrontEnd, new transform.SamplePhase)
var runId = 1
- def nextRunId = { runId += 1; runId }
+ def nextRunId = {
+ runId += 1; runId
+ }
def rootContext(implicit ctx: Context): Context = {
ctx.definitions.init(ctx)
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index ef16a970d..5f6698b33 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -233,6 +233,7 @@ class Definitions {
lazy val AnnotationDefaultAnnot = ctx.requiredClass("dotty.annotation.internal.AnnotationDefault")
lazy val ThrowsAnnot = ctx.requiredClass("scala.throws")
lazy val UncheckedAnnot = ctx.requiredClass("scala.unchecked")
+ lazy val VolatileAnnot = ctx.requiredClass("scala.volatile")
// convenient one-parameter method types
def methOfAny(tp: Type) = MethodType(List(AnyType), tp)
@@ -266,6 +267,7 @@ class Definitions {
def JavaRepeatedParamType = JavaRepeatedParamClass.typeRef
def ThrowableType = ThrowableClass.typeRef
def OptionType = OptionClass.typeRef
+ def VolatileAnnotType = VolatileAnnot.typeRef
def ClassType(arg: Type)(implicit ctx: Context) = {
val ctype = ClassClass.typeRef
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index e7c04e846..0cbcfa5a7 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -221,6 +221,7 @@ object StdNames {
val FAKE_LOCAL_THIS: N = "this$"
val IMPLCLASS_CONSTRUCTOR: N = "$init$"
val LAZY_LOCAL: N = "$lzy"
+ val LAZY_FIELD_OFFSET: N = "OFFSET$"
val LAZY_SLOW_SUFFIX: N = "$lzycompute"
val LOCAL_SUFFIX: N = " "
val UNIVERSE_BUILD_PREFIX: N = "$u.build."
diff --git a/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala b/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala
index dcbcc3b54..8560b6f6d 100644
--- a/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala
+++ b/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala
@@ -25,7 +25,7 @@ abstract class CreateCompanionObjects(group: TreeTransformer, idx: Int) extends
/** Given class definition should return true if companion object creation should be enforced
*/
- def predicate(cls: TypeDef): Boolean
+ def predicate(cls: TypeDef)(implicit ctx:Context): Boolean
override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[tpd.Tree] = {
@tailrec
diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala
new file mode 100644
index 000000000..ffc2096f1
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/LazyVals.scala
@@ -0,0 +1,377 @@
+package dotty.tools.dotc.transform
+
+import scala.collection.mutable
+import dotty.tools.dotc._
+import core._
+import Contexts._
+import Symbols._
+import Decorators._
+import NameOps._
+import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransformer, 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.Names.Name
+import dotty.runtime.LazyVals
+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.DenotTransformer
+
+
+class LazyValsCreateCompanionObjects extends CreateCompanionObjects {
+ import tpd._
+
+
+ override def name: String = "lazyValsModules"
+
+ /** Companion classes are required to hold offsets for volatile lazy vals */
+ override def predicate(forClass: tpd.TypeDef)(implicit ctx: Context): Boolean = {
+ (!(forClass.symbol is Flags.Module)) && forClass.rhs.isInstanceOf[Template] && {
+ val body = forClass.rhs.asInstanceOf[Template].body
+ body.exists {
+ case x: ValDef =>
+ (x.mods is Flags.Lazy) && x.mods.annotations.exists(_.tpe == defn.VolatileAnnotType)
+ case _ => false
+ }
+ }
+ }
+}
+class LazyValTranformContext {
+
+ import tpd._
+
+
+ def transformer = new LazyValsTransform
+
+ /** this map contains mutable state of transformation: OffsetDefs to be appended to companion object definitions,
+ * and number of bits currently used */
+ class OffsetInfo(var defs: List[Tree], var ord:Int)
+ val appendOffsetDefs = mutable.Map.empty[Name, OffsetInfo]
+
+ val infoTransformerNewDefinitions = mutable.Map.empty[ClassSymbol, ListBuffer[Symbol]]
+
+ def addSym(owner: ClassSymbol, sym: Symbol) {
+ infoTransformerNewDefinitions.get(owner) match {
+ case Some(x) => x += sym
+ case None => infoTransformerNewDefinitions.put(owner, ListBuffer(sym))
+ }
+ }
+
+ class LazyValsTransform extends TreeTransform with DenotTransformer {
+
+ override def name: String = "LazyVals"
+
+ def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
+ ref match {
+ case ref: SymDenotation if ref.symbol.isClass =>
+ val oldSym = ref.symbol.asClass
+ infoTransformerNewDefinitions.get(oldSym) match {
+ case Some(x) =>
+ val den = ref.copySymDenotation()
+ den.resetFlag(Flags.Frozen)
+ x.foreach(stat => den.asClass.enter(stat))
+ den
+ case None =>
+ ref
+ }
+ case _ => ref
+ }
+ }
+
+ override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ if (!(tree.mods is Flags.Lazy)) tree
+ else {
+ val isField = tree.symbol.owner.isClass
+ val isVolatile = tree.mods.annotations.exists(_.tpe == defn.VolatileAnnotType)
+
+ if (isField) {
+ if (isVolatile) transformFieldValDefVolatile(tree)
+ else transformFieldValDefNonVolatile(tree)
+ }
+ else transformLocalValDef(tree)
+ }
+ }
+
+ /** Append offset fields to companion objects
+ */
+ override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ if (!tree.symbol.isClass) tree
+ else {
+ appendOffsetDefs.get(tree.symbol.name) match {
+ case None => tree
+ case Some(data) =>
+ val template = tree.rhs.asInstanceOf[Template]
+ ClassDef(tree.symbol.asClass, template.constr, data.defs.mapConserve(transformFollowingDeep) ::: template.body)
+ }
+ }
+ }
+ /** Replace a local lazy val inside a method,
+ * with a LazyHolder from
+ * dotty.runtime(eg dotty.runtime.LazyInt)
+ */
+ def transformLocalValDef(x: ValDef)(implicit ctx: Context) = x match {
+ case x@ValDef(mods, name, tpt, rhs) =>
+ val valueInitter = rhs
+ val holderName = ctx.freshName(name.toString + StdNames.nme.LAZY_LOCAL).toTermName
+ val tpe = x.tpe.widen
+
+ val holderType =
+ if (tpe =:= defn.IntType) "LazyInt"
+ else if (tpe =:= defn.LongType) "LazyLong"
+ else if (tpe =:= defn.BooleanType) "LazyBoolean"
+ else if (tpe =:= defn.FloatType) "LazyFloat"
+ else if (tpe =:= defn.DoubleType) "LazyDouble"
+ else if (tpe =:= defn.ByteType) "LazyByte"
+ else if (tpe =:= defn.CharType) "LazyChar"
+ else if (tpe =:= defn.ShortType) "LazyShort"
+ else "LazyRef"
+
+ val holderImpl = ctx.requiredClass("dotty.runtime." + holderType)
+
+ val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, Flags.Synthetic, holderImpl.typeRef, coord = x.symbol.coord)
+ val holderTree = ValDef(holderSymbol, New(holderImpl.typeRef, List(valueInitter)))
+ val methodTree = DefDef(x.symbol.asTerm, Select(Ident(holderSymbol.termRef), "value".toTermName))
+ ctx.debuglog(s"found a lazy val ${x.show},\n rewrote with ${holderTree.show}")
+ Thicket(holderTree, methodTree)
+ }
+
+ /** Create non-threadsafe lazy accessor equivalent to such code
+ * def methodSymbol() = {
+ * if (flag) target
+ * else {
+ * target = rhs
+ * flag = true
+ * target
+ * }
+ * }
+ */
+
+ def mkNonThreadSafeDef(target: Symbol, flag: Symbol, rhs: Tree)(implicit ctx: Context) = {
+ val cond = Ident(flag.termRef)
+ val exp = Ident(target.termRef)
+ val setFlag = Assign(cond, Literal(Constants.Constant(true)))
+ val setTarget = Assign(exp, rhs)
+ val init = Block(List(setFlag, setTarget), exp)
+ If(cond, exp, init)
+ }
+
+ /** Create non-threadsafe lazy accessor for not-nullable types equivalent to such code
+ * def methodSymbol() = {
+ * if (target eq null) {
+ * target = rhs
+ * target
+ * } else target
+ * }
+ */
+ def mkDefNonThreadSafeNonNullable(target: Symbol, rhs: Tree)(implicit ctx: Context) = {
+ val cond = Apply(Select(Ident(target.termRef), "eq".toTermName), List(Literal(Constant(null))))
+ val exp = Ident(target.termRef)
+ val setTarget = Assign(exp, rhs)
+ val init = Block(List(setTarget), exp)
+ If(cond, init, exp)
+ }
+
+ def initValue(tpe: Types.Type)(implicit ctx: Context) =
+ if (tpe =:= defn.IntType) Constant(0)
+ else if (tpe =:= defn.LongType) Constant(0L)
+ else if (tpe =:= defn.BooleanType) Constant(false)
+ else if (tpe =:= defn.CharType) Constant('\u0000')
+ else if (tpe =:= defn.FloatType) Constant(0f)
+ else if (tpe =:= defn.DoubleType) Constant(0d)
+ else if (tpe =:= defn.ByteType) Constant(0.toByte)
+ else if (tpe =:= defn.ShortType) Constant(0.toShort)
+ else Constant(null)
+
+
+ def transformFieldValDefNonVolatile(x: ValDef)(implicit ctx: Context) = x match {
+ case x@ValDef(mods, name, tpt, rhs) if (mods is Flags.Lazy) =>
+ val claz = x.symbol.owner.asClass
+ val tpe = x.tpe.widen
+ assert(!(mods is Flags.Mutable))
+ val containerName = ctx.freshName(name.toString + StdNames.nme.LAZY_LOCAL).toTermName
+ val containerSymbol = ctx.newSymbol(claz, containerName, (mods &~ Flags.Lazy & Flags.Synthetic).flags, tpe, coord = x.symbol.coord)
+ addSym(claz, containerSymbol)
+
+ val containerTree = ValDef(containerSymbol, Literal(initValue(tpe)))
+ if (x.tpe.isNotNull && initValue(tpe).tag == Constants.NullTag) {
+ val slowPath = DefDef(x.symbol.asTerm, mkDefNonThreadSafeNonNullable(containerSymbol, rhs))
+ Thicket(List(containerTree, slowPath))
+ }
+ else {
+ val flagName = ctx.freshName(name.toString + StdNames.nme.BITMAP_PREFIX).toTermName
+ val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, Flags.Synthetic, defn.BooleanType)
+ val flag = ValDef(flagSymbol, Literal(Constants.Constant(false)))
+ val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(containerSymbol, flagSymbol, rhs))
+ Thicket(List(containerTree, flag, slowPath))
+ }
+
+ }
+
+ /** Create non-threadsafe lazy accessor equivalent to such code
+ *
+ * def methodSymbol(): Int = {
+ * val result: Int = 0
+ * val retry: Boolean = true
+ * var flag: Long = 0L
+ * while retry do {
+ * flag = dotty.runtime.LazyVals.get(this, $claz.$OFFSET)
+ * dotty.runtime.LazyVals.STATE(flag, 0) match {
+ * case 0 =>
+ * if dotty.runtime.LazyVals.CAS(this, $claz.$OFFSET, flag, 1, $ord) {
+ * try {result = rhs} catch {
+ * case x: Throwable =>
+ * dotty.runtime.LazyVals.setFlag(this, $claz.$OFFSET, 0, $ord)
+ * throw x
+ * }
+ * $target = result
+ * dotty.runtime.LazyVals.setFlag(this, $claz.$OFFSET, 3, $ord)
+ * retry = false
+ * }
+ * case 1 =>
+ * dotty.runtime.LazyVals.wait4Notification(this, $claz.$OFFSET, flag, $ord)
+ * case 2 =>
+ * dotty.runtime.LazyVals.wait4Notification(this, $claz.$OFFSET, flag, $ord)
+ * case 3 =>
+ * retry = false
+ * result = $target
+ * }
+ * }
+ * result
+ * }
+ */
+ def mkThreadSafeDef(methodSymbol: TermSymbol, claz: ClassSymbol, ord: Int, target: Symbol, rhs: Tree, tp: Types.Type, offset: Tree, getFlag: Tree, stateMask: Tree, casFlag: Tree, setFlagState: Tree, waitOnLock: Tree)(implicit ctx: Context) = {
+ val initState = Literal(Constants.Constant(0))
+ val computeState = Literal(Constants.Constant(1))
+ val notifyState = Literal(Constants.Constant(2))
+ val computedState = Literal(Constants.Constant(3))
+ val flagSymbol = ctx.newSymbol(methodSymbol, "flag".toTermName, Flags.Mutable & Flags.Synthetic, defn.LongType)
+ val flagDef = ValDef(flagSymbol, Literal(Constant(0L)))
+
+ val thiz = This(claz)(ctx.fresh.withOwner(claz))
+
+ val resultSymbol = ctx.newSymbol(methodSymbol, "result".toTermName, Flags.Mutable & Flags.Synthetic, tp)
+ val resultDef = ValDef(resultSymbol, Literal(initValue(tp.widen)))
+
+ val retrySymbol = ctx.newSymbol(methodSymbol, "retry".toTermName, Flags.Mutable & Flags.Synthetic, defn.BooleanType)
+ val retryDef = ValDef(retrySymbol, Literal(Constants.Constant(true)))
+
+ val whileCond = Ident(retrySymbol.termRef)
+
+ val compute = {
+ val handlerSymbol = ctx.newSymbol(methodSymbol, "$anonfun".toTermName, Flags.Synthetic,
+ MethodType(List("x$1".toTermName), List(defn.ThrowableType), defn.IntType))
+
+ val handler = Closure(handlerSymbol, {
+ args =>
+ val exception = args.head.head
+ val complete = Apply(setFlagState, List(thiz, offset, initState, Literal(Constant(ord))))
+ Block(List(complete), Throw(exception))
+ })
+
+ val compute = Assign(Ident(resultSymbol.termRef), rhs)
+ val tr = Try(compute, handler, EmptyTree)
+ val assign = Assign(Ident(target.termRef), Ident(resultSymbol.termRef))
+ val complete = Apply(setFlagState, List(thiz, offset, computedState, Literal(Constant(ord))))
+ val noRetry = Assign(Ident(retrySymbol.termRef), Literal(Constants.Constant(false)))
+ val body = If(Apply(casFlag, List(thiz, offset, Ident(flagSymbol.termRef), computeState, Literal(Constant(ord)))),
+ Block(tr :: assign :: complete :: noRetry :: Nil, Literal(Constant(()))),
+ Literal(Constant(())))
+
+ CaseDef(initState, EmptyTree, body)
+ }
+
+ val waitFirst = {
+ val wait = Apply(waitOnLock, List(thiz, offset, Ident(flagSymbol.termRef), Literal(Constant(ord))))
+ CaseDef(computeState, EmptyTree, wait)
+ }
+
+ val waitSecond = {
+ val wait = Apply(waitOnLock, List(thiz, offset, Ident(flagSymbol.termRef), Literal(Constant(ord))))
+ CaseDef(notifyState, EmptyTree, wait)
+ }
+
+ val computed = {
+ val noRetry = Assign(Ident(retrySymbol.termRef), Literal(Constants.Constant(false)))
+ val result = Assign(Ident(resultSymbol.termRef), Ident(target.termRef))
+ val body = Block(noRetry :: result :: Nil, Literal(Constant(())))
+ CaseDef(computedState, EmptyTree, body)
+ }
+
+ val cases = Match(Apply(stateMask, List(Ident(flagSymbol.termRef), Literal(Constant(ord)))),
+ List(compute, waitFirst, waitSecond, computed)) //todo: annotate with @switch
+
+ val whileBody = Block(List(Assign(Ident(flagSymbol.termRef), Apply(getFlag, List(thiz, offset)))), cases)
+ val cycle = untpd.WhileDo(whileCond, whileBody).withTypeUnchecked(defn.UnitType)
+ DefDef(methodSymbol, Block(resultDef :: retryDef :: flagDef :: cycle :: Nil, Ident(resultSymbol.termRef)))
+ }
+
+ def transformFieldValDefVolatile(x: ValDef)(implicit ctx: Context) = x match {
+ case x@ValDef(mods, name, tpt, rhs) if (mods is Flags.Lazy) =>
+ assert(!(mods is Flags.Mutable))
+
+ val tpe = x.tpe.widen
+ val claz = x.symbol.owner.asClass
+ val thiz = This(claz)(ctx.fresh.withOwner(claz))
+ val companion = claz.companionModule
+ val helperModule = ctx.requiredModule("dotty.runtime.LazyVals")
+ val getOffset = Select(Ident(helperModule.termRef), LazyVals.Names.getOffset.toTermName)
+ var offsetSymbol: TermSymbol = null
+ var flag: Tree = EmptyTree
+ var ord = 0
+
+ // 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
+ info.ord += 1
+ ord = info.ord % flagsPerLong
+ val id = info.ord / flagsPerLong
+ if(ord != 0) { // there are unused bits in already existing flag
+ offsetSymbol = companion.moduleClass.info.decl((StdNames.nme.LAZY_FIELD_OFFSET + id.toString).toTermName)
+ .suchThat(sym => (sym is Flags.Synthetic) && sym.isTerm)
+ .symbol.asTerm
+ } else { // need to create a new flag
+ offsetSymbol = ctx.newSymbol(companion.moduleClass, (StdNames.nme.LAZY_FIELD_OFFSET + id.toString).toTermName, Flags.Synthetic, defn.LongType).entered
+ val flagName = (StdNames.nme.BITMAP_PREFIX + id.toString).toTermName
+ val flagSymbol = ctx.newSymbol(claz, flagName, Flags.Synthetic, defn.LongType)
+ addSym(claz, flagSymbol)
+ flag = ValDef(flagSymbol, Literal(Constants.Constant(0L)))
+ val offsetTree = ValDef(offsetSymbol, Apply(getOffset, List(thiz, Literal(Constant(flagName.toString)))))
+ info.defs = offsetTree :: info.defs
+ }
+
+ case None =>
+ offsetSymbol = ctx.newSymbol(companion.moduleClass, (StdNames.nme.LAZY_FIELD_OFFSET + "0").toTermName, Flags.Synthetic, defn.LongType).entered
+ val flagName = (StdNames.nme.BITMAP_PREFIX + "0").toTermName
+ val flagSymbol = ctx.newSymbol(claz, flagName, Flags.Synthetic, defn.LongType)
+ addSym(claz, flagSymbol)
+ flag = ValDef(flagSymbol, Literal(Constants.Constant(0L)))
+ val offsetTree = ValDef(offsetSymbol, Apply(getOffset, List(thiz, Literal(Constant(flagName.toString)))))
+ appendOffsetDefs += (companion.name.moduleClassName -> new OffsetInfo(List(offsetTree), ord))
+ }
+
+ val containerName = ctx.freshName(name.toString + StdNames.nme.LAZY_LOCAL).toTermName
+ val containerSymbol = ctx.newSymbol(claz, containerName, (mods &~ Flags.Lazy & Flags.Synthetic).flags, tpe, coord = x.symbol.coord)
+ addSym(claz, containerSymbol)
+ val containerTree = ValDef(containerSymbol, Literal(initValue(tpe)))
+
+ val offset = Select(Ident(companion.termRef), offsetSymbol.name)
+ val getFlag = Select(Ident(helperModule.termRef), LazyVals.Names.get.toTermName)
+ val setFlag = Select(Ident(helperModule.termRef), LazyVals.Names.setFlag.toTermName)
+ val wait = Select(Ident(helperModule.termRef), LazyVals.Names.wait4Notification.toTermName)
+ val state = Select(Ident(helperModule.termRef), LazyVals.Names.state.toTermName)
+ val cas = Select(Ident(helperModule.termRef), LazyVals.Names.compareAndSet.toTermName)
+
+ val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, rhs, x.tpe, offset, getFlag, state, cas, setFlag, wait)
+ if(flag eq EmptyTree)
+ Thicket(List(containerTree, accessor))
+ else Thicket(List(containerTree, flag, accessor))
+ }
+
+ }
+}
+
+
+
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index ecbe8daaf..3e29af0e4 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -113,13 +113,16 @@ object TreeTransforms {
def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] = trees
/** Transform tree using all transforms of current group (including this one) */
- def transform(tree: Tree)(implicit ctx: Context): Tree = group.transform(tree)
+ def transform(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = group.transform(tree, info, 0)
/** Transform subtree using all transforms following the current one in this group */
def transformFollowingDeep(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = group.transform(tree, info, idx + 1)
/** Transform single node using all transforms following the current one in this group */
def transformFollowing(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = group.transformSingle(tree, idx + 1)
+
+ /** perform context-dependant initialization */
+ def init(implicit ctx:Context): Unit = {}
}
val NoTransform = new TreeTransform(null, -1)
@@ -402,7 +405,7 @@ object TreeTransforms {
var nxCopied = false
var result = info.transformers
var resultNX = info.nx
- var i = mutationPlan(cur)
+ var i = mutationPlan(0) // if TreeTransform.transform() method didn't exist we could have used mutationPlan(cur)
val l = result.length
var allDone = i < l
while (i < l) {
@@ -459,6 +462,7 @@ object TreeTransforms {
def transform(t: Tree)(implicit ctx: Context): Tree = {
val initialTransformations = transformations.zipWithIndex.map(x => x._1(this, x._2))
+ initialTransformations.foreach(_.init)
transform(t, new TransformerInfo(initialTransformations, new NXTransformations(initialTransformations)), 0)
}
diff --git a/test/test/transform/LazyValsTest.scala b/test/test/transform/LazyValsTest.scala
new file mode 100644
index 000000000..c14ee3e98
--- /dev/null
+++ b/test/test/transform/LazyValsTest.scala
@@ -0,0 +1,350 @@
+package test.transform
+
+import org.junit.Test
+import test.DottyTest
+import org.junit.Assert
+
+class LazyValsTest extends DottyTest {
+
+ @Test
+ def localInt = {
+ checkCompile("LazyVals", "class LocalLV { def m = { lazy val s = 1; s }}"){ (tree, ctx) =>
+ Assert.assertTrue("local lazy int rewritten to class creation", tree.toString.contains(
+ "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class runtime),LazyInt)],Apply(Select(New(TypeTree[TypeRef(ThisType(module class runtime),LazyInt)]),<init>),List(Literal(Constant(1)))))"
+ ))
+ }
+ }
+ /*
+ @Test
+ def localLong = {
+ checkCompile("LazyVals", "class LocalLV { def m = { lazy val s = 1L; s }}"){ (tree, ctx) =>
+ Assert.assertTrue("local lazy long rewritten to class creation", tree.toString.contains(
+ "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class runtime),LazyLong)],Apply(Select(New(TypeTree[TypeRef(ThisType(module class runtime),LazyLong)]),<init>),List(Literal(Constant(1)))))"
+ ))
+ }
+ }
+
+ @Test
+ def localFloat = {
+ checkCompile("LazyVals", "class LocalLV { def m = { lazy val s = 1.0f; s }}"){ (tree, ctx) =>
+ Assert.assertTrue("local lazy float rewritten to class creation", tree.toString.contains(
+ "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class runtime),LazyFloat)],Apply(Select(New(TypeTree[TypeRef(ThisType(module class runtime),LazyFloat)]),<init>),List(Literal(Constant(1.0)))))"
+ ))
+ }
+ }
+
+ @Test
+ def localDouble = {
+ checkCompile("LazyVals", "class LocalLV { def m = { lazy val s = 1.0; s }}"){ (tree, ctx) =>
+ Assert.assertTrue("local lazy double rewritten to class creation", tree.toString.contains(
+ "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class runtime),LazyDouble)],Apply(Select(New(TypeTree[TypeRef(ThisType(module class runtime),LazyDouble)]),<init>),List(Literal(Constant(1.0)))))"
+ ))
+ }
+ }
+
+ @Test
+ def localBoolean = {
+ checkCompile("LazyVals", "class LocalLV { def m = { lazy val s = true; s }}"){ (tree, ctx) =>
+ Assert.assertTrue("local lazy boolean rewritten to class creation", tree.toString.contains(
+ "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class runtime),LazyBoolean)],Apply(Select(New(TypeTree[TypeRef(ThisType(module class runtime),LazyBoolean)]),<init>),List(Literal(Constant(true)))))"
+ ))
+ }
+ }
+
+ @Test
+ def localChar = {
+ checkCompile("LazyVals", "class LocalLV { def m = { lazy val s = 'a'; s }}"){ (tree, ctx) =>
+ Assert.assertTrue("local lazy char rewritten to class creation", tree.toString.contains(
+ "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class runtime),LazyChar)],Apply(Select(New(TypeTree[TypeRef(ThisType(module class runtime),LazyChar)]),<init>),List(Literal(Constant(a)))))"
+ ))
+ }
+ }
+
+ @Test
+ def localByte = {
+ checkCompile("LazyVals", "class LocalLV { def m = { lazy val s:Byte = 1; s }}"){ (tree, ctx) =>
+ Assert.assertTrue("local lazy byte rewritten to class creation", tree.toString.contains(
+ "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class runtime),LazyByte)],Apply(Select(New(TypeTree[TypeRef(ThisType(module class runtime),LazyByte)]),<init>),List(Literal(Constant(1)))))"
+ ))
+ }
+ }
+
+ @Test
+ def localShort = {
+ checkCompile("LazyVals", "class LocalLV { def m = { lazy val s:Short = 1; s }}"){ (tree, ctx) =>
+ Assert.assertTrue("local lazy short rewritten to class creation", tree.toString.contains(
+ "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class runtime),LazyShort)],Apply(Select(New(TypeTree[TypeRef(ThisType(module class runtime),LazyShort)]),<init>),List(Literal(Constant(1)))))"
+ ))
+ }
+ }
+
+ @Test
+ def localRef = {
+ checkCompile("LazyVals", "class LocalLV { def m = { lazy val s = \"string\"; s }}"){ (tree, ctx) =>
+ Assert.assertTrue("local lazy ref rewritten to class creation", tree.toString.contains(
+ "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class runtime),LazyRef)],Apply(Select(New(TypeTree[TypeRef(ThisType(module class runtime),LazyRef)]),<init>),List(Literal(Constant(string)))))"
+ ))
+ }
+ }
+
+ @Test
+ def fieldRef = {
+ checkCompile("LazyVals", "class LV { lazy val s = \"string\" }"){ (tree, ctx) =>
+ Assert.assertTrue("field lazy int rewritten to class creation", tree.toString.contains(
+ "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class lang),String)],If(Ident(sbitmap$1),Ident(s$lzy1),Block(List(Assign(Ident(sbitmap$1),Literal(Constant(true))), Assign(Ident(s$lzy1),Literal(Constant(string)))),Ident(s$lzy1))))"
+ ))
+ }
+ }
+
+ @Test
+ def fieldInt = {
+ checkCompile("LazyVals", "class LV { lazy val s = 1 }"){ (tree, ctx) =>
+ Assert.assertTrue("field lazy int rewritten", tree.toString.contains(
+ "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Int)],If(Ident(sbitmap$1),Ident(s$lzy1),Block(List(Assign(Ident(sbitmap$1),Literal(Constant(true))), Assign(Ident(s$lzy1),Literal(Constant(1)))),Ident(s$lzy1))))"
+ ))
+ }
+ }
+
+ @Test
+ def fieldLong = {
+ checkCompile("LazyVals", "class LV { lazy val s = 1L }"){ (tree, ctx) =>
+ Assert.assertTrue("field lazy long rewritten", tree.toString.contains(
+ "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Long)],If(Ident(sbitmap$1),Ident(s$lzy1),Block(List(Assign(Ident(sbitmap$1),Literal(Constant(true))), Assign(Ident(s$lzy1),Literal(Constant(1)))),Ident(s$lzy1))))"
+ ))
+ }
+ }
+
+ @Test
+ def fieldShort = {
+ checkCompile("LazyVals", "class LV { lazy val s:Short = 1 }"){ (tree, ctx) =>
+ Assert.assertTrue("field lazy short rewritten", tree.toString.contains(
+ "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Short)],If(Ident(sbitmap$1),Ident(s$lzy1),Block(List(Assign(Ident(sbitmap$1),Literal(Constant(true))), Assign(Ident(s$lzy1),Literal(Constant(1)))),Ident(s$lzy1))))"
+ ))
+ }
+ }
+
+ @Test
+ def fieldByte = {
+ checkCompile("LazyVals", "class LV { lazy val s:Byte = 1 }"){ (tree, ctx) =>
+ Assert.assertTrue("field lazy byte rewritten", tree.toString.contains(
+ "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Byte)],If(Ident(sbitmap$1),Ident(s$lzy1),Block(List(Assign(Ident(sbitmap$1),Literal(Constant(true))), Assign(Ident(s$lzy1),Literal(Constant(1)))),Ident(s$lzy1))))"
+ ))
+ }
+ }
+
+ @Test
+ def fieldBoolean = {
+ checkCompile("LazyVals", "class LV { lazy val s = true }"){ (tree, ctx) =>
+ Assert.assertTrue("field lazy boolean rewritten", tree.toString.contains(
+ "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Boolean)],If(Ident(sbitmap$1),Ident(s$lzy1),Block(List(Assign(Ident(sbitmap$1),Literal(Constant(true))), Assign(Ident(s$lzy1),Literal(Constant(true)))),Ident(s$lzy1))))"
+ ))
+ }
+ }
+
+ @Test
+ def fieldDouble = {
+ checkCompile("LazyVals", "class LV { lazy val s = 1.0 }"){ (tree, ctx) =>
+ Assert.assertTrue("field lazy double rewritten", tree.toString.contains(
+ "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Double)],If(Ident(sbitmap$1),Ident(s$lzy1),Block(List(Assign(Ident(sbitmap$1),Literal(Constant(true))), Assign(Ident(s$lzy1),Literal(Constant(1.0)))),Ident(s$lzy1))))"
+ ))
+ }
+ }
+
+ @Test
+ def fieldFloat = {
+ checkCompile("LazyVals", "class LV { lazy val s = 1.0f }"){ (tree, ctx) =>
+ Assert.assertTrue("field lazy float rewritten", tree.toString.contains(
+ "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Float)],If(Ident(sbitmap$1),Ident(s$lzy1),Block(List(Assign(Ident(sbitmap$1),Literal(Constant(true))), Assign(Ident(s$lzy1),Literal(Constant(1.0)))),Ident(s$lzy1))))"
+ ))
+ }
+ }
+
+ @Test
+ def fieldChar = {
+ checkCompile("LazyVals", "class LV { lazy val s = 'a' }"){ (tree, ctx) =>
+ Assert.assertTrue("field lazy char rewritten", tree.toString.contains(
+ "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Char)],If(Ident(sbitmap$1),Ident(s$lzy1),Block(List(Assign(Ident(sbitmap$1),Literal(Constant(true))), Assign(Ident(s$lzy1),Literal(Constant(a)))),Ident(s$lzy1))))"
+ ))
+ }
+ }
+
+ @Test
+ def volatileFieldRef = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val s = \"a\" }") {
+ (tree, ctx) =>
+ val accessor = "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class lang),String)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(null))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(a))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
+ val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class lang),String)],Literal(Constant(null))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
+ }
+ }
+
+ @Test
+ def volatileFieldInt = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val s = 1 }") {
+ (tree, ctx) =>
+ val accessor = "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
+ val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Int)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
+ }
+ }
+
+ @Test
+ def volatileFieldLong = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val s = 1L }") {
+ (tree, ctx) =>
+ val accessor = "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Long)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
+ val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
+ }
+ }
+
+ @Test
+ def volatileFieldFloat = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val s = 1.0f }") {
+ (tree, ctx) =>
+ val accessor = "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Float)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1.0))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
+ val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Float)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
+ }
+ }
+
+ @Test
+ def volatileFieldDouble = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val s = 1.0 }") {
+ (tree, ctx) =>
+ val accessor = "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Double)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1.0))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
+ val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Double)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
+ }
+ }
+
+ @Test
+ def volatileFieldBoolean = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val s = true }") {
+ (tree, ctx) =>
+ val accessor = "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Boolean)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(false))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(true))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
+ val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(false))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
+ }
+ }
+
+ @Test
+ def volatileFieldByte = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val s:Byte = 1 }") {
+ (tree, ctx) =>
+ val accessor = "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Byte)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
+ val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Byte)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
+ }
+ }
+
+ @Test
+ def volatileFieldShort = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val s:Short = 1 }") {
+ (tree, ctx) =>
+ val accessor = "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Short)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
+ val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Short)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
+ }
+ }
+
+ @Test
+ def volatileFieldChar = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val s = 'a' }") {
+ (tree, ctx) =>
+ val accessor = "DefDef(Modifiers(,,List()),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Char)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(\u0000))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(a))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
+ val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Char)],Literal(Constant(\u0000))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
+ }
+ }
+
+ @Test
+ def volatilesReuseBitmaps = {
+ checkCompile("LazyVals", "class LV { @volatile lazy val a = 'a'; @volatile lazy val b = 'b'; }") {
+ (tree, ctx) =>
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val reuseFieldPattern = "Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(1))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(moduleField) && treeS.contains(reuseFieldPattern))
+ }
+ }
+
+ @Test
+ def volatilesCreateNewBitmaps = {
+ checkCompile("LazyVals",
+ """
+ | class LV {
+ | @volatile lazy val a1 = '1';
+ | @volatile lazy val a2 = '1';
+ | @volatile lazy val a3 = '1';
+ | @volatile lazy val a4 = '1';
+ | @volatile lazy val a5 = '1';
+ | @volatile lazy val a6 = '1';
+ | @volatile lazy val a7 = '1';
+ | @volatile lazy val a8 = '1';
+ | @volatile lazy val a9 = '1';
+ | @volatile lazy val a10 = '1';
+ | @volatile lazy val a11 = '1';
+ | @volatile lazy val a12 = '1';
+ | @volatile lazy val a13 = '1';
+ | @volatile lazy val a14 = '1';
+ | @volatile lazy val a15 = '1';
+ | @volatile lazy val a16 = '1';
+ | @volatile lazy val a17 = '1';
+ | @volatile lazy val a18 = '1';
+ | @volatile lazy val a19 = '1';
+ | @volatile lazy val a20 = '1';
+ | @volatile lazy val a21 = '1';
+ | @volatile lazy val a22 = '1';
+ | @volatile lazy val a23 = '1';
+ | @volatile lazy val a24 = '1';
+ | @volatile lazy val a25 = '1';
+ | @volatile lazy val a26 = '1';
+ | @volatile lazy val a27 = '1';
+ | @volatile lazy val a28 = '1';
+ | @volatile lazy val a29 = '1';
+ | @volatile lazy val a30 = '1';
+ | @volatile lazy val a31 = '1';
+ | @volatile lazy val a32 = '1';
+ | @volatile lazy val a33 = '1';
+ | @volatile lazy val a34 = '1';
+ | }
+ """.stripMargin ){
+ (tree, ctx) =>
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$1,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$1))))), ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val reuseFieldPattern = "Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$1), Literal(Constant(3)), Literal(Constant(1))))"
+ val treeS = tree.toString
+ Assert.assertTrue("volatile field lazy ref rewritten to class creation",
+ treeS.contains(moduleField) && treeS.contains(reuseFieldPattern))
+ }
+ }
+ */
+}