summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-08-16 20:03:14 +0200
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-08-20 08:11:06 +0100
commit1ee7ffb6fd2de6e7194a4eb89601d98503b50048 (patch)
treea7395953072397beb1435c4907cf4e23cbb4e469 /src
parent0cde930b192acc73d1e0b5951b3300c286ae4dd2 (diff)
downloadscala-1ee7ffb6fd2de6e7194a4eb89601d98503b50048.tar.gz
scala-1ee7ffb6fd2de6e7194a4eb89601d98503b50048.tar.bz2
scala-1ee7ffb6fd2de6e7194a4eb89601d98503b50048.zip
Optimizations to cut down on #closures created
Driven by profile data.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala8
-rwxr-xr-xsrc/library/scala/collection/LinearSeqOptimized.scala59
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala23
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala14
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala25
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala15
-rw-r--r--src/reflect/scala/tools/nsc/io/ZipArchive.scala27
9 files changed, 144 insertions, 31 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 3cb33ec1f8..d97fbf5daa 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -488,7 +488,7 @@ abstract class Erasure extends AddInterfaces
private def isPrimitiveValueMember(sym: Symbol) =
sym != NoSymbol && isPrimitiveValueClass(sym.owner)
- private def box(tree: Tree, target: => String): Tree = {
+ @inline private def box(tree: Tree, target: => String): Tree = {
val result = box1(tree)
log("boxing "+tree+":"+tree.tpe+" to "+target+" = "+result+":"+result.tpe)
result
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index fc0f9370b4..1870e1511e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -661,7 +661,13 @@ trait Infer {
val restp1 = followApply(restp)
if (restp1 eq restp) tp else restp1
case _ =>
- val appmeth = tp.nonPrivateMember(nme.apply) filter (_.isPublic)
+ val appmeth = {
+ //OPT cut down on #closures by special casing non-overloaded case
+ // was: tp.nonPrivateMember(nme.apply) filter (_.isPublic)
+ val result = tp.nonPrivateMember(nme.apply)
+ if ((result eq NoSymbol) || !result.isOverloaded && result.isPublic) result
+ else result filter (_.isPublic)
+ }
if (appmeth == NoSymbol) tp
else OverloadedType(tp, appmeth.alternatives)
}
diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala
index 5e0bd010a6..2a06b9d0bd 100755
--- a/src/library/scala/collection/LinearSeqOptimized.scala
+++ b/src/library/scala/collection/LinearSeqOptimized.scala
@@ -93,6 +93,16 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea
cnt
}
+ override /*SeqLike*/
+ def contains(elem: Any): Boolean = {
+ var these = this
+ while (!these.isEmpty) {
+ if (these.head == elem) return true
+ these = these.tail
+ }
+ false
+ }
+
override /*IterableLike*/
def find(p: A => Boolean): Option[A] = {
var these = this
@@ -113,7 +123,54 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea
}
acc
}
-
+
+ override /*TraversableLike*/
+ def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ b.sizeHint(this)
+ var these = this
+ while (!these.isEmpty) {
+ b += f(these.head)
+ these = these.tail
+ }
+ b.result
+ }
+
+ override /*TraversableLike*/
+ def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val b = bf(repr)
+ var these = this
+ while (!these.isEmpty) {
+ b ++= f(these.head).seq
+ these = these.tail
+ }
+ b.result
+ }
+
+ override /*TraversableLike*/
+ def filter(p: A => Boolean): Repr = {
+ val b = newBuilder
+ var these = this
+ while (!these.isEmpty) {
+ val x = these.head
+ if (p(x)) b += x
+ these = these.tail
+ }
+ b.result
+ }
+
+ override /*TraversableLike*/
+ def filterNot(p: A => Boolean): Repr = {
+ val b = newBuilder
+ var these = this
+ while (!these.isEmpty) {
+ val x = these.head
+ if (!p(x)) b += x
+ these = these.tail
+ }
+ b.result
+ }
+
override /*IterableLike*/
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 229570dafd..a444c786f7 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -8,6 +8,7 @@ package internal
import util._
import pickling.ByteCodecs
+import scala.annotation.tailrec
/** AnnotationInfo and its helpers */
trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
@@ -31,11 +32,27 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
case AnnotationInfo(tp, Literal(Constant(tpe: Type)) :: Nil, _) if tp.typeSymbol == ThrowsClass => tpe.typeSymbol
}
- /** Test for, get, or remove an annotation */
- def hasAnnotation(cls: Symbol) = annotations exists (_ matches cls)
- def getAnnotation(cls: Symbol) = annotations find (_ matches cls)
+ /** Tests for, get, or remove an annotation */
+ def hasAnnotation(cls: Symbol): Boolean =
+ //OPT inlined from exists to save on #closures; was: annotations exists (_ matches cls)
+ dropOtherAnnotations(annotations, cls).nonEmpty
+
+ def getAnnotation(cls: Symbol): Option[AnnotationInfo] =
+ //OPT inlined from exists to save on #closures; was: annotations find (_ matches cls)
+ dropOtherAnnotations(annotations, cls) match {
+ case ann :: _ => Some(ann)
+ case _ => None
+ }
+
def removeAnnotation(cls: Symbol): Self = filterAnnotations(ann => !(ann matches cls))
+
final def withAnnotation(annot: AnnotationInfo): Self = withAnnotations(List(annot))
+
+ @tailrec private
+ def dropOtherAnnotations(anns: List[AnnotationInfo], cls: Symbol): List[AnnotationInfo] = anns match {
+ case ann :: rest => if (ann matches cls) anns else dropOtherAnnotations(rest, cls)
+ case Nil => Nil
+ }
}
/** Arguments to classfile annotations (which are written to
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 15ca276b1a..f9e4005d16 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -1897,10 +1897,16 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* @param ofclazz The class containing the symbol's definition
* @param site The base type from which member types are computed
*/
- final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol =
- ofclazz.info.nonPrivateDecl(name).filter(sym =>
- !sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
-
+ final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol = {
+ //OPT cut down on #closures by special casing non-overloaded case
+ // was: ofclazz.info.nonPrivateDecl(name) filter (sym =>
+ // !sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
+ val result = ofclazz.info.nonPrivateDecl(name)
+ def qualifies(sym: Symbol) = !sym.isTerm || (site.memberType(this) matches site.memberType(sym))
+ if ((result eq NoSymbol) || !result.isOverloaded && qualifies(result)) result
+ else result filter qualifies
+ }
+
/** The non-private member of `site` whose type and name match the type of this symbol. */
final def matchingSymbol(site: Type, admit: Long = 0L): Symbol =
site.nonPrivateMemberAdmitting(name, admit).filter(sym =>
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 8baed325fd..8f4c0de001 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -29,7 +29,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def setType(tp: Type): this.type = { rawtpe = tp; this }
def defineType(tp: Type): this.type = setType(tp)
- def symbol: Symbol = null
+ def symbol: Symbol = null //!!!OPT!!! symbol is about 3% of hot compile times -- megamorphic dispatch?
def symbol_=(sym: Symbol) { throw new UnsupportedOperationException("symbol_= inapplicable for " + this) }
def setSymbol(sym: Symbol): this.type = { symbol = sym; this }
def hasSymbol = false
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 5697df4924..da92d5eb09 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -3991,15 +3991,18 @@ trait Types extends api.Types { self: SymbolTable =>
override def variance = _variance
def variance_=(x: Int) = _variance = x
- override protected def noChangeToSymbols(origSyms: List[Symbol]) = {
- origSyms forall { sym =>
- val v = variance
- if (sym.isAliasType) variance = 0
- val result = this(sym.info)
- variance = v
- result eq sym.info
+ override protected def noChangeToSymbols(origSyms: List[Symbol]) =
+ //OPT inline from forall to save on #closures
+ origSyms match {
+ case sym :: rest =>
+ val v = variance
+ if (sym.isAliasType) variance = 0
+ val result = this(sym.info)
+ variance = v
+ (result eq sym.info) && noChangeToSymbols(rest)
+ case _ =>
+ true
}
- }
override protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] =
map2Conserve(args, tparams) { (arg, tparam) =>
@@ -5131,14 +5134,14 @@ trait Types extends api.Types { self: SymbolTable =>
1
}
- private def maxDepth(tps: Seq[Type], by: Type => Int): Int = {
+ private def maxDepth(tps: List[Type], by: Type => Int): Int = {
var d = 0
for (tp <- tps) d = d max by(tp) //!!!OPT!!!
d
}
- private def typeDepth(tps: Seq[Type]): Int = maxDepth(tps, typeDepth)
- private def baseTypeSeqDepth(tps: Seq[Type]): Int = maxDepth(tps, _.baseTypeSeqDepth)
+ private def typeDepth(tps: List[Type]): Int = maxDepth(tps, typeDepth)
+ private def baseTypeSeqDepth(tps: List[Type]): Int = maxDepth(tps, _.baseTypeSeqDepth)
/** Is intersection of given types populated? That is,
* for all types tp1, tp2 in intersection
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index dd515b2201..38f61d3e93 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -769,8 +769,21 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
}
/* Read a reference to a pickled item */
+ protected def readSymbolRef(): Symbol = {//OPT inlined from: at(readNat(), readSymbol) to save on closure creation
+ val i = readNat()
+ var r = entries(i)
+ if (r eq null) {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ r = readSymbol()
+ assert(entries(i) eq null, entries(i))
+ entries(i) = r
+ readIndex = savedIndex
+ }
+ r.asInstanceOf[Symbol]
+ }
+
protected def readNameRef(): Name = at(readNat(), readName)
- protected def readSymbolRef(): Symbol = at(readNat(), readSymbol)
protected def readTypeRef(): Type = at(readNat(), () => readType()) // after the NMT_TRANSITION period, we can leave off the () => ... ()
protected def readConstantRef(): Constant = at(readNat(), readConstant)
protected def readAnnotationRef(): AnnotationInfo = at(readNat(), readAnnotation)
diff --git a/src/reflect/scala/tools/nsc/io/ZipArchive.scala b/src/reflect/scala/tools/nsc/io/ZipArchive.scala
index 852dba9ec8..d1a91294a5 100644
--- a/src/reflect/scala/tools/nsc/io/ZipArchive.scala
+++ b/src/reflect/scala/tools/nsc/io/ZipArchive.scala
@@ -96,14 +96,25 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq
}
}
- private def ensureDir(dirs: mutable.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry = {
- dirs.getOrElseUpdate(path, {
- val parent = ensureDir(dirs, dirName(path), null)
- val dir = new DirEntry(path)
- parent.entries(baseName(path)) = dir
- dir
- })
- }
+ private def ensureDir(dirs: mutable.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry =
+ //OPT inlined from getOrElseUpdate; saves ~50K closures on test run.
+ // was:
+ // dirs.getOrElseUpdate(path, {
+ // val parent = ensureDir(dirs, dirName(path), null)
+ // val dir = new DirEntry(path)
+ // parent.entries(baseName(path)) = dir
+ // dir
+ // })
+ dirs get path match {
+ case Some(v) => v
+ case None =>
+ val parent = ensureDir(dirs, dirName(path), null)
+ val dir = new DirEntry(path)
+ parent.entries(baseName(path)) = dir
+ dirs(path) = dir
+ dir
+ }
+
protected def getDir(dirs: mutable.Map[String, DirEntry], entry: ZipEntry): DirEntry = {
if (entry.isDirectory) ensureDir(dirs, entry.getName, entry)
else ensureDir(dirs, dirName(entry.getName), null)