summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-01-15 23:21:25 +0000
committerPaul Phillips <paulp@improving.org>2011-01-15 23:21:25 +0000
commit866801385f81417a2ac33916280df918e4bd5b3b (patch)
tree17cf474ab89a37804af270c97852d580a576beec /src
parent604797b64518cbd75583e6ac14876552d6598c9d (diff)
downloadscala-866801385f81417a2ac33916280df918e4bd5b3b.tar.gz
scala-866801385f81417a2ac33916280df918e4bd5b3b.tar.bz2
scala-866801385f81417a2ac33916280df918e4bd5b3b.zip
Optimization to string concatenation.
with a primitive CONCAT and several opcodes, I'm assuming nobody will oppose this on principle. Given an expression of the exact form "" + x (that is, the NPE-immune and much less ugly way to call .toString) we used to get 4x the bytecode and create an unneeded StringBuilder. Now this: 0: aload_1 1: invokestatic #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 4: areturn Closes #4160, review by dragos.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala63
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala1
2 files changed, 48 insertions, 16 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 7bfabc239f..e9d0b6c90e 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -26,7 +26,7 @@ abstract class GenICode extends SubComponent {
import icodes._
import icodes.opcodes._
import definitions.{
- ArrayClass, ObjectClass, ThrowableClass, StringClass, NothingClass, NullClass, AnyRefClass,
+ ArrayClass, ObjectClass, ThrowableClass, StringClass, StringModule, NothingClass, NullClass, AnyRefClass,
Object_equals, Object_isInstanceOf, Object_asInstanceOf, ScalaRunTimeModule,
BoxedNumberClass, BoxedCharacterClass,
getMember, runtimeCompanions
@@ -1321,6 +1321,34 @@ abstract class GenICode extends SubComponent {
}
}
+ /** The Object => String overload.
+ */
+ private lazy val String_valueOf: Symbol = getMember(StringModule, "valueOf") filter (sym =>
+ sym.info.paramTypes match {
+ case List(pt) => pt.typeSymbol == ObjectClass
+ case _ => false
+ }
+ )
+
+ // I wrote it this way before I realized all the primitive types are
+ // boxed at this point, so I'd have to unbox them. Keeping it around in
+ // case we want to get more precise.
+ //
+ // private def valueOfForType(tp: Type): Symbol = {
+ // val xs = getMember(StringModule, "valueOf") filter (sym =>
+ // // We always exclude the Array[Char] overload because java throws an NPE if
+ // // you pass it a null. It will instead find the Object one, which doesn't.
+ // sym.info.paramTypes match {
+ // case List(pt) => pt.typeSymbol != ArrayClass && (tp <:< pt)
+ // case _ => false
+ // }
+ // )
+ // xs.alternatives match {
+ // case List(sym) => sym
+ // case _ => NoSymbol
+ // }
+ // }
+
/** Generate string concatenation.
*
* @param tree ...
@@ -1328,22 +1356,25 @@ abstract class GenICode extends SubComponent {
* @return ...
*/
def genStringConcat(tree: Tree, ctx: Context): Context = {
- val Apply(Select(larg, _), rarg) = tree
- var ctx1 = ctx
-
- val concatenations = liftStringConcat(tree)
- if (settings.debug.value)
- log("Lifted string concatenations for " + tree + "\n to: " + concatenations);
-
- ctx1.bb.emit(CALL_PRIMITIVE(StartConcat), tree.pos);
- for (elem <- concatenations) {
- val kind = toTypeKind(elem.tpe)
- ctx1 = genLoad(elem, ctx1, kind)
- ctx1.bb.emit(CALL_PRIMITIVE(StringConcat(kind)), elem.pos)
+ liftStringConcat(tree) match {
+ // Optimization for expressions of the form "" + x. We can avoid the StringBuilder.
+ case List(Literal(Constant("")), arg) =>
+ if (settings.debug.value) log("Rewriting \"\" + x as String.valueOf(x) for: " + arg)
+ val ctx1 = genLoad(arg, ctx, ObjectReference)
+ ctx1.bb.emit(CALL_METHOD(String_valueOf, Static(false)), arg.pos)
+ ctx1
+ case concatenations =>
+ if (settings.debug.value) log("Lifted string concatenations for " + tree + "\n to: " + concatenations)
+ var ctx1 = ctx
+ ctx1.bb.emit(CALL_PRIMITIVE(StartConcat), tree.pos)
+ for (elem <- concatenations) {
+ val kind = toTypeKind(elem.tpe)
+ ctx1 = genLoad(elem, ctx1, kind)
+ ctx1.bb.emit(CALL_PRIMITIVE(StringConcat(kind)), elem.pos)
+ }
+ ctx1.bb.emit(CALL_PRIMITIVE(EndConcat), tree.pos)
+ ctx1
}
- ctx1.bb.emit(CALL_PRIMITIVE(EndConcat), tree.pos)
-
- ctx1
}
/** Generate the scala ## method.
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 26b4f88f0c..659b7e80d2 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -149,6 +149,7 @@ trait Definitions extends reflect.generic.StandardDefinitions {
lazy val PartialFunctionClass = getClass("scala.PartialFunction")
lazy val SymbolClass = getClass("scala.Symbol")
lazy val StringClass = getClass(sn.String)
+ lazy val StringModule = StringClass.linkedClassOfClass
lazy val ClassClass = getClass(sn.Class)
def Class_getMethod = getMember(ClassClass, nme.getMethod_)