diff options
author | Paul Phillips <paulp@improving.org> | 2012-07-06 15:55:45 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-07-12 09:57:08 +0200 |
commit | e6ac99e6a9871cb6f6931890d65f17a3663c3a4e (patch) | |
tree | 58c22a66b70388e96a85be7adcab3ac0c4afce6e /src | |
parent | e90f79a446414541402cf55e9ac664106a5bc355 (diff) | |
download | scala-e6ac99e6a9871cb6f6931890d65f17a3663c3a4e.tar.gz scala-e6ac99e6a9871cb6f6931890d65f17a3663c3a4e.tar.bz2 scala-e6ac99e6a9871cb6f6931890d65f17a3663c3a4e.zip |
Further optimization of asSeenFrom.
After some more early exclusion of uninteresting arguments,
asSeenFrom is now over twice as fast. Compiling the collections,
three runs:
-- Without these two commits:
8108775ms, 8132052ms, 8257527ms in asSeenFrom
Wall clock: 0m54.202s, 0m54.877s, 0m55.925s
-- With these two commits:
3568719ms, 3542860ms, 3570892ms in asSeenFrom
Wall clock: 0m50.730s, 0m51.213s, 0m50.850s
(Rebase of https://github.com/scala/scala/pull/835)
Diffstat (limited to 'src')
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 49 |
1 files changed, 27 insertions, 22 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 246e32a147..f3dd1f03ad 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -693,28 +693,21 @@ trait Types extends api.Types { self: SymbolTable => * = Int */ def asSeenFrom(pre: Type, clazz: Symbol): Type = { - if (isTrivial || phase.erasedTypes && pre.typeSymbol != ArrayClass) this - else { - // scala.tools.nsc.util.trace.when(pre.isInstanceOf[ExistentialType])("X "+this+".asSeenfrom("+pre+","+clazz+" = ") - Statistics.incCounter(asSeenFromCount) - val start = Statistics.pushTimer(typeOpsStack, asSeenFromNanos) - val pre1 = pre.normalize - - val result: Type = ( - if (pre1.isTrivial && (clazz.isPackageClass || !clazz.isClass)) this - else { - val m = new AsSeenFromMap(pre1, clazz) - val tp = m apply this - val tp1 = existentialAbstraction(m.capturedParams, tp) - if (m.capturedSkolems.isEmpty) tp1 - else deriveType(m.capturedSkolems, _.cloneSymbol setFlag CAPTURED)(tp1) - } + TypesStats.timedTypeOp(asSeenFromNanos) { + val trivial = ( + this.isTrivial + || phase.erasedTypes && pre.typeSymbol != ArrayClass + || pre.normalize.isTrivial && !isPossiblePrefix(clazz) ) - Statistics.popTimer(typeOpsStack, start) - if ((result ne this) && pre1.isTrivial) - debuglog(s"asSeenFrom($pre1, $clazz)\n old: ${this}\n new: $result") + if (trivial) this + else { + val m = new AsSeenFromMap(pre.normalize, clazz) + val tp = m(this) + val tp1 = existentialAbstraction(m.capturedParams, tp) - result + if (m.capturedSkolems.isEmpty) tp1 + else deriveType(m.capturedSkolems, _.cloneSymbol setFlag CAPTURED)(tp1) + } } } @@ -4265,15 +4258,21 @@ trait Types extends api.Types { self: SymbolTable => def singletonBounds(hi: Type) = TypeBounds.upper(intersectionType(List(hi, SingletonClass.tpe))) + /** Might the given symbol be important when calculating the prefix + * of a type? When tp.asSeenFrom(pre, clazz) is called on `tp`, + * the result will be `tp` unchanged if `pre` is trivial and `clazz` + * is a symbol such that isPossiblePrefix(clazz) == false. + */ + def isPossiblePrefix(clazz: Symbol) = clazz.isClass && !clazz.isPackageClass + /** A map to compute the asSeenFrom method */ class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap with KeepOnlyTypeConstraints { var capturedSkolems: List[Symbol] = List() var capturedParams: List[Symbol] = List() @inline private def skipPrefixOf(pre: Type, clazz: Symbol) = ( - (pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass + (pre eq NoType) || (pre eq NoPrefix) || !isPossiblePrefix(clazz) ) - override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { object annotationArgRewriter extends TypeMapTransformer { private def canRewriteThis(sym: Symbol) = ( @@ -6922,4 +6921,10 @@ object TypesStats { val typerefBaseTypeSeqCount = Statistics.newSubCounter(" of which for typerefs", baseTypeSeqCount) val singletonBaseTypeSeqCount = Statistics.newSubCounter(" of which for singletons", baseTypeSeqCount) val typeOpsStack = Statistics.newTimerStack() + + @inline final def timedTypeOp[T](c: Statistics.StackableTimer)(op: => T): T = { + val start = Statistics.pushTimer(typeOpsStack, c) + try op + finally Statistics.popTimer(typeOpsStack, start) + } } |