diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2013-02-02 00:27:38 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2013-10-18 17:48:51 +0200 |
commit | d05566ca327103d61b071a5022be98f1f3f045f3 (patch) | |
tree | 6023560ed3c69d52996bf16c652b3baf7247ed63 /src/reflect/scala/reflect/internal/Symbols.scala | |
parent | 484d6d70a4c51d0ddf220c67265182949e69ca45 (diff) | |
download | scala-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/reflect/scala/reflect/internal/Symbols.scala')
-rw-r--r-- | src/reflect/scala/reflect/internal/Symbols.scala | 13 |
1 files changed, 10 insertions, 3 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 |