@@ -17,9 +17,9 @@ package immutable
1717import scala .language .`2.13`
1818import java .io .{ObjectInputStream , ObjectOutputStream }
1919import java .lang .{StringBuilder => JStringBuilder }
20-
2120import scala .annotation .tailrec
2221import scala .collection .generic .SerializeEnd
22+ import scala .collection .immutable .LazyListBase .InRace
2323import scala .collection .mutable .{Builder , ReusableBuilder , StringBuilder }
2424import scala .language .implicitConversions
2525import scala .runtime .Statics
@@ -264,7 +264,7 @@ import scala.runtime.Statics
264264 */
265265@ SerialVersionUID (4L )
266266final class LazyList [+ A ] private (lazyState : AnyRef /* EmptyMarker.type | () => LazyList[A] */ )
267- extends AbstractSeq [A ]
267+ extends LazyListBase [A ]( if (lazyState eq LazyList . EmptyMarker ) null else lazyState)
268268 with LinearSeq [A ]
269269 with LinearSeqOps [A , LazyList , LazyList [A ]]
270270 with IterableFactoryDefaults [A , LazyList ]
@@ -276,56 +276,86 @@ final class LazyList[+A] private (lazyState: AnyRef /* EmptyMarker.type | () =>
276276 private def this (head : A , tail : LazyList [A ]) = {
277277 this (LazyList .EmptyMarker )
278278 _head = head
279- _tail = tail
279+ setRawTail( tail)
280280 }
281281
282- // used to synchronize lazy state evaluation
283- // after initialization (`_head ne Uninitialized`)
282+ // `_head` and `_tail` are used to synchronize lazy state evaluation.
283+ //
284+ // initially, `_head` is `Uninitialized`. after initialization, `_head` holds:
284285 // - `null` if this is an empty lazy list
285- // - `head: A` otherwise (can be `null`, `_tail == null` is used to test emptiness)
286+ // - `head: A` otherwise (can be the `null` value, `_tail == null` is used to test emptiness)
287+ //
288+ // `_tail` (declared in `LazyListBase`) can hold the following values:
289+ // - when `_head eq Uninitialized`
290+ // - `lazyState: () => LazyList[A]`
291+ // - while evaluating `lazyState`: the evaluating `Thread`
292+ // - if multiple threads attempt initialization: an `InRace` instance
293+ // - when `_head ne Uninitialized`
294+ // - `null` if this is an empty lazy list
295+ // - `tail: LazyList[A]` otherwise
286296 @ volatile private var _head : Any /* Uninitialized | A */ =
287297 if (lazyState eq EmptyMarker ) null else Uninitialized
288298
289- // when `_head eq Uninitialized`
290- // - `lazySate: () => LazyList[A]`
291- // - MidEvaluation while evaluating lazyState
292- // when `_head ne Uninitialized`
293- // - `null` if this is an empty lazy list
294- // - `tail: LazyList[A]` otherwise
295- private var _tail : AnyRef | Null /* () => LazyList[A] | MidEvaluation.type | LazyList[A] | Null */ =
296- if (lazyState eq EmptyMarker ) null else lazyState
297-
298299 private def rawHead : Any = _head
299- private def rawTail : AnyRef | Null = _tail
300300
301301 @ inline private def isEvaluated : Boolean = _head.asInstanceOf [AnyRef ] ne Uninitialized
302302
303- private def initState (): Unit = synchronized {
304- if (! isEvaluated) {
305- // if it's already mid-evaluation, we're stuck in an infinite
306- // self-referential loop (also it's empty)
307- if (_tail eq MidEvaluation )
308- throw new RuntimeException (
309- " LazyList evaluation depends on its own result (self-reference); see docs for more info" )
310-
311- val fun = _tail.asInstanceOf [() => LazyList [A ]]
312- _tail = MidEvaluation
313- val l =
314- // `fun` returns a LazyList that represents the state (head/tail) of `this`. We call `l.evaluated` to ensure
315- // `l` is initialized, to prevent races when reading `rawTail` / `rawHead` below.
316- // Often, lazy lists are created with `newLL(eagerCons(...))` so `l` is already initialized, but `newLL` also
317- // accepts non-evaluated lazy lists.
318- try fun().evaluated
319- // restore `fun` in finally so we can try again later if an exception was thrown (similar to lazy val)
320- finally _tail = fun
321- _tail = l.rawTail
322- _head = l.rawHead
303+ private def initState (): Unit = {
304+ def selfRef (): Nothing =
305+ // if it's already mid-evaluation, we're stuck in an infinite self-referential loop (also it's empty)
306+ throw new RuntimeException (
307+ " LazyList evaluation depends on its own result (self-reference); see docs for more info" )
308+
309+ while (! isEvaluated) {
310+ rawTail match {
311+ case t : Thread =>
312+ if (LazyListBase .isCurrentThread(t)) selfRef()
313+ val ir = InRace (t)
314+ if (_tailUpdater.compareAndSet(this , t, ir))
315+ ir.await()
316+ // loop on lost CAS
317+
318+ case ir : InRace =>
319+ if (LazyListBase .isCurrentThread(ir.owner)) selfRef()
320+ ir.await()
321+
322+ case fun : Function0 [_] =>
323+ // use the current thread as marker that `fun` is being evaluated.
324+ // this way, there is no allocation in the common case where there's no race.
325+ // if multiple threads attempt to initialize a LazyList, an `InRace` instance is created to coordinate.
326+ if (_tailUpdater.compareAndSet(this , fun, Thread .currentThread)) {
327+ var ex : Throwable | Null = null
328+ // `fun` returns a LazyList that represents the state (head/tail) of `this`. We call `evaluated` to ensure
329+ // the result is initialized, to prevent races when reading `rawTail` / `rawHead` below.
330+ // Often, lazy lists are created with `newLL(eagerCons(...))` so `l` is already initialized, but `newLL`
331+ // also accepts non-evaluated lazy lists.
332+ val l = try fun().asInstanceOf [LazyList [A ]].evaluated catch {
333+ case t : Throwable =>
334+ ex = t
335+ null
336+ }
337+ // update `_tail` before `_head`, because `_head` is used to test `isEvaluated`
338+ val newTail = if (ex == null ) l.nn.rawTail else fun
339+ val sentinel = _tailUpdater.getAndSet(this , newTail)
340+ if (ex == null ) _head = l.nn.rawHead
341+ sentinel match {
342+ case ir : InRace => ir.countDown()
343+ case _ =>
344+ }
345+ if (ex != null ) throw ex.nn
346+ }
347+ // loop on lost CAS
348+
349+ case _ =>
350+ // loop when _tail is a LazyList but _head is still `Uninitialized`
351+ // could call `Thread.onSpinWait()` on JDK 9+
352+ }
323353 }
324354 }
325355
326356 @ tailrec private def evaluated : LazyList [A ] =
327357 if (isEvaluated) {
328- if (_tail == null ) Empty
358+ if (rawTail == null ) Empty
329359 else this
330360 } else {
331361 initState()
@@ -1160,11 +1190,13 @@ object LazyList extends SeqFactory[LazyList] {
11601190 // def kount(): Unit = k += 1
11611191
11621192 private object Uninitialized extends Serializable
1163- private object MidEvaluation
11641193 private object EmptyMarker
11651194
11661195 private val Empty : LazyList [Nothing ] = new LazyList (EmptyMarker )
11671196
1197+ // lazy val to break cycle (Predef -> scala.package -> val LazyList -> makeTailUpdater -> Predef.classOf)
1198+ private lazy val _tailUpdater : LazyListBase .TailUpdater = Empty .makeTailUpdater
1199+
11681200 /** Creates a new LazyList.
11691201 *
11701202 * @tparam A the element type of the lazy list
0 commit comments