Skip to content

Commit 1825b6b

Browse files
committed
Make List safe to share across threads without synchronization
1 parent 41f4394 commit 1825b6b

File tree

4 files changed

+22
-6
lines changed

4 files changed

+22
-6
lines changed

src/library/scala/collection/immutable/List.scala

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import java.io.{ObjectInputStream, ObjectOutputStream}
77
import scala.annotation.unchecked.uncheckedVariance
88
import scala.annotation.tailrec
99
import mutable.{Builder, ListBuffer}
10+
import scala.runtime.ScalaRunTime
1011

1112
/** A class for immutable linked lists representing ordered collections
1213
* of elements of type `A`.
@@ -147,6 +148,7 @@ sealed abstract class List[+A]
147148
t = nx
148149
rest = rest.tail
149150
}
151+
ScalaRunTime.releaseFence()
150152
h
151153
}
152154

@@ -216,6 +218,7 @@ sealed abstract class List[+A]
216218
t = nx
217219
rest = rest.tail
218220
}
221+
ScalaRunTime.releaseFence()
219222
h
220223
}
221224
}
@@ -242,7 +245,7 @@ sealed abstract class List[+A]
242245
}
243246
rest = rest.tail
244247
} while (rest ne Nil)
245-
h
248+
{ScalaRunTime.releaseFence(); h}
246249
}
247250
}
248251

@@ -267,7 +270,7 @@ sealed abstract class List[+A]
267270
}
268271
rest = rest.tail
269272
}
270-
if (!found) Nil else h
273+
if (!found) Nil else {ScalaRunTime.releaseFence(); h}
271274
}
272275
}
273276

@@ -435,7 +438,9 @@ sealed abstract class List[+A]
435438
}
436439
}
437440
}
438-
loop(null, null, this, this)
441+
val result = loop(null, null, this, this)
442+
ScalaRunTime.releaseFence()
443+
result
439444
}
440445

441446
override def filter(p: A => Boolean): List[A] = filterImpl(p, isFlipped = false)
@@ -517,7 +522,9 @@ sealed abstract class List[+A]
517522
newHead
518523
}
519524

520-
noneIn(this)
525+
val result = noneIn(this)
526+
ScalaRunTime.releaseFence()
527+
result
521528
}
522529

523530
final override def toList: List[A] = this
@@ -546,6 +553,7 @@ sealed abstract class List[+A]
546553

547554
final case class :: [+A](override val head: A, private[scala] var next: List[A @uncheckedVariance]) // sound because `next` is used only locally
548555
extends List[A] {
556+
ScalaRunTime.releaseFence()
549557
override def isEmpty: Boolean = false
550558
override def headOption: Some[A] = Some(head)
551559
override def tail: List[A] = next

src/library/scala/collection/mutable/ListBuffer.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import scala.annotation.tailrec
55
import scala.collection.immutable.{List, Nil, ::}
66
import scala.annotation.tailrec
77
import java.lang.{IllegalArgumentException, IndexOutOfBoundsException}
8+
import scala.runtime.ScalaRunTime
89

910
/** A `Buffer` implementation backed by a list. It provides constant time
1011
* prepend and append. Most other operations are linear.
@@ -61,6 +62,7 @@ class ListBuffer[A]
6162
// Avoids copying where possible.
6263
override def toList: List[A] = {
6364
aliased = nonEmpty
65+
ScalaRunTime.releaseFence()
6466
first
6567
}
6668

src/reflect/scala/reflect/internal/tpe/FindMembers.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package tpe
77

88
import util.StatisticsStatics
99
import Flags._
10+
import scala.runtime.ScalaRunTime
1011

1112
trait FindMembers {
1213
this: SymbolTable =>
@@ -282,6 +283,7 @@ trait FindMembers {
282283
} else {
283284
if (StatisticsStatics.areSomeColdStatsEnabled) statistics.incCounter(multMemberCount)
284285
lastM.next = Nil
286+
ScalaRunTime.releaseFence()
285287
initBaseClasses.head.newOverloaded(tpe, members)
286288
}
287289
}

src/reflect/scala/reflect/internal/util/Collections.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
package scala
77
package reflect.internal.util
88

9-
import scala.collection.{ mutable, immutable }
9+
import scala.collection.{immutable, mutable}
1010
import scala.annotation.tailrec
1111
import mutable.ListBuffer
12+
import scala.runtime.ScalaRunTime
1213

1314
/** Profiler driven changes.
1415
* TODO - inlining doesn't work from here because of the bug that
@@ -58,6 +59,7 @@ trait Collections {
5859
tail = next
5960
rest = rest.tail
6061
}
62+
ScalaRunTime.releaseFence()
6163
head
6264
}
6365

@@ -128,7 +130,9 @@ trait Collections {
128130
}
129131
}
130132
}
131-
loop(null, xs, xs, ys)
133+
val result = loop(null, xs, xs, ys)
134+
ScalaRunTime.releaseFence()
135+
result
132136
}
133137

134138
final def map3[A, B, C, D](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => D): List[D] = {

0 commit comments

Comments
 (0)