diff options
author | Marko Elezovic <marko@mentat-labs.com> | 2015-11-27 03:36:27 +0100 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-02-06 08:58:16 +0100 |
commit | cb68d9c1868e9fbb3e58cdfd606274e070db5b31 (patch) | |
tree | 00d0be1be40db7ca93e2f98f7475058ce53b5757 /src/compiler/scala/tools/nsc/backend/jvm | |
parent | 93b7e2982d7ee503bfc27a9523d17bbd2f5e1fd6 (diff) | |
download | scala-cb68d9c1868e9fbb3e58cdfd606274e070db5b31.tar.gz scala-cb68d9c1868e9fbb3e58cdfd606274e070db5b31.tar.bz2 scala-cb68d9c1868e9fbb3e58cdfd606274e070db5b31.zip |
SI-9571 Avoid boxing primitives in string concatenation
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm')
-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 59d584c370..1170e60d85 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -999,9 +999,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) } |