aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorDmitry Petrashko <dmitry.petrashko@gmail.com>2014-03-14 12:56:11 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-03-19 14:13:47 +0100
commit5cbd2fbc8409b446f8751792b006693e1d091055 (patch)
tree6440bff96597df0e10e69a66ec673091f92ea284 /src/dotty/tools
parent46856320f4e21d94b3c5c29a921efac40e12421f (diff)
downloaddotty-5cbd2fbc8409b446f8751792b006693e1d091055.tar.gz
dotty-5cbd2fbc8409b446f8751792b006693e1d091055.tar.bz2
dotty-5cbd2fbc8409b446f8751792b006693e1d091055.zip
LazyVals phase.
Creates accessors for lazy vals: 1) lazy local vals are rewritten to dotty.runtime.Lazy*** holders 2) for a non-volatile field lazy val create a non-thread-safe accessor and flag: 2.a) if lazy val type indicates that val is not nullable, uses null value as a flag 2.b) else uses boolean flag for sake of performance, method size, and allowing more jvm optimizations 3) for a volatile field lazy val use double locking scheme, that guaranties no spurious deadlocks, using long bits as bitmaps and creating companion objects to store offsets needed for unsafe methods. Conflicts: test/dotc/tests.scala
Diffstat (limited to 'src/dotty/tools')
-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
6 files changed, 395 insertions, 7 deletions
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)
}