From e3af86a5e535650bc04a29f1977b0e35616148f6 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 1 Nov 2013 17:55:33 +0100 Subject: Optimize generic signatures utility method `dotCleanup` --- src/compiler/scala/tools/nsc/transform/Erasure.scala | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 0a013995b6..aaaa3287c7 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -92,11 +92,22 @@ abstract class Erasure extends AddInterfaces // more rigorous way up front rather than catching it after the fact, // but that will be more involved. private def dotCleanup(sig: String): String = { + // OPT 50% of time in generic signatures (~1% of compile time) was in this method, hence the imperative rewrite. var last: Char = '\u0000' - sig map { - case '.' if last != '>' => last = '.' ; '$' - case ch => last = ch ; ch + var i = 0 + val len = sig.length + val copy: Array[Char] = sig.toCharArray + var changed = false + while (i < sig.length) { + val ch = copy(i) + if (ch == '.' && last != '>') { + copy(i) = '$' + changed = true + } + last = ch + i += 1 } + if (changed) new String(copy) else sig } /** This object is only used for sanity testing when -check:genjvm is set. -- cgit v1.2.3 From 811e4232ae6b56a4ec72d5b26f11eb370e924a31 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 6 Nov 2013 23:00:57 +0100 Subject: Avoid needless Name creation - Don't create names just to perform prefix/suffix checks - Don't create names, decode, *and* intern strings in ICode --- .../scala/tools/nsc/backend/icode/Members.scala | 8 ++--- src/reflect/scala/reflect/internal/Names.scala | 35 +++++++++++++++------- src/reflect/scala/reflect/internal/Symbols.scala | 2 +- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 267fa15312..64146585e5 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -21,7 +21,7 @@ trait Members { import global._ - object NoCode extends Code(null, "NoCode") { + object NoCode extends Code(null, TermName("NoCode")) { override def blocksList: List[BasicBlock] = Nil } @@ -29,8 +29,8 @@ trait Members { * This class represents the intermediate code of a method or * other multi-block piece of code, like exception handlers. */ - class Code(method: IMethod, name: String) { - def this(method: IMethod) = this(method, method.symbol.decodedName.toString.intern) + class Code(method: IMethod, name: Name) { + def this(method: IMethod) = this(method, method.symbol.name) /** The set of all blocks */ val blocks = mutable.ListBuffer[BasicBlock]() @@ -82,7 +82,7 @@ trait Members { } /** This methods returns a string representation of the ICode */ - override def toString = "ICode '" + name + "'" + override def toString = "ICode '" + name.decoded + "'" /* Compute a unique new label */ def nextLabel: Int = { diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 4075653674..73ce59feb2 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -345,6 +345,13 @@ trait Names extends api.Names { i += 1 i == prefix.length } + final def startsWith(prefix: String, start: Int): Boolean = { + var i = 0 + while (i < prefix.length && start + i < len && + chrs(index + start + i) == prefix.charAt(i)) + i += 1 + i == prefix.length + } /** Does this name end with suffix? */ final def endsWith(suffix: Name): Boolean = endsWith(suffix, len) @@ -357,6 +364,13 @@ trait Names extends api.Names { i += 1 i > suffix.length } + final def endsWith(suffix: String, end: Int): Boolean = { + var i = 1 + while (i <= suffix.length && i <= end && + chrs(index + end - i) == suffix.charAt(suffix.length - i)) + i += 1 + i > suffix.length + } final def containsName(subname: String): Boolean = containsName(newTermName(subname)) final def containsName(subname: Name): Boolean = { @@ -382,9 +396,9 @@ trait Names extends api.Names { final def startChar: Char = this charAt 0 final def endChar: Char = this charAt len - 1 final def startsWith(char: Char): Boolean = len > 0 && startChar == char - final def startsWith(name: String): Boolean = startsWith(newTermName(name)) + final def startsWith(name: String): Boolean = startsWith(name, 0) final def endsWith(char: Char): Boolean = len > 0 && endChar == char - final def endsWith(name: String): Boolean = endsWith(newTermName(name)) + final def endsWith(name: String): Boolean = endsWith(name, len) /** Rewrite the confusing failure indication via result == length to * the normal failure indication via result == -1. @@ -443,9 +457,10 @@ trait Names extends api.Names { } /** TODO - find some efficiency. */ - def append(ch: Char) = newName("" + this + ch) - def append(suffix: String) = newName("" + this + suffix) - def append(suffix: Name) = newName("" + this + suffix) + def append(ch: Char) = newName(toString + ch) + def append(suffix: String) = newName(toString + suffix) + def append(suffix: Name) = newName(toString + suffix) + def append(separator: Char, suffix: Name) = newName(toString + separator + suffix) def prepend(prefix: String) = newName("" + prefix + this) def decodedName: ThisNameType = newName(decode) @@ -463,7 +478,7 @@ trait Names extends api.Names { */ final class NameOps[T <: Name](name: T) { import NameTransformer._ - def stripSuffix(suffix: String): T = stripSuffix(suffix: TermName) + def stripSuffix(suffix: String): T = if (name endsWith suffix) dropRight(suffix.length) else name // OPT avoid creating a Name with `suffix` def stripSuffix(suffix: Name): T = if (name endsWith suffix) dropRight(suffix.length) else name def take(n: Int): T = name.subName(0, n).asInstanceOf[T] def drop(n: Int): T = name.subName(n, name.length).asInstanceOf[T] @@ -500,21 +515,21 @@ trait Names extends api.Names { /** TermName_S and TypeName_S have fields containing the string version of the name. * TermName_R and TypeName_R recreate it each time toString is called. */ - private class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { + private final class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString) override def newName(str: String): TermName = newTermNameCached(str) } - private class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { + private final class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString) override def newName(str: String): TypeName = newTypeNameCached(str) } - private class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { + private final class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h) override def toString = new String(chrs, index, len) } - private class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { + private final class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h) override def toString = new String(chrs, index, len) } diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index f49ddaf6ca..f8a6cae5f6 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -1102,7 +1102,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def fullNameInternal(separator: Char): Name = ( if (isRoot || isRootPackage || this == NoSymbol) name else if (owner.isEffectiveRoot) name - else ((effectiveOwner.enclClass.fullNameAsName(separator) append separator): Name) append name + else effectiveOwner.enclClass.fullNameAsName(separator) append (separator, name) ) def fullNameAsName(separator: Char): Name = fullNameInternal(separator).dropLocal -- cgit v1.2.3 From 86bc3249421cccdd9a9dd6a4b5ad352afbe2a620 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 6 Nov 2013 22:42:20 +0100 Subject: Optimization in Uncurry Only perform HashMap lookup of a tree until after checking more cheaply if it refers to a symbol with by-name parameter type. --- src/compiler/scala/tools/nsc/transform/UnCurry.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index e193cf3de2..e7ea686bc8 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -105,12 +105,11 @@ abstract class UnCurry extends InfoTransform */ def isByNameRef(tree: Tree) = ( tree.isTerm - && !byNameArgs(tree) && (tree.symbol ne null) && (isByName(tree.symbol)) + && !byNameArgs(tree) ) - // ------- Handling non-local returns ------------------------------------------------- /** The type of a non-local return expression with given argument type */ -- cgit v1.2.3 From a2f595ccc77d9ffa210c007b92b605550df74c6f Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 1 Nov 2013 16:43:11 +0100 Subject: Avoid work in GenICode#run when inactive. scalaPrimitives.init() represented 1% of a small (1s) compilation run. --- src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 1332d01dbd..4ab6663423 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -46,8 +46,10 @@ abstract class GenICode extends SubComponent { var unit: CompilationUnit = NoCompilationUnit override def run() { - scalaPrimitives.init() - classes.clear() + if (!settings.isBCodeActive) { + scalaPrimitives.init() + classes.clear() + } super.run() } -- cgit v1.2.3