summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2016-09-02 19:25:46 +0200
committerAdriaan Moors <adriaan@lightbend.com>2016-09-02 19:53:20 +0200
commitc1bd0eadd3412643f95b63d27519b369eabb755d (patch)
tree1453c7bbe92b18c070365b0cad88cfecd632d93a /src
parent50462a45dcbe91ef43652c235721b7a7ec0c8bb2 (diff)
downloadscala-c1bd0eadd3412643f95b63d27519b369eabb755d.tar.gz
scala-c1bd0eadd3412643f95b63d27519b369eabb755d.tar.bz2
scala-c1bd0eadd3412643f95b63d27519b369eabb755d.zip
More elegant holders for local lazy vals.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Fields.scala42
-rw-r--r--src/library/scala/runtime/LazyRef.scala145
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
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"