IC mangling: Generalize mangling algorithm between two backends

This commit is contained in:
Ilmir Usmanov
2020-11-13 23:42:31 +01:00
parent b33774e5f2
commit bc1b6fef1f
3 changed files with 130 additions and 128 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
@@ -23,6 +24,62 @@ const val NOT_INLINE_CLASS_PARAMETER_PLACEHOLDER = "_"
private fun FunctionDescriptor.isFunctionFromStdlib(): Boolean = fqNameSafe.startsWith(Name.identifier("kotlin"))
class InfoForMangling(
val fqName: FqNameUnsafe,
val isInline: Boolean,
val isNullable: Boolean
)
fun collectFunctionSignatureForManglingSuffix(
useOldManglingRules: Boolean,
requiresFunctionNameManglingForParameterTypes: Boolean,
fqNamesForMangling: List<InfoForMangling?>,
returnTypeInfo: InfoForMangling?,
): String? {
fun getSignatureElementForMangling(info: InfoForMangling?): String = buildString {
if (info == null) return ""
if (useOldManglingRules || info.isInline) {
append('L')
append(info.fqName)
if (info.isNullable) append('?')
append(';')
} else {
append(NOT_INLINE_CLASS_PARAMETER_PLACEHOLDER)
}
}
fun collectSignatureForMangling(): String =
fqNamesForMangling.joinToString(separator = if (useOldManglingRules) ", " else "") {
getSignatureElementForMangling(it)
}
if (useOldManglingRules) {
if (requiresFunctionNameManglingForParameterTypes) {
return collectSignatureForMangling()
}
// If a class member function returns inline class value, mangle its name.
// NB here function can be a suspend function JVM view with return type replaced with 'Any',
// should unwrap it and take original return type instead.
if (returnTypeInfo != null) {
return ":" + getSignatureElementForMangling(returnTypeInfo)
}
} else {
// If a function accepts inline class parameters, mangle its name.
if (requiresFunctionNameManglingForParameterTypes || returnTypeInfo != null) {
// If a class member function returns inline class value, mangle its name.
// NB here function can be a suspend function JVM view with return type replaced with 'Any',
// should unwrap it and take original return type instead.
val signature = collectSignatureForMangling() +
if (returnTypeInfo != null)
":" + getSignatureElementForMangling(returnTypeInfo)
else ""
return signature
}
}
return null
}
fun getManglingSuffixBasedOnKotlinSignature(
descriptor: CallableMemberDescriptor,
shouldMangleByReturnType: Boolean,
@@ -38,77 +95,31 @@ fun getManglingSuffixBasedOnKotlinSignature(
val unwrappedDescriptor = descriptor.unwrapInitialDescriptorForSuspendFunction()
if (useOldManglingRules || descriptor.isFunctionFromStdlib()) {
if (requiresFunctionNameManglingForParameterTypes(descriptor)) {
return "-" + md5base64(collectSignatureForMangling(descriptor, true))
}
val resultNew = collectFunctionSignatureForManglingSuffix(
useOldManglingRules = useOldManglingRules || descriptor.isFunctionFromStdlib(),
requiresFunctionNameManglingForParameterTypes = requiresFunctionNameManglingForParameterTypes(descriptor),
fqNamesForMangling =
(listOfNotNull(descriptor.extensionReceiverParameter?.type) + descriptor.valueParameters.map { it.type })
.map { getInfoForMangling(it) },
returnTypeInfo =
if (shouldMangleByReturnType && requiresFunctionNameManglingForReturnType(unwrappedDescriptor))
getInfoForMangling(unwrappedDescriptor.returnType!!)
else null
)
// If a class member function returns inline class value, mangle its name.
// NB here function can be a suspend function JVM view with return type replaced with 'Any',
// should unwrap it and take original return type instead.
if (shouldMangleByReturnType) {
if (requiresFunctionNameManglingForReturnType(unwrappedDescriptor)) {
return "-" + md5base64(
":" + getSignatureElementForMangling(
unwrappedDescriptor.returnType!!, true
)
)
}
}
} else {
// If a function accepts inline class parameters, mangle its name.
if (requiresFunctionNameManglingForParameterTypes(descriptor) ||
(shouldMangleByReturnType && requiresFunctionNameManglingForReturnType(unwrappedDescriptor))
) {
// If a class member function returns inline class value, mangle its name.
// NB here function can be a suspend function JVM view with return type replaced with 'Any',
// should unwrap it and take original return type instead.
val signature = collectSignatureForMangling(descriptor, false) +
if (shouldMangleByReturnType && requiresFunctionNameManglingForReturnType(unwrappedDescriptor))
":" + getSignatureElementForMangling(unwrappedDescriptor.returnType!!, false)
else ""
return "-" + md5base64(signature)
}
}
return null
return resultNew?.let { "-" + md5base64(it) }
}
private fun collectSignatureForMangling(descriptor: CallableMemberDescriptor, useOldManglingRules: Boolean): String {
val types = listOfNotNull(descriptor.extensionReceiverParameter?.type) + descriptor.valueParameters.map { it.type }
return types.joinToString(separator = if (useOldManglingRules) ", " else "") { getSignatureElementForMangling(it, useOldManglingRules) }
}
private fun getInfoForMangling(type: KotlinType): InfoForMangling? {
val descriptor = type.constructor.declarationDescriptor ?: return null
return when (descriptor) {
is ClassDescriptor -> InfoForMangling(descriptor.fqNameUnsafe, descriptor.isInline, type.isMarkedNullable)
private fun getSignatureElementForMangling(type: KotlinType, useOldManglingRules: Boolean): String = buildString {
val descriptor = type.constructor.declarationDescriptor ?: return ""
if (useOldManglingRules) {
when (descriptor) {
is ClassDescriptor -> {
append('L')
append(descriptor.fqNameUnsafe)
if (type.isMarkedNullable) append('?')
append(';')
}
is TypeParameterDescriptor -> {
append(getSignatureElementForMangling(descriptor.representativeUpperBound, useOldManglingRules))
}
is TypeParameterDescriptor -> {
getInfoForMangling(descriptor.representativeUpperBound)
}
} else {
when (descriptor) {
is ClassDescriptor -> if (descriptor.isInline) {
append('L')
append(descriptor.fqNameUnsafe)
if (type.isMarkedNullable) append('?')
append(';')
} else {
append(NOT_INLINE_CLASS_PARAMETER_PLACEHOLDER)
}
is TypeParameterDescriptor -> {
append(getSignatureElementForMangling(descriptor.representativeUpperBound, useOldManglingRules))
}
}
else -> null
}
}