@@ -104,8 +104,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
104104 }
105105 }
106106
107- /**
108- * Append offset fields to companion objects.
107+
108+ /** Append offset fields to companion objects
109109 */
110110 override def transformTemplate (template : Template )(using Context ): Tree = {
111111 val cls = ctx.owner.asClass
@@ -122,9 +122,9 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
122122 case _ => prefix ::: stats
123123 }
124124
125- /**
126- * Make an eager val that would implement synthetic module.
125+ /** Make an eager val that would implement synthetic module.
127126 * Eager val ensures thread safety and has less code generated.
127+ *
128128 */
129129 def transformSyntheticModule (tree : ValOrDefDef )(using Context ): Thicket = {
130130 val sym = tree.symbol
@@ -135,8 +135,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
135135 Thicket (field, getter)
136136 }
137137
138- /**
139- * Desugar a local `lazy val x: Int = <RHS>` into:
138+ /** Desugar a local `lazy val x: Int = <RHS>` into:
140139 *
141140 * ```
142141 * val x$lzy = new scala.runtime.LazyInt()
@@ -276,75 +275,47 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
276275 }
277276
278277 /**
279- * Create a threadsafe lazy accessor equivalent to the following code:
278+ * Create a threadsafe lazy accessor and function that computes the field's value. `Evaluating` and
279+ * `NullValue` are represented by `object`s and `Waiting` by a class that allows awaiting the completion
280+ * of the evaluation. Note that since tail-recursive functions are transformed *before* lazy-vals,
281+ * this implementation does involve explicit while loop. `PatternMatcher` is coming before `LazyVals`,
282+ * therefore the pattern matching is implemented using if-s.
283+ *
280284 * ```
281285 * private @volatile var _x: AnyRef = null
282- * @tailrec def x: A =
283- * _x match
284- * case current: A =>
285- * current
286- * case NullValue => null
287- * case null =>
288- * if CAS(_x, null, Evaluating) then
289- * var result: AnyRef = null // here, we need `AnyRef` to possibly assign `NullValue`
290- * try
291- * result = rhs
292- * nullable = null // if the field is nullable; see `CollectNullableFields`
293- * finally
294- * if result == null then result = NullValue // drop if A is non-nullable
295- * if !CAS(_x, Evaluating, result) then
296- * val lock = _x.asInstanceOf[Waiting]
297- * CAS(_x, lock, result)
298- * lock.release()
299- * x
300- * case Evaluating =>
301- * CAS(_x, Evaluating, new Waiting)
302- * x
303- * case current: Waiting =>
304- * current.awaitRelease()
305- * x
306- * ```
307- * Where `Evaluating` and `NullValue` are represented by `object`s and `Waiting` by a class that
308- * allows awaiting the completion of the evaluation. Note that since tail-recursive
309- * functions are transformed *before* lazy-vals, this implementation directly implements
310- * the resulting loop. `PatternMatcher` coming before `LazyVals`, the pattern matching block
311- * is implemented using if-s. Additionally, the code can be optimized to be better inlined by
312- * introducing separate function for computing the lazy value and awaiting it. That is:
313- *
314- * ```
315- * private var _x: AnyRef = null
316286 *
317287 * def x: A =
318- * if !(_x == null || _x.isInstanceOf[LazyValControlState]) then
319- * return _x.asInstanceOf[A]
320- * else if _x == NullValue then
321- * return null
288+ * val result = _x
289+ * if result.isInstanceOf[A] then
290+ * result // possible unboxing applied here
291+ * else if result.eq(NullValue) then
292+ * null // possible unboxing applied here
322293 * else
323- * return x_compute()
294+ * return x_compute() // possible unboxing applied here
324295 *
325296 * private def x_compute() =
326297 * while <EmptyTree> do
327298 * val current: AnyRef = _x
328- * if current == null then
299+ * if current.eq( null) then
329300 * if CAS(_x, null, Evaluating) then
330301 * var resultNullable: AnyRef = null
331302 * var result: AnyRef = null
332303 * try
333304 * resultNullable = rhs
334- * nullable = null
335- * if resultNullable == null then
305+ * nullable = null // nulls out the nullable fields used only in initialization
306+ * if resultNullable.eq( null) then
336307 * result = NullValue
337308 * else
338309 * result = resultNullable
339- * return result
340310 * finally
341311 * if !CAS(_x, Evaluating, result) then
342312 * val lock = _x.asInstanceOf[Waiting]
343313 * CAS(_x, lock, result)
344314 * lock.release()
315+ * return resultNullable
345316 * else
346317 * if current.isInstanceOf[LazyValControlState] then
347- * if current.isInstanceOf[ Evaluating] then // To avoid creating Waiting instance
318+ * if current.eq( Evaluating) then // To avoid creating Waiting instance
348319 * CAS(current, Evaluating, new Waiting)
349320 * else if current.isInstanceOf[Waiting] then
350321 * current.asInstanceOf[Waiting].await()
@@ -353,7 +324,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
353324 * return current.asInstanceOf[A]
354325 * end while
355326 * * ```
356- *
327+ *
357328 * @param memberDef the transformed lazy field member definition
358329 * @param claz the class containing this lazy val field
359330 * @param target the target synthetic field
@@ -469,7 +440,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
469440 Return (ref(current), lazyInitMethodSymbol)
470441 )
471442
472- val initBody = Block (ValDef (current, ref(target)) :: Nil , If (ref(current).equal (nullLiteral), initialize, ifNotUninitialized).withType(defn.UnitType ))
443+ val initBody = Block (ValDef (current, ref(target)) :: Nil , If (ref(current).select(defn. Object_eq ).appliedTo (nullLiteral), initialize, ifNotUninitialized).withType(defn.UnitType ))
473444 val initMainLoop = WhileDo (EmptyTree , initBody) // becomes: while (true) do { body }
474445 val initMethodDef = DefDef (lazyInitMethodSymbol, initMainLoop)
475446 (accessorDef, initMethodDef)
0 commit comments