Remove Concat and StringPlus intrinsics in favor of IrStringConcatenation.

This commit is contained in:
Steven Schäfer
2019-04-04 16:09:49 +02:00
committed by max-kammerer
parent 26c9d69252
commit f2392a6a28
20 changed files with 192 additions and 120 deletions
@@ -8,13 +8,15 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
import org.jetbrains.kotlin.ir.expressions.impl.IrStringConcatenationImpl
import org.jetbrains.kotlin.ir.types.isString
import org.jetbrains.kotlin.ir.types.isStringClassType
import org.jetbrains.kotlin.ir.util.getPackageFragment
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -73,11 +75,13 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
return when (expression) {
is IrStringConcatenation -> true
is IrCall -> {
val dispatchReceiver = expression.dispatchReceiver
dispatchReceiver != null &&
dispatchReceiver.type.isString() &&
expression.symbol.owner.name == PLUS_NAME &&
expression.type.isString() &&
val function = expression.symbol.owner
val receiver = expression.dispatchReceiver ?: expression.extensionReceiver
receiver != null &&
receiver.type.isStringClassType() &&
function.getPackageFragment()?.fqName == KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME &&
function.name == PLUS_NAME &&
expression.type.isStringClassType() &&
expression.valueArgumentsCount == 1
}
else -> false
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.common.descriptors.propertyIfAccessor
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty
import org.jetbrains.kotlin.backend.jvm.intrinsics.Not
import org.jetbrains.kotlin.backend.jvm.lower.CrIrType
@@ -29,9 +30,7 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -774,12 +773,28 @@ class ExpressionCodegen(
override fun visitStringConcatenation(expression: IrStringConcatenation, data: BlockInfo): PromisedValue {
expression.markLineNumber(startOffset = true)
when (expression.arguments.size) {
0 -> mv.aconst("")
1 -> {
val arity = expression.arguments.size
when {
arity == 0 -> mv.aconst("")
arity == 1 -> {
// Convert single arg to string.
val type = expression.arguments[0].accept(this, data).materialized.type
AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper).put(expression.asmType, mv)
if (!expression.arguments[0].type.isString())
AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper).put(expression.asmType, mv)
}
arity == 2 && expression.arguments[0].type.isStringClassType() -> {
// Call the stringPlus intrinsic
expression.arguments.forEach {
val type = it.accept(this, data).materialized.type
if (type.sort != Type.OBJECT)
AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper).put(expression.asmType, mv)
}
mv.invokestatic(
IntrinsicMethods.INTRINSICS_CLASS_NAME,
"stringPlus",
"(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;",
false
)
}
else -> {
// Use StringBuilder to concatenate.
@@ -1,70 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class Concat : IntrinsicMethod() {
override fun toCallable(
expression: IrMemberAccessExpression,
signature: JvmMethodSignature,
context: JvmBackendContext
): IrIntrinsicFunction {
val argsTypes = expression.receiverAndArgs().asmTypes(context).toMutableList()
argsTypes[0] = AsmTypes.JAVA_STRING_TYPE
return object : IrIntrinsicFunction(expression, signature, context, argsTypes) {
override fun genInvokeInstruction(v: InstructionAdapter) {
AsmUtil.genInvokeAppendMethod(v, argsTypes[1], null)
v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false)
}
override fun invoke(
v: InstructionAdapter,
codegen: org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen,
data: BlockInfo
): StackValue {
v.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder")
v.dup()
return super.invoke(v, codegen, data)
}
override fun genArg(
expression: IrExpression,
codegen: org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen,
index: Int,
data: BlockInfo
) {
super.genArg(expression, codegen, index, data)
if (index == 0) {
codegen.mv.invokespecial("java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false)
}
}
}
}
}
@@ -55,7 +55,6 @@ public class IntrinsicMethods {
private static final IteratorNext ITERATOR_NEXT = new IteratorNext();
private static final ArraySet ARRAY_SET = new ArraySet();
private static final ArrayGet ARRAY_GET = new ArrayGet();
private static final StringPlus STRING_PLUS = new StringPlus();
private static final ToString TO_STRING = new ToString();
private static final Clone CLONE = new Clone();
@@ -119,13 +118,11 @@ public class IntrinsicMethods {
declareIntrinsicFunction(FQ_NAMES._boolean, "not", 0, new Not());
declareIntrinsicFunction(FQ_NAMES.string, "plus", 1, new Concat());
declareIntrinsicFunction(FQ_NAMES.string, "get", 1, new StringGetChar());
declareIntrinsicFunction(FQ_NAMES.cloneable, "clone", 0, CLONE);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.any, "toString", 0, TO_STRING);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.string, "plus", 1, STRING_PLUS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOfNulls", 1, new NewArray());
for (PrimitiveType type : PrimitiveType.values()) {
@@ -92,7 +92,7 @@ open class IrIntrinsicFunction(
}
}
open fun genArg(expression: IrExpression, codegen: ExpressionCodegen, index: Int, data: BlockInfo) {
private fun genArg(expression: IrExpression, codegen: ExpressionCodegen, index: Int, data: BlockInfo) {
codegen.gen(expression, argsTypes[index], data)
}
@@ -1,30 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
class StringPlus : IntrinsicMethod() {
override fun toCallable(expression: IrMemberAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction {
return IrIntrinsicFunction.create(expression, signature, context) {
it.invokestatic("kotlin/jvm/internal/Intrinsics", "stringPlus",
"(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;", false)
}
}
}
@@ -16,9 +16,9 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName
private fun IrType.isNotNullClassType(fqName: FqNameUnsafe) = isClassType(fqName, hasQuestionMark = false)
private fun IrType.isNullableClassType(fqName: FqNameUnsafe) = isClassType(fqName, hasQuestionMark = true)
private fun IrType.isClassType(fqName: FqNameUnsafe, hasQuestionMark: Boolean): Boolean {
private fun IrType.isClassType(fqName: FqNameUnsafe, hasQuestionMark: Boolean? = null): Boolean {
if (this !is IrSimpleType) return false
if (this.hasQuestionMark != hasQuestionMark) return false
if (hasQuestionMark != null && this.hasQuestionMark != hasQuestionMark) return false
val classSymbol = this.classifier as? IrClassSymbol ?: return false
return classFqNameEquals(classSymbol, fqName)
}
@@ -37,6 +37,7 @@ fun IrType.isNullableAny(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAME
fun IrType.isString(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.string)
fun IrType.isNullableString(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES.string)
fun IrType.isStringClassType(): Boolean = isClassType(KotlinBuiltIns.FQ_NAMES.string)
fun IrType.isArray(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.array)
fun IrType.isNullableArray(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES.array)
fun IrType.isCollection(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.collection.toUnsafe())