diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Fields.scala | 42 | ||||
-rw-r--r-- | src/library/scala/runtime/LazyRef.scala | 145 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/StdNames.scala | 1 |
3 files changed, 144 insertions, 44 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index 3529fbd0eb..a383b65192 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -528,10 +528,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor * def x$lzycompute(): Int = * x$lzy.synchronized { * if (x$lzy.initialized()) x$lzy.value() - * else { - * x$lzy.initialized = true - * x$lzy.value = rhs - * } + * else x$lzy.initialize(rhs) // for a Unit-typed lazy val, this becomes `{ rhs ; x$lzy.initialize() }` to avoid passing around BoxedUnit * } * def x(): Int = if (x$lzy.initialized()) x$lzy.value() else x$lzycompute() * ``` @@ -543,6 +540,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor val lazyValType = lazyVal.tpe.resultType val refClass = lazyHolders.getOrElse(lazyValType.typeSymbol, LazyRefClass) + val isUnit = refClass == LazyUnitClass val refTpe = if (refClass != LazyRefClass) refClass.tpe else appliedType(refClass.typeConstructor, List(lazyValType)) val lazyName = lazyVal.name.toTermName @@ -556,33 +554,29 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor // Must be marked LAZY to allow forward references, as in `def test2 { println(s.length) ; lazy val s = "abc" } val holderSym = owner.newValue(localLazyName, pos, LAZY | ARTIFACT) setInfo refTpe - val initializedGetter = refTpe.member(nme.initialized) - val isUnit = refClass == LazyUnitClass - val valueGetter = if (isUnit) NoSymbol else refTpe.member(nme.value) - def getValue = if (isUnit) UNIT else Apply(Select(Ident(holderSym), valueGetter), Nil) + val initializedSym = refTpe.member(nme.initialized) + val initializeSym = refTpe.member(nme.initialize) + + // LazyUnit does not have a `value` member + val valueSym = if (isUnit) NoSymbol else refTpe.member(nme.value) - def mkChecked(alreadyComputed: Tree, compute: Tree) = If(Ident(holderSym) DOT initializedGetter, alreadyComputed, compute) + def initialized = Select(Ident(holderSym), initializedSym) + def initialize = Select(Ident(holderSym), initializeSym) + def getValue = if (isUnit) UNIT else Apply(Select(Ident(holderSym), valueSym), Nil) val computerSym = owner.newMethod(lazyName append nme.LAZY_SLOW_SUFFIX, pos, ARTIFACT | PRIVATE) setInfo MethodType(Nil, lazyValType) val rhsAtComputer = rhs.changeOwner(lazyVal -> computerSym) - val computer = mkAccessor(computerSym) { - val setInitialized = Apply(Select(Ident(holderSym), initializedGetter.setterIn(refClass)), TRUE :: Nil) - - if (isUnit) - gen.mkSynchronized(Ident(holderSym))(mkChecked(alreadyComputed = UNIT, compute = Block(List(rhsAtComputer, setInitialized), UNIT))) - else { - val valueSetter = Select(Ident(holderSym), valueGetter.setterIn(refClass)) - - gen.mkSynchronized(Ident(holderSym))(mkChecked( - alreadyComputed = getValue, - compute = Block(Apply(valueSetter, rhsAtComputer :: Nil) :: setInitialized :: Nil, getValue)) - ) - } - } - val accessor = mkAccessor(lazyVal)(mkChecked(getValue, Apply(Ident(computerSym), Nil))) + val computer = mkAccessor(computerSym)(gen.mkSynchronized(Ident(holderSym))( + If(initialized, getValue, + if (isUnit) Block(rhsAtComputer :: Nil, Apply(initialize, Nil)) + else Apply(initialize, rhsAtComputer :: Nil)))) + + val accessor = mkAccessor(lazyVal)( + If(initialized, getValue, + Apply(Ident(computerSym), Nil))) // do last! // remove STABLE: prevent replacing accessor call of type Unit by BoxedUnit.UNIT in erasure diff --git a/src/library/scala/runtime/LazyRef.scala b/src/library/scala/runtime/LazyRef.scala index 3cd2d2d06b..5a0bd5442c 100644 --- a/src/library/scala/runtime/LazyRef.scala +++ b/src/library/scala/runtime/LazyRef.scala @@ -1,52 +1,157 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2016, LAMP/EPFL and Lightbend, Inc ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + package scala.runtime -/* Classes used as holders for local lazy vals */ +/** Classes used as holders for lazy vals defined in methods. */ class LazyRef[T] { - var value: T = _ - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: T = _ + def value: T = _value + def initialize(value: T): T = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyRef ${if (_initialized) s"of: ${_value}" else "thunk"}" } class LazyBoolean { - var value: Boolean = _ - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Boolean = _ + def value: Boolean = _value + def initialize(value: Boolean): Boolean = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyBoolean ${if (_initialized) s"of: ${_value}" else "thunk"}" } class LazyByte { - var value: Byte = _ - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Byte = _ + + def value: Byte = _value + + def initialize(value: Byte): Byte = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyByte ${if (_initialized) s"of: ${_value}" else "thunk"}" } class LazyChar { - var value: Char = _ - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Char = _ + def value: Char = _value + def initialize(value: Char): Char = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyChar ${if (_initialized) s"of: ${_value}" else "thunk"}" } class LazyShort { - var value: Short = _ - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Short = _ + def value: Short = _value + def initialize(value: Short): Short = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyShort ${if (_initialized) s"of: ${_value}" else "thunk"}" } class LazyInt { - var value: Int = _ - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Int = _ + def value: Int = _value + def initialize(value: Int): Int = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyInt ${if (_initialized) s"of: ${_value}" else "thunk"}" } class LazyLong { - var value: Long = _ - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Long = _ + def value: Long = _value + def initialize(value: Long): Long = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyLong ${if (_initialized) s"of: ${_value}" else "thunk"}" } class LazyFloat { - var value: Float = _ - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Float = _ + def value: Float = _value + def initialize(value: Float): Float = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyFloat ${if (_initialized) s"of: ${_value}" else "thunk"}" } class LazyDouble { - var value: Double = _ - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Double = _ + def value: Double = _value + def initialize(value: Double): Double = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyDouble ${if (_initialized) s"of: ${_value}" else "thunk"}" } class LazyUnit { - @volatile var initialized: Boolean = false + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + def initialize(): Unit = _initialized = true + + override def toString = s"LazyUnit${if (_initialized) "" else " thunk"}" } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index c8e4d3d1d5..1a6c84b19e 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -704,6 +704,7 @@ trait StdNames { val immutable: NameType = "immutable" val implicitly: NameType = "implicitly" val in: NameType = "in" + val initialize : NameType = "initialize" val initialized : NameType = "initialized" val internal: NameType = "internal" val inlinedEquals: NameType = "inlinedEquals" |