summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-01-15 21:07:15 +0300
committerEugene Burmako <xeno.by@gmail.com>2014-01-21 14:12:39 +0300
commit2bd304404ac00939a18a678aa982da9cbb3471a2 (patch)
tree3cbd2f12522953a0cd9945aca7fae02f44ec1b94 /src/reflect/scala/reflect/internal/pickling/UnPickler.scala
parentf142d854d3401728546ae6822662b7a3ad655a58 (diff)
downloadscala-2bd304404ac00939a18a678aa982da9cbb3471a2.tar.gz
scala-2bd304404ac00939a18a678aa982da9cbb3471a2.tar.bz2
scala-2bd304404ac00939a18a678aa982da9cbb3471a2.zip
SI-8131 fixes residual race condition in runtime reflection
Apparently some completers can call setInfo while they’re not yet done, which resets the LOCKED flag, and makes anything that uses LOCKED to track completion unreliable. Unfortunately, that’s exactly the mechanism that was used by runtime reflection to elide locking for symbols that are known to be initialized. This commit fixes the problematic lock elision strategy by introducing an explicit communication channel between SynchronizedSymbol’s and their completers. Now instead of trying hard to infer whether it’s already initialized or not, every symbol gets a volatile field that can be queried to provide necessary information.
Diffstat (limited to 'src/reflect/scala/reflect/internal/pickling/UnPickler.scala')
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala12
1 files changed, 9 insertions, 3 deletions
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 3d222fce10..2f3e726787 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -275,6 +275,7 @@ abstract class UnPickler {
def pflags = flags & PickledFlags
def finishSym(sym: Symbol): Symbol = {
+ markFlagsCompleted(sym)(mask = AllFlags)
sym.privateWithin = privateWithin
sym.info = (
if (atEnd) {
@@ -663,7 +664,7 @@ abstract class UnPickler {
private class LazyTypeRef(i: Int) extends LazyType with FlagAgnosticCompleter {
private val definedAtRunId = currentRunId
private val p = phase
- override def complete(sym: Symbol) : Unit = try {
+ protected def completeInternal(sym: Symbol) : Unit = try {
val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType`
if (p ne null)
slowButSafeEnteringPhase(p) (sym setInfo tp)
@@ -673,6 +674,10 @@ abstract class UnPickler {
catch {
case e: MissingRequirementError => throw toTypeError(e)
}
+ override def complete(sym: Symbol) : Unit = {
+ completeInternal(sym)
+ if (!isCompilerUniverse) markAllCompleted(sym)
+ }
override def load(sym: Symbol) { complete(sym) }
}
@@ -680,8 +685,9 @@ abstract class UnPickler {
* of completed symbol to symbol at index `j`.
*/
private class LazyTypeRefAndAlias(i: Int, j: Int) extends LazyTypeRef(i) {
- override def complete(sym: Symbol) = try {
- super.complete(sym)
+ override def completeInternal(sym: Symbol) = try {
+ super.completeInternal(sym)
+
var alias = at(j, readSymbol)
if (alias.isOverloaded)
alias = slowButSafeEnteringPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt))))