summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2014-02-01 09:16:51 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2014-02-01 09:16:51 -0800
commit1e82fd85ec7b72eb38a5fd143b47ee2327b40c96 (patch)
treee885ef6824b06781878cf4b80516220725f57a16 /src
parent1a3de955b824aa4d946467c5b207133b6839b17d (diff)
parent8ef0c6cde0625efb2d956bde276eeeedd9dec6e7 (diff)
downloadscala-1e82fd85ec7b72eb38a5fd143b47ee2327b40c96.tar.gz
scala-1e82fd85ec7b72eb38a5fd143b47ee2327b40c96.tar.bz2
scala-1e82fd85ec7b72eb38a5fd143b47ee2327b40c96.zip
Merge pull request #3444 from retronym/topic/opt6
Avoid generic collections operations hot paths
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala8
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala8
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala21
-rw-r--r--src/reflect/scala/reflect/internal/util/Collections.scala34
8 files changed, 57 insertions, 26 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 42c929baed..c59b726076 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -439,10 +439,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
else
specializedTypeVars(sym.typeParams zip args collect { case (tp, arg) if tp.isSpecialized => arg })
- case PolyType(tparams, resTpe) => specializedTypeVars(resTpe :: tparams.map(_.info))
+ case PolyType(tparams, resTpe) => specializedTypeVars(resTpe :: mapList(tparams)(symInfo)) // OPT
// since this method may be run at phase typer (before uncurry, where NMTs are eliminated)
case NullaryMethodType(resTpe) => specializedTypeVars(resTpe)
- case MethodType(argSyms, resTpe) => specializedTypeVars(resTpe :: argSyms.map(_.tpe))
+ case MethodType(argSyms, resTpe) => specializedTypeVars(resTpe :: mapList(argSyms)(symTpe)) // OPT
case ExistentialType(_, res) => specializedTypeVars(res)
case AnnotatedType(_, tp) => specializedTypeVars(tp)
case TypeBounds(lo, hi) => specializedTypeVars(lo :: hi :: Nil)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 598b12b00d..e5907e1a0f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -1303,7 +1303,7 @@ trait Contexts { self: Analyzer =>
var renamed = false
var selectors = tree.selectors
def current = selectors.head
- while (selectors.nonEmpty && result == NoSymbol) {
+ while ((selectors ne Nil) && result == NoSymbol) {
if (current.rename == name.toTermName)
result = qual.tpe.nonLocalMember( // new to address #2733: consider only non-local members for imports
if (name.isTypeName) current.name.toTypeName else current.name)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 9776b1e80e..b44375e8c4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3411,7 +3411,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case:
// val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo)
// precise(foo) : foo.type => foo.type
- val restpe = mt.resultType(args1 map (arg => gen stableTypeFor arg orElse arg.tpe))
+ val restpe = mt.resultType(mapList(args1)(arg => gen stableTypeFor arg orElse arg.tpe))
def ifPatternSkipFormals(tp: Type) = tp match {
case MethodType(_, rtp) if (mode.inPatternMode) => rtp
case _ => tp
@@ -3831,7 +3831,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// lifted out of typed1 because it's needed in typedImplicit0
protected def typedTypeApply(tree: Tree, mode: Mode, fun: Tree, args: List[Tree]): Tree = fun.tpe match {
case OverloadedType(pre, alts) =>
- inferPolyAlternatives(fun, args map (_.tpe))
+ inferPolyAlternatives(fun, mapList(args)(treeTpe))
val tparams = fun.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree)
val args1 = if (sameLength(args, tparams)) {
//@M: in case TypeApply we can't check the kind-arities of the type arguments,
@@ -3851,7 +3851,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
typedTypeApply(tree, mode, fun setType fun.tpe.widen, args)
case PolyType(tparams, restpe) if tparams.nonEmpty =>
if (sameLength(tparams, args)) {
- val targs = args map (_.tpe)
+ val targs = mapList(args)(treeTpe)
checkBounds(tree, NoPrefix, NoSymbol, tparams, targs, "")
if (isPredefClassOf(fun.symbol))
typedClassOf(tree, args.head, noGen = true)
@@ -4871,7 +4871,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
typedHigherKindedType(arg, mode, pt)
}
- val argtypes = args1 map (_.tpe)
+ val argtypes = mapList(args1)(treeTpe)
foreach2(args, tparams) { (arg, tparam) =>
// note: can't use args1 in selector, because Binds got replaced
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 4fde57ed02..d634034fe9 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -48,7 +48,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
/** 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
+ dropOtherAnnotations(annotations, cls) ne Nil
def getAnnotation(cls: Symbol): Option[AnnotationInfo] =
//OPT inlined from exists to save on #closures; was: annotations find (_ matches cls)
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index f49ddaf6ca..26914fecc1 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -3404,8 +3404,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* @return the new list of info-adjusted symbols
*/
def deriveSymbols(syms: List[Symbol], symFn: Symbol => Symbol): List[Symbol] = {
- val syms1 = syms map symFn
- syms1 map (_ substInfo (syms, syms1))
+ val syms1 = mapList(syms)(symFn)
+ mapList(syms1)(_ substInfo (syms, syms1))
}
/** Derives a new Type by first deriving new symbols as in deriveSymbols,
@@ -3445,9 +3445,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* @return the newly created, info-adjusted symbols
*/
def cloneSymbolsAndModify(syms: List[Symbol], infoFn: Type => Type): List[Symbol] =
- cloneSymbols(syms) map (_ modifyInfo infoFn)
+ mapList(cloneSymbols(syms))(_ modifyInfo infoFn)
def cloneSymbolsAtOwnerAndModify(syms: List[Symbol], owner: Symbol, infoFn: Type => Type): List[Symbol] =
- cloneSymbolsAtOwner(syms, owner) map (_ modifyInfo infoFn)
+ mapList(cloneSymbolsAtOwner(syms, owner))(_ modifyInfo infoFn)
/** Functions which perform the standard clone/substituting on the given symbols and type,
* then call the creator function with the new symbols and type as arguments.
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index e602a12175..145b4a3f1f 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -49,10 +49,10 @@ abstract class TreeGen extends macros.TreeBuilder {
mkMethodCall(Select(receiver, method), targs, args)
def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree =
- Apply(mkTypeApply(target, targs map TypeTree), args)
+ Apply(mkTypeApply(target, mapList(targs)(TypeTree)), args)
def mkNullaryCall(method: Symbol, targs: List[Type]): Tree =
- mkTypeApply(mkAttributedRef(method), targs map TypeTree)
+ mkTypeApply(mkAttributedRef(method), mapList(targs)(TypeTree))
/** Builds a reference to value whose type is given stable prefix.
* The type must be suitable for this. For example, it
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 9ddaea4c62..2acf901d0e 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -1977,7 +1977,7 @@ trait Types
def pendingVolatiles = _pendingVolatiles
class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) {
- require(args0.nonEmpty, this)
+ require(args0 ne Nil, this)
/** No unapplied type params size it has (should have) equally as many args. */
override def isHigherKinded = false
@@ -2035,7 +2035,7 @@ trait Types
// to a java or scala symbol, but it does matter whether it occurs in java or scala code.
// TypeRefs w/o type params that occur in java signatures/code are considered raw types, and are
// represented as existential types.
- override def isHigherKinded = typeParams.nonEmpty
+ override def isHigherKinded = (typeParams ne Nil)
override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams
private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym)
@@ -2221,7 +2221,7 @@ trait Types
//OPT specialize hashCode
override final def computeHashCode = {
import scala.util.hashing.MurmurHash3._
- val hasArgs = args.nonEmpty
+ val hasArgs = args ne Nil
var h = productSeed
h = mix(h, pre.hashCode)
h = mix(h, sym.hashCode)
@@ -2412,7 +2412,7 @@ trait Types
object TypeRef extends TypeRefExtractor {
def apply(pre: Type, sym: Symbol, args: List[Type]): Type = unique({
- if (args.nonEmpty) {
+ if (args ne Nil) {
if (sym.isAliasType) new AliasArgsTypeRef(pre, sym, args)
else if (sym.isAbstractType) new AbstractArgsTypeRef(pre, sym, args)
else new ClassArgsTypeRef(pre, sym, args)
@@ -2485,7 +2485,7 @@ trait Types
true
}
- def isImplicit = params.nonEmpty && params.head.isImplicit
+ def isImplicit = (params ne Nil) && params.head.isImplicit
def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized?
//assert(paramTypes forall (pt => !pt.typeSymbol.isImplClass))//DEBUG
@@ -2493,7 +2493,7 @@ trait Types
override def paramss: List[List[Symbol]] = params :: resultType.paramss
- override def paramTypes = params map (_.tpe)
+ override def paramTypes = mapList(params)(symTpe) // OPT use mapList rather than .map
override def boundSyms = resultType.boundSyms ++ params
@@ -4120,7 +4120,7 @@ trait Types
&& (variance.isCovariant || isSubType(t2, t1, depth))
)
- corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg)
+ corresponds3(tps1, tps2, mapList(tparams)(_.variance))(isSubArg)
}
def specializesSym(tp: Type, sym: Symbol, depth: Depth): Boolean = {
@@ -4304,7 +4304,7 @@ trait Types
}
def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] =
- tparams map (_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds)
+ mapList(tparams)(_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds)
def elimAnonymousClass(t: Type) = t match {
case TypeRef(pre, clazz, Nil) if clazz.isAnonymousClass =>
@@ -4553,7 +4553,10 @@ trait Types
private[scala] val typeIsExistentiallyBound = (tp: Type) => tp.typeSymbol.isExistentiallyBound
private[scala] val typeIsErroneous = (tp: Type) => tp.isErroneous
private[scala] val symTypeIsError = (sym: Symbol) => sym.tpe.isError
- private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations.nonEmpty
+ private[scala] val treeTpe = (t: Tree) => t.tpe
+ private[scala] val symTpe = (sym: Symbol) => sym.tpe
+ private[scala] val symInfo = (sym: Symbol) => sym.info
+ private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations ne Nil
private[scala] val boundsContainType = (bounds: TypeBounds, tp: Type) => bounds containsType tp
private[scala] val typeListIsEmpty = (ts: List[Type]) => ts.isEmpty
private[scala] val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableTpe
diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala
index 7cc2952c96..d128521be8 100644
--- a/src/reflect/scala/reflect/internal/util/Collections.scala
+++ b/src/reflect/scala/reflect/internal/util/Collections.scala
@@ -47,6 +47,30 @@ trait Collections {
final def mforeach[A](xss: List[List[A]])(f: A => Unit) = xss foreach (_ foreach f)
final def mforeach[A](xss: Traversable[Traversable[A]])(f: A => Unit) = xss foreach (_ foreach f)
+ /** A version of List#map, specialized for List, and optimized to avoid allocation if `as` is empty */
+ final def mapList[A, B](as: List[A])(f: A => B): List[B] = if (as eq Nil) Nil else {
+ val head = new ::[B](f(as.head), Nil)
+ var tail: ::[B] = head
+ var rest = as.tail
+ while (rest ne Nil) {
+ val next = new ::(f(rest.head), Nil)
+ tail.tl = next
+ tail = next
+ rest = rest.tail
+ }
+ head
+ }
+
+ final def collectFirst[A, B](as: List[A])(pf: PartialFunction[A, B]): Option[B] = {
+ @tailrec
+ def loop(rest: List[A]): Option[B] = rest match {
+ case Nil => None
+ case a :: as if pf.isDefinedAt(a) => Some(pf(a))
+ case a :: as => loop(as)
+ }
+ loop(as)
+ }
+
final def map2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => C): List[C] = {
val lb = new ListBuffer[C]
var ys1 = xs1
@@ -99,15 +123,19 @@ trait Collections {
else f(xs1.head, xs2.head, xs3.head) :: map3(xs1.tail, xs2.tail, xs3.tail)(f)
}
final def flatMap2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => List[C]): List[C] = {
- val lb = new ListBuffer[C]
+ var lb: ListBuffer[C] = null
var ys1 = xs1
var ys2 = xs2
while (!ys1.isEmpty && !ys2.isEmpty) {
- lb ++= f(ys1.head, ys2.head)
+ val cs = f(ys1.head, ys2.head)
+ if (cs ne Nil) {
+ if (lb eq null) lb = new ListBuffer[C]
+ lb ++= cs
+ }
ys1 = ys1.tail
ys2 = ys2.tail
}
- lb.toList
+ if (lb eq null) Nil else lb.result
}
final def flatCollect[A, B](elems: List[A])(pf: PartialFunction[A, Traversable[B]]): List[B] = {