diff options
author | Lukas Rytz <lukas.rytz@typesafe.com> | 2016-02-12 08:17:43 +0100 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@typesafe.com> | 2016-02-12 08:17:43 +0100 |
commit | 7c25282ff91445dc1bdc20e49b68c2d20c318876 (patch) | |
tree | cebfa03c9062988c0d7445dd734345384ece9687 /src | |
parent | 7910508d1071e0e769ff6e291d3a1c479a067262 (diff) | |
parent | cb68d9c1868e9fbb3e58cdfd606274e070db5b31 (diff) | |
download | scala-7c25282ff91445dc1bdc20e49b68c2d20c318876.tar.gz scala-7c25282ff91445dc1bdc20e49b68c2d20c318876.tar.bz2 scala-7c25282ff91445dc1bdc20e49b68c2d20c318876.zip |
Merge pull request #4944 from lrytz/stringBuilderNoBox
SI-9571 Avoid boxing primitives in string concatenation
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 14 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala | 15 |
2 files changed, 20 insertions, 9 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index efa97b0d6f..a28d4b0083 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -1008,9 +1008,17 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { case concatenations => bc.genStartConcat(tree.pos) for (elem <- concatenations) { - val kind = tpeTK(elem) - genLoad(elem, kind) - bc.genStringConcat(kind, elem.pos) + val loadedElem = elem match { + case Apply(boxOp, value :: Nil) if currentRun.runDefinitions.isBox(boxOp.symbol) => + // Eliminate boxing of primitive values. Boxing is introduced by erasure because + // there's only a single synthetic `+` method "added" to the string class. + value + + case _ => elem + } + val elemType = tpeTK(loadedElem) + genLoad(loadedElem, elemType) + bc.genConcat(elemType, loadedElem.pos) } bc.genEndConcat(tree.pos) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala index 328a8187c8..0a95bc5e39 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala @@ -197,16 +197,19 @@ abstract class BCodeIdiomatic extends SubComponent { /* * can-multi-thread */ - final def genStringConcat(el: BType, pos: Position): Unit = { - val jtype = el match { + def genConcat(elemType: BType, pos: Position): Unit = { + val paramType = elemType match { case ct: ClassBType if ct.isSubtypeOf(StringRef).get => StringRef case ct: ClassBType if ct.isSubtypeOf(jlStringBufferRef).get => jlStringBufferRef case ct: ClassBType if ct.isSubtypeOf(jlCharSequenceRef).get => jlCharSequenceRef - case rt: RefBType => ObjectRef - case pt: PrimitiveBType => pt // Currently this ends up being boxed in erasure + // Don't match for `ArrayBType(CHAR)`, even though StringBuilder has such an overload: + // `"a" + Array('b')` should NOT be "ab", but "a[C@...". + case _: RefBType => ObjectRef + // jlStringBuilder does not have overloads for byte and short, but we can just use the int version + case BYTE | SHORT => INT + case pt: PrimitiveBType => pt } - - val bt = MethodBType(List(jtype), jlStringBuilderRef) + val bt = MethodBType(List(paramType), jlStringBuilderRef) invokevirtual(JavaStringBuilderClassName, "append", bt.descriptor, pos) } |