From 7bddd73f6e18bde931026abf5fe2526b747727ad Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 8 Apr 2012 23:20:59 -0700 Subject: Make specialize check cheaper and consistent. Profiler said checking hasAnnotation thousands of times is expensive. I always wondered why some things used the SPECIALIZED flag and others looked for the annotation. No reason emerges which is apparent from the tests. So: - mark an annotated symbol specialized at a convenient time - always look for the flag - create Symbol#isSpecialized to be consistent with all others --- src/compiler/scala/reflect/internal/Symbols.scala | 1 + .../tools/nsc/transform/SpecializeTypes.scala | 40 ++++++++++------------ .../scala/tools/nsc/transform/UnCurry.scala | 6 ++++ 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index ba1513d12b..e6f03faa42 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -512,6 +512,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** The bottom classes are Nothing and Null, found in Definitions. */ def isBottomClass = false + def isSpecialized = this hasFlag SPECIALIZED /** These are all tests for varieties of ClassSymbol, which has these subclasses: * - ModuleClassSymbol diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 51da933312..30decd4854 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -99,9 +99,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Concrete methods that use a specialized type, or override such methods. */ private val concreteSpecMethods = perRunCaches.newWeakSet[Symbol]() - private def isSpecialized(sym: Symbol) = sym hasAnnotation SpecializedClass - private def hasSpecializedFlag(sym: Symbol) = sym hasFlag SPECIALIZED - private def specializedTypes(tps: List[Symbol]) = tps filter isSpecialized + private def specializedTypes(tps: List[Symbol]) = tps filter (_.isSpecialized) private def specializedOn(sym: Symbol): List[Symbol] = { sym getAnnotation SpecializedClass match { case Some(AnnotationInfo(_, Nil, _)) => specializableTypes.map(_.typeSymbol) @@ -141,7 +139,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def fromSpecialization(sym: Symbol, args: List[Type]): TypeEnv = { ifDebug(assert(sym.info.typeParams.length == args.length, sym + " args: " + args)) - emptyEnv ++ collectMap2(sym.info.typeParams, args)((k, v) => isSpecialized(k)) + emptyEnv ++ collectMap2(sym.info.typeParams, args)((k, v) => k.isSpecialized) } /** Does typeenv `t1` include `t2`? All type variables in `t1` @@ -166,7 +164,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ def isValid(env: TypeEnv, sym: Symbol): Boolean = { env forall { case (tvar, tpe) => - isSpecialized(tvar) && (concreteTypes(tvar) contains tpe) && { + tvar.isSpecialized && (concreteTypes(tvar) contains tpe) && { (sym.typeParams contains tvar) || (sym.owner != RootClass && (sym.owner.typeParams contains tvar)) } @@ -178,7 +176,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * 'sClass' itself if sClass is not a specialized subclass. */ def genericClass(sClass: Symbol): Symbol = - if (hasSpecializedFlag(sClass)) sClass.superClass + if (sClass.isSpecialized) sClass.superClass else sClass case class Overload(sym: Symbol, env: TypeEnv) { @@ -243,7 +241,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Type bounds of a @specialized type var are now in the environment. */ override def typeBoundsIn(env: TypeEnv): Boolean = { target.info.typeParams exists { tvar => - isSpecialized(tvar) && (specializedTypeVars(tvar.info.bounds) exists env.isDefinedAt) + tvar.isSpecialized && (specializedTypeVars(tvar.info.bounds) exists env.isDefinedAt) } } @@ -259,21 +257,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Has `clazz` any type parameters that need be specialized? */ def hasSpecializedParams(clazz: Symbol) = - clazz.info.typeParams exists isSpecialized + clazz.info.typeParams exists (_.isSpecialized) /** Return specialized type parameters. */ def specializedParams(sym: Symbol): List[Symbol] = - sym.info.typeParams filter isSpecialized + sym.info.typeParams filter (_.isSpecialized) def splitParams(tps: List[Symbol]) = - tps partition isSpecialized + tps partition (_.isSpecialized) /** Given an original class symbol and a list of types its type parameters are instantiated at * returns a list of type parameters that should remain in the TypeRef when instantiating a * specialized type. */ def survivingArgs(sym: Symbol, args: List[Type]): List[Type] = - for ((tvar, tpe) <- sym.info.typeParams.zip(args) if !isSpecialized(tvar) || !isScalaValueType(tpe)) + for ((tvar, tpe) <- sym.info.typeParams.zip(args) if !tvar.isSpecialized || !isScalaValueType(tpe)) yield tpe val specializedType = new TypeMap { @@ -347,7 +345,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * These are in a meaningful order for stability purposes. */ def concreteTypes(sym: Symbol): List[Type] = { - val types = if (!isSpecialized(sym)) + val types = if (!sym.isSpecialized) Nil // no @specialized Annotation else specializedOn(sym) map (s => specializesClass(s).tpe) sorted @@ -363,7 +361,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ private def specializations(tps: List[Symbol]): List[TypeEnv] = { // the keys in each TypeEnv - val keys: List[Symbol] = tps filter isSpecialized + val keys: List[Symbol] = tps filter (_.isSpecialized) // creating each permutation of concrete types def loop(ctypes: List[List[Type]]): List[List[Type]] = ctypes match { case Nil => Nil @@ -384,11 +382,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ private def needsSpecialization(env: TypeEnv, sym: Symbol): Boolean = { specializedTypeVars(sym).intersect(env.keySet).diff(wasSpecializedForTypeVars(sym)).nonEmpty || - (sym.isClassConstructor && (sym.enclClass.typeParams exists isSpecialized)) || + (sym.isClassConstructor && (sym.enclClass.typeParams exists (_.isSpecialized))) || (isNormalizedMember(sym) && info(sym).typeBoundsIn(env)) } - def isNormalizedMember(m: Symbol) = hasSpecializedFlag(m) && (info get m exists { + def isNormalizedMember(m: Symbol) = m.isSpecialized && (info get m exists { case NormalizedMember(_) => true case _ => false }) @@ -409,14 +407,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case TypeRef(pre, sym, args) => if (sym.isAliasType) specializedTypeVars(tpe.normalize) - else if (sym.isTypeParameter && isSpecialized(sym) || (sym.isTypeSkolem && isSpecialized(sym.deSkolemize))) + else if (sym.isTypeParameter && sym.isSpecialized || (sym.isTypeSkolem && sym.deSkolemize.isSpecialized)) Set(sym) else if (sym == ArrayClass) specializedTypeVars(args) else if (args.isEmpty) Set() else - specializedTypeVars(sym.typeParams zip args collect { case (tp, arg) if isSpecialized(tp) => arg }) + specializedTypeVars(sym.typeParams zip args collect { case (tp, arg) if tp.isSpecialized => arg }) case PolyType(tparams, resTpe) => specializedTypeVars(resTpe :: tparams.map(_.info)) // since this method may be run at phase typer (before uncurry, where NMTs are eliminated) @@ -450,7 +448,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Type parameters that survive when specializing in the specified environment. */ def survivingParams(params: List[Symbol], env: TypeEnv) = - params.filter(p => !isSpecialized(p) || !isScalaValueType(env(p))) + params.filter(p => !p.isSpecialized || !isScalaValueType(env(p))) /** Produces the symbols from type parameters `syms` of the original owner, * in the given type environment `env`. The new owner is `nowner`. @@ -994,7 +992,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * If `strict` is true, a UnifyError is thrown if unification is impossible. */ private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match { - case (TypeRef(_, sym1, _), _) if isSpecialized(sym1) => + case (TypeRef(_, sym1, _), _) if sym1.isSpecialized => debuglog("Unify " + tp1 + ", " + tp2) if (isPrimitiveValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1)) env + ((sym1, tp2)) @@ -1235,13 +1233,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Return the generic class corresponding to this specialized class. */ def originalClass(clazz: Symbol): Symbol = - if (hasSpecializedFlag(clazz)) { + if (clazz.isSpecialized) { val (originalName, _, _) = nme.splitSpecializedName(clazz.name) clazz.owner.info.decl(originalName).suchThat(_.isClass) } else NoSymbol def illegalSpecializedInheritance(clazz: Symbol): Boolean = ( - hasSpecializedFlag(clazz) + clazz.isSpecialized && originalClass(clazz).parentSymbols.exists(p => hasSpecializedParams(p) && !p.isTrait) ) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 0efdd9ab9f..7fc472df2f 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -494,6 +494,12 @@ abstract class UnCurry extends InfoTransform } val sym = tree.symbol + // Take a pass looking for @specialize annotations and set all + // their SPECIALIZE flags for cheaper recognition. + if ((sym ne null) && (sym.isClass || sym.isMethod)) { + for (tp <- sym.typeParams ; if tp hasAnnotation SpecializedClass) + tp setFlag SPECIALIZED + } val result = ( // TODO - settings.noassertions.value temporarily retained to avoid // breakage until a reasonable interface is settled upon. -- cgit v1.2.3