summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-01-01 07:51:33 +0000
committerPaul Phillips <paulp@improving.org>2011-01-01 07:51:33 +0000
commit15cb1c75355f0d38da5281d165edfb2fd1a3b049 (patch)
treee412682fc3ba04a160ec25e530314964d6ce7ae8
parent79ca8d4cd2759a99e902c126c93ad37eb16adf91 (diff)
downloadscala-15cb1c75355f0d38da5281d165edfb2fd1a3b049.tar.gz
scala-15cb1c75355f0d38da5281d165edfb2fd1a3b049.tar.bz2
scala-15cb1c75355f0d38da5281d165edfb2fd1a3b049.zip
Generalized a pile of duplicated type caching c...
Generalized a pile of duplicated type caching code, but it's still largely undeployed because I haven't figured out how to make it as fast as the copy-pasted version, which bugs me like you wouldn't believe. Cannot deal with making "Sophie's Choice" between performance and lack of duplication. I left one deployment in because it fixed a bug, or at least so I see it: can't see why one would want the two absent error messages in t2641.check. Review by odersky.
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Caches.scala103
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala11
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala39
-rw-r--r--test/files/neg/t2641.check12
5 files changed, 117 insertions, 49 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Caches.scala b/src/compiler/scala/tools/nsc/symtab/Caches.scala
new file mode 100644
index 0000000000..f47da9c84c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/Caches.scala
@@ -0,0 +1,103 @@
+/* NSC -- new scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package symtab
+
+import scala.collection.{ mutable, immutable }
+
+/** A cache for some entity whose validity depends on a monotonically
+ * increasing sequence number.
+ */
+abstract class SequencedCache[T >: Null] {
+ def zero: Int
+ def sequenceId: Int
+ def calculate(): T
+
+ /** If sequence numbers differ, this condition is consulted before
+ * updating the cached value.
+ */
+ def isCacheValid: Boolean
+
+ /** Public so accesses can be inlined. */
+ @inline var cachedId: Int = 0
+ @inline var cachedValue: T = _
+
+ /** Puts cache back in uninitialized state. */
+ @inline final def clear() = {
+ cachedId = zero
+ cachedValue = null
+ }
+ /** Resets the sequence id without touching the cached value. */
+ @inline final def reset() = {
+ cachedId = zero
+ }
+
+ final def get(): T = {
+ if (cachedValue == null) {
+ cachedValue = calculate()
+ cachedId = sequenceId
+ }
+ else if (cachedId != sequenceId) {
+ if (!isCacheValid)
+ cachedValue = calculate()
+
+ cachedId = sequenceId
+ }
+ cachedValue
+ }
+}
+
+trait Caches {
+ self: SymbolTable =>
+
+ final def isValid(period: Period): Boolean =
+ period != 0 && runId(period) == currentRunId && {
+ val pid = phaseId(period)
+ if (phase.id > pid) infoTransformers.nextFrom(pid).pid >= phase.id
+ else infoTransformers.nextFrom(phase.id).pid >= pid
+ }
+
+ final def isValidForBaseClasses(period: Period): Boolean = {
+ def noChangeInBaseClasses(it: InfoTransformer, limit: Phase#Id): Boolean = (
+ it.pid >= limit ||
+ !it.changesBaseClasses && noChangeInBaseClasses(it.next, limit)
+ );
+ period != 0 && runId(period) == currentRunId && {
+ val pid = phaseId(period)
+ if (phase.id > pid) noChangeInBaseClasses(infoTransformers.nextFrom(pid), phase.id)
+ else noChangeInBaseClasses(infoTransformers.nextFrom(phase.id), pid)
+ }
+ }
+
+ abstract class PeriodCache[T >: Null] extends SequencedCache[T] {
+ final val zero = NoPeriod
+ @inline final def sequenceId = currentPeriod
+ }
+
+ abstract class ListOfTypesCache extends PeriodCache[List[Type]] {
+ @inline final def isCacheValid = isValidForBaseClasses(cachedId)
+ }
+ abstract class ListOfSymbolsCache extends PeriodCache[List[Symbol]] {
+ @inline final def isCacheValid = isValidForBaseClasses(cachedId)
+ }
+ abstract class BaseTypeSeqCache extends PeriodCache[BaseTypeSeq] {
+ @inline final def isCacheValid = isValidForBaseClasses(cachedId)
+ }
+ abstract class TypeCache extends PeriodCache[Type] {
+ @inline final def isCacheValid = isValid(cachedId)
+ }
+ abstract class TypeCacheForRunId extends SequencedCache[Type] {
+ final val zero = NoRunId
+ @inline final def sequenceId = currentRunId
+ @inline final override def isCacheValid = false
+ }
+ object TypeCache {
+ def apply(body: => Type): TypeCache = new TypeCache {
+ @inline final def calculate() = body
+ }
+ }
+}
+
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
index 03166de05d..97b7ce03bf 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -15,6 +15,7 @@ abstract class SymbolTable extends reflect.generic.Universe
with Symbols
with Types
with Scopes
+ with Caches
with Definitions
with reflect.generic.Constants
with BaseTypeSeqs
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index feccb4e462..43dc2b768b 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -1801,6 +1801,11 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
override def isAbstractType = isDeferred
override def isAliasType = !isDeferred
+ private def newTypeRef(targs: List[Type]) = {
+ val pre = if (hasFlag(PARAM | EXISTENTIAL)) NoPrefix else owner.thisType
+ typeRef(pre, this, targs)
+ }
+
/** Let's say you have a type definition
*
* type T <: Number
@@ -1823,8 +1828,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
else unsafeTypeParams map (_.typeConstructor) //@M! use typeConstructor to generate dummy type arguments,
// sym.tpe should not be called on a symbol that's supposed to be a higher-kinded type
// memberType should be used instead, that's why it uses tpeHK and not tpe
- tpeCache = typeRef(if (hasFlag(PARAM | EXISTENTIAL)) NoPrefix else owner.thisType,
- this, targs)
+ tpeCache = newTypeRef(targs)
}
}
assert(tpeCache ne null/*, "" + this + " " + phase*/)//debug
@@ -1836,8 +1840,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
override def typeConstructor: Type = {
if ((tyconCache eq null) || tyconRunId != currentRunId) {
- tyconCache = typeRef(if (hasFlag(PARAM | EXISTENTIAL)) NoPrefix else owner.thisType,
- this, List())
+ tyconCache = newTypeRef(Nil)
tyconRunId = currentRunId
}
assert(tyconCache ne null)
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 28e666755e..508274f73f 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1648,8 +1648,10 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
// assert(!(sym hasFlag (PARAM | EXISTENTIAL)) || pre == NoPrefix, this)
// assert(args.isEmpty || !sym.info.typeParams.isEmpty, this)
// assert(args.isEmpty || ((sym ne AnyClass) && (sym ne NothingClass))
- private var parentsCache: List[Type] = _
- private var parentsPeriod = NoPeriod
+
+ private val parentsCache = new ListOfTypesCache {
+ @inline final def calculate() = thisInfo.parents map transform
+ }
private var baseTypeSeqCache: BaseTypeSeq = _
private var baseTypeSeqPeriod = NoPeriod
@@ -1729,19 +1731,7 @@ A type's typeSymbol should never be inspected directly.
if (sym.isAbstractType) thisInfo.bounds // transform(thisInfo.bounds).asInstanceOf[TypeBounds] // ??? seems to be doing asSeenFrom twice
else super.bounds
- override def parents: List[Type] = {
- val period = parentsPeriod
- if (period != currentPeriod) {
- parentsPeriod = currentPeriod
- if (!isValidForBaseClasses(period)) {
- parentsCache = thisInfo.parents map transform
- } else if (parentsCache == null) { // seems this can happen if things are currupted enough, see #2641
- parentsCache = List(AnyClass.tpe)
- }
- }
- parentsCache
- }
-
+ override def parents: List[Type] = parentsCache.get()
override def typeOfThis = transform(sym.typeOfThis)
/*
@@ -3912,25 +3902,6 @@ A type's typeSymbol should never be inspected directly.
d + LubGlbMargin
}
- final def isValid(period: Period): Boolean =
- period != 0 && runId(period) == currentRunId && {
- val pid = phaseId(period)
- if (phase.id > pid) infoTransformers.nextFrom(pid).pid >= phase.id
- else infoTransformers.nextFrom(phase.id).pid >= pid
- }
-
- final def isValidForBaseClasses(period: Period): Boolean = {
- def noChangeInBaseClasses(it: InfoTransformer, limit: Phase#Id): Boolean = (
- it.pid >= limit ||
- !it.changesBaseClasses && noChangeInBaseClasses(it.next, limit)
- );
- period != 0 && runId(period) == currentRunId && {
- val pid = phaseId(period)
- if (phase.id > pid) noChangeInBaseClasses(infoTransformers.nextFrom(pid), phase.id)
- else noChangeInBaseClasses(infoTransformers.nextFrom(phase.id), pid)
- }
- }
-
/** Is intersection of given types populated? That is,
* for all types tp1, tp2 in intersection
* for all common base classes bc of tp1 and tp2
diff --git a/test/files/neg/t2641.check b/test/files/neg/t2641.check
index 771624e8d9..f19a901859 100644
--- a/test/files/neg/t2641.check
+++ b/test/files/neg/t2641.check
@@ -19,17 +19,7 @@ t2641.scala:25: error: something is wrong (wrong class file?): trait ManagedSeq
t2641.scala:27: error: something is wrong (wrong class file?): trait ManagedSeq with type parameters [A,Coll] gets applied to arguments [], phase = namer
trait Sliced extends Transformed[A] with super.Sliced {
^
-t2641.scala:27: error: illegal inheritance; superclass Any
- is not a subclass of the superclass ManagedSeqStrict
- of the mixin trait Transformed
- trait Sliced extends Transformed[A] with super.Sliced {
- ^
-t2641.scala:27: error: illegal inheritance; superclass Any
- is not a subclass of the superclass Object
- of the mixin trait Sliced
- trait Sliced extends Transformed[A] with super.Sliced {
- ^
t2641.scala:28: error: value managedIterator is not a member of ManagedSeq
override def managedIterator = self.managedIterator slice (from, until)
^
-9 errors found
+7 errors found