[JVM] Micro-optimize method signature mapping

This commit optimizes functions related to method signature mapping on
the JVM backend. The most significant change is avoiding re-allocations
in StringBuilder when building internal names. The commit also includes
minor optimizations, such as removing redundant allocations of strings
and other objects.
This commit is contained in:
Iaroslav Postovalov
2023-08-29 23:44:17 +06:00
committed by Space Team
parent 70996035fc
commit 059046a2b1
10 changed files with 58 additions and 27 deletions
@@ -151,9 +151,15 @@ object AbstractTypeMapper {
materialized: Boolean materialized: Boolean
): Type { ): Type {
val typeArgument = type.asArgumentList()[0] val typeArgument = type.asArgumentList()[0]
val (variance, memberType) = when { val variance: Variance
typeArgument.isStarProjection() -> Variance.OUT_VARIANCE to nullableAnyType() val memberType: KotlinTypeMarker
else -> typeArgument.getVariance().toVariance() to typeArgument.getType()
if (typeArgument.isStarProjection()) {
variance = Variance.OUT_VARIANCE
memberType = nullableAnyType()
} else {
variance = typeArgument.getVariance().toVariance()
memberType = typeArgument.getType()
} }
val arrayElementType: Type val arrayElementType: Type
@@ -317,7 +317,7 @@ val CallableDescriptor.arity: Int
(if (extensionReceiverParameter != null) 1 else 0) + (if (extensionReceiverParameter != null) 1 else 0) +
(if (dispatchReceiverParameter != null) 1 else 0) (if (dispatchReceiverParameter != null) 1 else 0)
fun FqName.topLevelClassInternalName() = JvmClassName.byClassId(ClassId(parent(), shortName())).internalName fun FqName.topLevelClassInternalName() = JvmClassName.internalNameByClassId(ClassId(parent(), shortName()))
fun FqName.topLevelClassAsmType(): Type = Type.getObjectType(topLevelClassInternalName()) fun FqName.topLevelClassAsmType(): Type = Type.getObjectType(topLevelClassInternalName())
fun initializeVariablesForDestructuredLambdaParameters(codegen: ExpressionCodegen, valueParameters: List<ValueParameterDescriptor>, endLabel: Label?) { fun initializeVariablesForDestructuredLambdaParameters(codegen: ExpressionCodegen, valueParameters: List<ValueParameterDescriptor>, endLabel: Label?) {
@@ -55,7 +55,15 @@ open class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapp
override fun mapTypeCommon(type: KotlinTypeMarker, mode: TypeMappingMode): Type = override fun mapTypeCommon(type: KotlinTypeMarker, mode: TypeMappingMode): Type =
mapType(type as IrType, mode) mapType(type as IrType, mode)
private fun computeClassInternalName(irClass: IrClass): StringBuilder { private fun computeClassInternalNameAsString(irClass: IrClass): String {
context.getLocalClassType(irClass)?.internalName?.let {
return it
}
return computeClassInternalName(irClass, 0).toString()
}
private fun computeClassInternalName(irClass: IrClass, capacity: Int): StringBuilder {
context.getLocalClassType(irClass)?.internalName?.let { context.getLocalClassType(irClass)?.internalName?.let {
return StringBuilder(it) return StringBuilder(it)
} }
@@ -63,20 +71,26 @@ open class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapp
val shortName = SpecialNames.safeIdentifier(irClass.name).identifier val shortName = SpecialNames.safeIdentifier(irClass.name).identifier
when (val parent = irClass.parent) { when (val parent = irClass.parent) {
is IrPackageFragment -> is IrPackageFragment -> {
return StringBuilder().apply { val fqName = parent.packageFqName
val fqName = parent.packageFqName var ourCapacity = shortName.length
if (!fqName.isRoot) {
ourCapacity += fqName.asString().length + 1
}
return StringBuilder(ourCapacity + capacity).apply {
if (!fqName.isRoot) { if (!fqName.isRoot) {
append(fqName.asString().replace('.', '/')).append("/") append(fqName.asString().replace('.', '/')).append("/")
} }
append(shortName) append(shortName)
} }
}
is IrClass -> is IrClass ->
return computeClassInternalName(parent).append("$").append(shortName) return computeClassInternalName(parent, 1 + shortName.length).append("$").append(shortName)
is IrFunction -> is IrFunction ->
if (parent.isSuspend && parent.parentAsClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) { if (parent.isSuspend && parent.parentAsClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) {
return computeClassInternalName(parent.parentAsClass.parentAsClass) val parentName = parent.name.asString()
.append("$").append(parent.name.asString()) return computeClassInternalName(parent.parentAsClass.parentAsClass, 1 + parentName.length)
.append("$").append(parentName)
} }
} }
@@ -92,7 +106,7 @@ open class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapp
context.classNameOverride[irClass]?.let { return it.internalName } context.classNameOverride[irClass]?.let { return it.internalName }
return JvmCodegenUtil.sanitizeNameIfNeeded( return JvmCodegenUtil.sanitizeNameIfNeeded(
computeClassInternalName(irClass).toString(), computeClassInternalNameAsString(irClass),
context.state.languageVersionSettings context.state.languageVersionSettings
) )
} }
@@ -79,7 +79,12 @@ class MethodSignatureMapper(private val context: JvmBackendContext, private val
if (property != null) { if (property != null) {
val propertyName = property.name.asString() val propertyName = property.name.asString()
val propertyParent = property.parentAsClass val propertyParent = property.parentAsClass
if (propertyParent.isAnnotationClass || propertyParent.superTypes.any { it.isJavaLangRecord() }) return propertyName
if (propertyParent.isAnnotationClass) return propertyName
for (i in propertyParent.superTypes.indices) {
if (propertyParent.superTypes[i].isJavaLangRecord()) return propertyName
}
// The enum property getters <get-name> and <get-ordinal> have special names which also // The enum property getters <get-name> and <get-ordinal> have special names which also
// apply to their fake overrides. Unfortunately, getJvmMethodNameIfSpecial does not handle // apply to their fake overrides. Unfortunately, getJvmMethodNameIfSpecial does not handle
@@ -248,8 +253,8 @@ class MethodSignatureMapper(private val context: JvmBackendContext, private val
sw.writeParametersStart() sw.writeParametersStart()
val contextReceivers = function.valueParameters.subList(0, function.contextReceiverParametersCount) for (i in 0 until function.contextReceiverParametersCount) {
for (contextReceiver in contextReceivers) { val contextReceiver = function.valueParameters[i]
writeParameter(sw, JvmMethodParameterKind.CONTEXT_RECEIVER, contextReceiver.type, function) writeParameter(sw, JvmMethodParameterKind.CONTEXT_RECEIVER, contextReceiver.type, function)
} }
@@ -258,9 +263,8 @@ class MethodSignatureMapper(private val context: JvmBackendContext, private val
writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function) writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function)
} }
val regularValueParameters = for (i in function.contextReceiverParametersCount until function.valueParameters.size) {
function.valueParameters.subList(function.contextReceiverParametersCount, function.valueParameters.size) val parameter = function.valueParameters[i]
for (parameter in regularValueParameters) {
val kind = when (parameter.origin) { val kind = when (parameter.origin) {
JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> JvmMethodParameterKind.OUTER JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> JvmMethodParameterKind.OUTER
JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER -> JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER -> JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL
@@ -468,11 +472,10 @@ class MethodSignatureMapper(private val context: JvmBackendContext, private val
if (!isBuiltIn) return null if (!isBuiltIn) return null
return allOverridden(includeSelf = true) return allOverridden(includeSelf = true)
.filter { it.isBuiltIn } .filter { it.isBuiltIn }
.mapNotNull { .firstNotNullOfOrNull {
val signature = it.computeJvmSignature() val signature = it.computeJvmSignature()
SpecialGenericSignatures.SIGNATURE_TO_JVM_REPRESENTATION_NAME[signature]?.asString() SpecialGenericSignatures.SIGNATURE_TO_JVM_REPRESENTATION_NAME[signature]?.asString()
} }
.firstOrNull()
} }
private fun IrSimpleFunction.getBuiltinSpecialPropertyGetterName(): String? { private fun IrSimpleFunction.getBuiltinSpecialPropertyGetterName(): String? {
@@ -134,7 +134,7 @@ open class SpecialGenericSignatures {
signatureAndName.copy(name = jdkName).signature signatureAndName.copy(name = jdkName).signature
} }
val ORIGINAL_SHORT_NAMES: List<Name> = NAME_AND_SIGNATURE_TO_JVM_REPRESENTATION_NAME_MAP.keys.map { it.name } val ORIGINAL_SHORT_NAMES: Set<Name> = NAME_AND_SIGNATURE_TO_JVM_REPRESENTATION_NAME_MAP.keys.mapTo(HashSet()) { it.name }
val JVM_SHORT_NAME_TO_BUILTIN_SHORT_NAMES_MAP: Map<Name, Name> = val JVM_SHORT_NAME_TO_BUILTIN_SHORT_NAMES_MAP: Map<Name, Name> =
NAME_AND_SIGNATURE_TO_JVM_REPRESENTATION_NAME_MAP.entries NAME_AND_SIGNATURE_TO_JVM_REPRESENTATION_NAME_MAP.entries
@@ -34,5 +34,5 @@ object SignatureBuildingComponents {
val ClassId.internalName: String val ClassId.internalName: String
get() { get() {
return JvmClassName.byClassId(JavaToKotlinClassMap.mapKotlinToJava(asSingleFqName().toUnsafe()) ?: this).internalName return JvmClassName.internalNameByClassId(JavaToKotlinClassMap.mapKotlinToJava(asSingleFqName().toUnsafe()) ?: this)
} }
@@ -55,7 +55,7 @@ fun <T : Any> TypeSystemCommonBackendContext.mapBuiltInType(
if (!mode.kotlinCollectionsToJavaCollections && JavaToKotlinClassMap.mutabilityMappings.any { it.javaClass == classId }) if (!mode.kotlinCollectionsToJavaCollections && JavaToKotlinClassMap.mutabilityMappings.any { it.javaClass == classId })
return null return null
return typeFactory.createObjectType(JvmClassName.byClassId(classId).internalName) return typeFactory.createObjectType(JvmClassName.internalNameByClassId(classId))
} }
} }
@@ -28,11 +28,16 @@ public class JvmClassName {
@NotNull @NotNull
public static JvmClassName byClassId(@NotNull ClassId classId) { public static JvmClassName byClassId(@NotNull ClassId classId) {
return new JvmClassName(internalNameByClassId(classId));
}
@NotNull
public static String internalNameByClassId(@NotNull ClassId classId) {
FqName packageFqName = classId.getPackageFqName(); FqName packageFqName = classId.getPackageFqName();
String relativeClassName = classId.getRelativeClassName().asString().replace('.', '$'); String relativeClassName = classId.getRelativeClassName().asString().replace('.', '$');
return packageFqName.isRoot() return packageFqName.isRoot()
? new JvmClassName(relativeClassName) ? relativeClassName
: new JvmClassName(packageFqName.asString().replace('.', '/') + "/" + relativeClassName); : packageFqName.asString().replace('.', '/') + "/" + relativeClassName;
} }
/** /**
@@ -93,7 +93,7 @@ internal fun CallableDescriptor.computeJvmSignature(): String? = signatures {
internal val ClassDescriptor.internalName: String internal val ClassDescriptor.internalName: String
get() { get() {
JavaToKotlinClassMap.mapKotlinToJava(fqNameSafe.toUnsafe())?.let { JavaToKotlinClassMap.mapKotlinToJava(fqNameSafe.toUnsafe())?.let {
return JvmClassName.byClassId(it).internalName return JvmClassName.internalNameByClassId(it)
} }
return computeInternalName(this) return computeInternalName(this)
@@ -109,7 +109,10 @@ fun String.capitalizeAsciiOnly(): String {
if (isEmpty()) return this if (isEmpty()) return this
val c = this[0] val c = this[0]
return if (c in 'a'..'z') return if (c in 'a'..'z')
c.uppercaseChar() + substring(1) buildString(length) {
append(c.uppercaseChar())
append(this@capitalizeAsciiOnly, 1, this@capitalizeAsciiOnly.length)
}
else else
this this
} }