summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2013-02-02 00:27:38 +0100
committerEugene Burmako <xeno.by@gmail.com>2013-10-18 17:48:51 +0200
commitd05566ca327103d61b071a5022be98f1f3f045f3 (patch)
tree6023560ed3c69d52996bf16c652b3baf7247ed63 /src
parent484d6d70a4c51d0ddf220c67265182949e69ca45 (diff)
downloadscala-d05566ca327103d61b071a5022be98f1f3f045f3.tar.gz
scala-d05566ca327103d61b071a5022be98f1f3f045f3.tar.bz2
scala-d05566ca327103d61b071a5022be98f1f3f045f3.zip
optimizes Scala reflection GIL
First of all, GIL should only apply to runtime reflection, because noone is going to run toolboxes in multiple threads: a) that's impossible, b/c the compiler isn't thread safe, b) ToolBox api prevents that. Secondly, the only things in symbols which require synchronization are: 1) info/validTo (completers aren't thread-safe), 2) rawInfo and its dependencies (it shares a mutable field with info) 3) non-trivial caches like in typeAsMemberOfLock If you think about it, other things like sourceModule or associatedFile don't need synchronization, because they are either set up when a symbol is created or cloned or when it's completed. The former is obviously safe, while the latter is safe as well, because before acquiring init-dependent state of symbols, the compiler calls `initialize`, which is synchronized. We can say that symbols can be in four possible states: 1) being created, 2) created, but not yet initialized, 3) initializing, 4) initialized. Of those only #3 is dangerous and needs protection, which is what this commit does.
Diffstat (limited to 'src')
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala13
-rw-r--r--src/reflect/scala/reflect/runtime/Gil.scala13
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedOps.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala78
4 files changed, 41 insertions, 65 deletions
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index a7abe08c2e..a54a17901a 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -951,6 +951,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isInitialized: Boolean =
validTo != NoPeriod
+ /** Some completers call sym.setInfo when still in-flight and then proceed with initialization (e.g. see LazyPackageType)
+ * setInfo sets _validTo to current period, which means that after a call to setInfo isInitialized will start returning true.
+ * Unfortunately, this doesn't mean that info becomes ready to be used, because subsequent initialization might change the info.
+ * Therefore we need this method to distinguish between initialized and really initialized symbol states.
+ */
+ final def isFullyInitialized: Boolean = _validTo != NoPeriod && (flags & LOCKED) == 0
+
/** Can this symbol be loaded by a reflective mirror?
*
* Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs.
@@ -3129,8 +3136,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def thisType: Type = {
val period = thisTypePeriod
if (period != currentPeriod) {
- thisTypePeriod = currentPeriod
if (!isValid(period)) thisTypeCache = ThisType(this)
+ thisTypePeriod = currentPeriod
}
thisTypeCache
}
@@ -3218,9 +3225,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def typeOfThis = {
val period = typeOfThisPeriod
if (period != currentPeriod) {
- typeOfThisPeriod = currentPeriod
if (!isValid(period))
typeOfThisCache = singleType(owner.thisType, sourceModule)
+ typeOfThisPeriod = currentPeriod
}
typeOfThisCache
}
@@ -3231,9 +3238,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// Skip a package object class, because the members are also in
// the package and we wish to avoid spurious ambiguities as in pos/t3999.
if (!isPackageObjectClass) {
+ implicitMembersCacheValue = tp.implicitMembers
implicitMembersCacheKey1 = tp
implicitMembersCacheKey2 = tp.decls.elems
- implicitMembersCacheValue = tp.implicitMembers
}
}
implicitMembersCacheValue
diff --git a/src/reflect/scala/reflect/runtime/Gil.scala b/src/reflect/scala/reflect/runtime/Gil.scala
index 8a8bfebf8c..cf6f1431d7 100644
--- a/src/reflect/scala/reflect/runtime/Gil.scala
+++ b/src/reflect/scala/reflect/runtime/Gil.scala
@@ -12,11 +12,14 @@ private[reflect] trait Gil {
lazy val gil = new java.util.concurrent.locks.ReentrantLock
@inline final def gilSynchronized[T](body: => T): T = {
- try {
- gil.lock()
- body
- } finally {
- gil.unlock()
+ if (isCompilerUniverse) body
+ else {
+ try {
+ gil.lock()
+ body
+ } finally {
+ gil.unlock()
+ }
}
}
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
index 21df973297..c90901410a 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
@@ -44,7 +44,7 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
// we can keep this lock fine-grained, because methods of Scope don't do anything extraordinary, which makes deadlocks impossible
// fancy subclasses of internal.Scopes#Scope should do synchronization themselves (e.g. see PackageScope for an example)
private lazy val syncLock = new Object
- def syncLockSynchronized[T](body: => T): T = syncLock.synchronized { body }
+ def syncLockSynchronized[T](body: => T): T = if (isCompilerUniverse) body else syncLock.synchronized { body }
override def isEmpty: Boolean = syncLockSynchronized { super.isEmpty }
override def size: Int = syncLockSynchronized { super.size }
override def enter[T <: Symbol](sym: T): T = syncLockSynchronized { super.enter(sym) }
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
index a52921c5c6..7f08e8fbe2 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
@@ -29,27 +29,16 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
trait SynchronizedSymbol extends Symbol {
- override def rawflags = gilSynchronized { super.rawflags }
- override def rawflags_=(x: Long) = gilSynchronized { super.rawflags_=(x) }
-
- override def rawowner = gilSynchronized { super.rawowner }
- override def owner_=(owner: Symbol) = gilSynchronized { super.owner_=(owner) }
-
- override def validTo = gilSynchronized { super.validTo }
- override def validTo_=(x: Period) = gilSynchronized { super.validTo_=(x) }
-
- override def pos = gilSynchronized { super.pos }
- override def setPos(pos: Position): this.type = { gilSynchronized { super.setPos(pos) }; this }
-
- override def privateWithin = gilSynchronized { super.privateWithin }
- override def privateWithin_=(sym: Symbol) = gilSynchronized { super.privateWithin_=(sym) }
+ def gilSynchronizedIfNotInited[T](body: => T): T = {
+ if (isFullyInitialized) body
+ else gilSynchronized { body }
+ }
- override def info = gilSynchronized { super.info }
- override def info_=(info: Type) = gilSynchronized { super.info_=(info) }
- override def updateInfo(info: Type): Symbol = gilSynchronized { super.updateInfo(info) }
- override def rawInfo: Type = gilSynchronized { super.rawInfo }
+ override def validTo = gilSynchronizedIfNotInited { super.validTo }
+ override def info = gilSynchronizedIfNotInited { super.info }
+ override def rawInfo: Type = gilSynchronizedIfNotInited { super.rawInfo }
- override def typeParams: List[Symbol] = gilSynchronized {
+ override def typeParams: List[Symbol] = gilSynchronizedIfNotInited {
if (isCompilerUniverse) super.typeParams
else {
if (isMonomorphicType) Nil
@@ -65,7 +54,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
}
}
}
- override def unsafeTypeParams: List[Symbol] = gilSynchronized {
+ override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotInited {
if (isCompilerUniverse) super.unsafeTypeParams
else {
if (isMonomorphicType) Nil
@@ -73,14 +62,6 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
}
}
- override def reset(completer: Type): this.type = gilSynchronized { super.reset(completer) }
-
- override def infosString: String = gilSynchronized { super.infosString }
-
- override def annotations: List[AnnotationInfo] = gilSynchronized { super.annotations }
- override def setAnnotations(annots: List[AnnotationInfo]): this.type = { gilSynchronized { super.setAnnotations(annots) }; this }
-
-
// ------ creators -------------------------------------------------------------------
override protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol =
@@ -128,41 +109,26 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
// ------- subclasses ---------------------------------------------------------------------
- trait SynchronizedTermSymbol extends TermSymbol with SynchronizedSymbol {
- override def name_=(x: Name) = gilSynchronized { super.name_=(x) }
- override def rawname = gilSynchronized { super.rawname }
- override def referenced: Symbol = gilSynchronized { super.referenced }
- override def referenced_=(x: Symbol) = gilSynchronized { super.referenced_=(x) }
- }
+ trait SynchronizedTermSymbol extends SynchronizedSymbol
trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol {
- override def typeAsMemberOf(pre: Type): Type = gilSynchronized { super.typeAsMemberOf(pre) }
- override def paramss: List[List[Symbol]] = gilSynchronized { super.paramss }
- override def returnType: Type = gilSynchronized { super.returnType }
+ // we can keep this lock fine-grained, because it's just a cache over asSeenFrom, which makes deadlocks impossible
+ // unfortunately we cannot elide this lock, because the cache depends on `pre`
+ private lazy val typeAsMemberOfLock = new Object
+ override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotInited { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } }
}
+ trait SynchronizedModuleSymbol extends ModuleSymbol with SynchronizedTermSymbol
+
trait SynchronizedTypeSymbol extends TypeSymbol with SynchronizedSymbol {
- override def name_=(x: Name) = gilSynchronized { super.name_=(x) }
- override def rawname = gilSynchronized { super.rawname }
- override def typeConstructor: Type = gilSynchronized { super.typeConstructor }
- override def tpe_* : Type = gilSynchronized { super.tpe_* }
- override def tpeHK : Type = gilSynchronized { super.tpeHK }
+ // unlike with typeConstructor, a lock is necessary here, because tpe calculation relies on
+ // temporarily assigning NoType to tpeCache to detect cyclic reference errors
+ private lazy val tpeLock = new Object
+ override def tpe_* : Type = gilSynchronizedIfNotInited { tpeLock.synchronized { super.tpe_* } }
}
- trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol {
- override def associatedFile = gilSynchronized { super.associatedFile }
- override def associatedFile_=(f: AbstractFile) = gilSynchronized { super.associatedFile_=(f) }
- override def thisSym: Symbol = gilSynchronized { super.thisSym }
- override def thisType: Type = gilSynchronized { super.thisType }
- override def typeOfThis: Type = gilSynchronized { super.typeOfThis }
- override def typeOfThis_=(tp: Type) = gilSynchronized { super.typeOfThis_=(tp) }
- override def children = gilSynchronized { super.children }
- override def addChild(sym: Symbol) = gilSynchronized { super.addChild(sym) }
- }
+ trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol
- trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol {
- override def sourceModule = gilSynchronized { super.sourceModule }
- override def implicitMembers: Scope = gilSynchronized { super.implicitMembers }
- }
+ trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol
}