IC mangling: Generalize mangling algorithm between two backends
This commit is contained in:
+76
-65
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen.state
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
|
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
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"))
|
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(
|
fun getManglingSuffixBasedOnKotlinSignature(
|
||||||
descriptor: CallableMemberDescriptor,
|
descriptor: CallableMemberDescriptor,
|
||||||
shouldMangleByReturnType: Boolean,
|
shouldMangleByReturnType: Boolean,
|
||||||
@@ -38,77 +95,31 @@ fun getManglingSuffixBasedOnKotlinSignature(
|
|||||||
|
|
||||||
val unwrappedDescriptor = descriptor.unwrapInitialDescriptorForSuspendFunction()
|
val unwrappedDescriptor = descriptor.unwrapInitialDescriptorForSuspendFunction()
|
||||||
|
|
||||||
if (useOldManglingRules || descriptor.isFunctionFromStdlib()) {
|
val resultNew = collectFunctionSignatureForManglingSuffix(
|
||||||
if (requiresFunctionNameManglingForParameterTypes(descriptor)) {
|
useOldManglingRules = useOldManglingRules || descriptor.isFunctionFromStdlib(),
|
||||||
return "-" + md5base64(collectSignatureForMangling(descriptor, true))
|
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.
|
return resultNew?.let { "-" + md5base64(it) }
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectSignatureForMangling(descriptor: CallableMemberDescriptor, useOldManglingRules: Boolean): String {
|
private fun getInfoForMangling(type: KotlinType): InfoForMangling? {
|
||||||
val types = listOfNotNull(descriptor.extensionReceiverParameter?.type) + descriptor.valueParameters.map { it.type }
|
val descriptor = type.constructor.declarationDescriptor ?: return null
|
||||||
return types.joinToString(separator = if (useOldManglingRules) ", " else "") { getSignatureElementForMangling(it, useOldManglingRules) }
|
return when (descriptor) {
|
||||||
}
|
is ClassDescriptor -> InfoForMangling(descriptor.fqNameUnsafe, descriptor.isInline, type.isMarkedNullable)
|
||||||
|
|
||||||
private fun getSignatureElementForMangling(type: KotlinType, useOldManglingRules: Boolean): String = buildString {
|
is TypeParameterDescriptor -> {
|
||||||
val descriptor = type.constructor.declarationDescriptor ?: return ""
|
getInfoForMangling(descriptor.representativeUpperBound)
|
||||||
if (useOldManglingRules) {
|
|
||||||
when (descriptor) {
|
|
||||||
is ClassDescriptor -> {
|
|
||||||
append('L')
|
|
||||||
append(descriptor.fqNameUnsafe)
|
|
||||||
if (type.isMarkedNullable) append('?')
|
|
||||||
append(';')
|
|
||||||
}
|
|
||||||
|
|
||||||
is TypeParameterDescriptor -> {
|
|
||||||
append(getSignatureElementForMangling(descriptor.representativeUpperBound, useOldManglingRules))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} 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 -> {
|
else -> null
|
||||||
append(getSignatureElementForMangling(descriptor.representativeUpperBound, useOldManglingRules))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -366,12 +366,13 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
private fun createInvokeMethod(receiverVar: IrValueDeclaration?): IrSimpleFunction =
|
private fun createInvokeMethod(receiverVar: IrValueDeclaration?): IrSimpleFunction =
|
||||||
functionReferenceClass.addFunction {
|
functionReferenceClass.addFunction {
|
||||||
setSourceRange(if (isLambda) callee else irFunctionReference)
|
setSourceRange(if (isLambda) callee else irFunctionReference)
|
||||||
name = if (samSuperType == null && callee.returnType.erasedUpperBound.isInline && context.state.functionsWithInlineClassReturnTypesMangled) {
|
name =
|
||||||
// For functions with inline class return type we need to mangle the invoke method.
|
if (samSuperType == null && callee.returnType.erasedUpperBound.isInline && context.state.functionsWithInlineClassReturnTypesMangled) {
|
||||||
// Otherwise, bridge lowering may fail to generate bridges for inline class types erasing to Any.
|
// For functions with inline class return type we need to mangle the invoke method.
|
||||||
val suffix = InlineClassAbi.hashSuffix(callee, mangleReturnTypes = true, useOldMangleRules = false)
|
// Otherwise, bridge lowering may fail to generate bridges for inline class types erasing to Any.
|
||||||
Name.identifier("${superMethod.owner.name.asString()}-${suffix}")
|
val suffix = InlineClassAbi.hashReturnSuffix(callee)
|
||||||
} else superMethod.owner.name
|
Name.identifier("${superMethod.owner.name.asString()}-${suffix}")
|
||||||
|
} else superMethod.owner.name
|
||||||
returnType = callee.returnType
|
returnType = callee.returnType
|
||||||
isSuspend = callee.isSuspend
|
isSuspend = callee.isSuspend
|
||||||
}.apply {
|
}.apply {
|
||||||
|
|||||||
+47
-57
@@ -7,13 +7,15 @@ package org.jetbrains.kotlin.backend.jvm.lower.inlineclasses
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||||
import org.jetbrains.kotlin.builtins.StandardNames
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.codegen.state.NOT_INLINE_CLASS_PARAMETER_PLACEHOLDER
|
import org.jetbrains.kotlin.codegen.state.InfoForMangling
|
||||||
|
import org.jetbrains.kotlin.codegen.state.collectFunctionSignatureForManglingSuffix
|
||||||
import org.jetbrains.kotlin.codegen.state.md5base64
|
import org.jetbrains.kotlin.codegen.state.md5base64
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,29 +76,7 @@ object InlineClassAbi {
|
|||||||
return Name.identifier("constructor-impl")
|
return Name.identifier("constructor-impl")
|
||||||
}
|
}
|
||||||
|
|
||||||
val suffix = if (useOldMangleRules || irFunction.isFunctionFromStdlib()) {
|
val suffix = hashSuffix(irFunction, mangleReturnTypes, useOldMangleRules) ?: return irFunction.name
|
||||||
when {
|
|
||||||
irFunction.fullValueParameterList.any { it.type.requiresMangling } ->
|
|
||||||
hashSuffix(irFunction, mangleReturnTypes = false, useOldMangleRules = true)
|
|
||||||
mangleReturnTypes && irFunction.hasMangledReturnType ->
|
|
||||||
returnHashSuffix(irFunction)
|
|
||||||
(irFunction.parent as? IrClass)?.isInline == true &&
|
|
||||||
irFunction.origin != IrDeclarationOrigin.IR_BUILTINS_STUB ->
|
|
||||||
"impl"
|
|
||||||
else ->
|
|
||||||
return irFunction.name
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
when {
|
|
||||||
irFunction.fullValueParameterList.any { it.type.requiresMangling } || (mangleReturnTypes && irFunction.hasMangledReturnType) ->
|
|
||||||
hashSuffix(irFunction, mangleReturnTypes, false)
|
|
||||||
(irFunction.parent as? IrClass)?.isInline == true &&
|
|
||||||
irFunction.origin != IrDeclarationOrigin.IR_BUILTINS_STUB ->
|
|
||||||
"impl"
|
|
||||||
else ->
|
|
||||||
return irFunction.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val base = when {
|
val base = when {
|
||||||
irFunction.isGetter ->
|
irFunction.isGetter ->
|
||||||
@@ -112,44 +92,54 @@ object InlineClassAbi {
|
|||||||
return Name.identifier("$base-$suffix")
|
return Name.identifier("$base-$suffix")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IrFunction.propertyName: Name
|
private fun hashSuffix(
|
||||||
get() = (this as IrSimpleFunction).correspondingPropertySymbol!!.owner.name
|
irFunction: IrFunction,
|
||||||
|
mangleReturnTypes: Boolean,
|
||||||
|
useOldMangleRules: Boolean,
|
||||||
|
alwaysMangleReturnType: Boolean = false
|
||||||
|
): String? {
|
||||||
|
val signatureForMangling = collectFunctionSignatureForManglingSuffix(
|
||||||
|
useOldManglingRules = useOldMangleRules || irFunction.isFunctionFromStdlib(),
|
||||||
|
requiresFunctionNameManglingForParameterTypes = irFunction.fullValueParameterList.any { it.type.requiresMangling },
|
||||||
|
fqNamesForMangling = irFunction.fullValueParameterList.map {
|
||||||
|
it.type.asInfoForMangling()
|
||||||
|
} + listOfNotNull(
|
||||||
|
// The JVM backend computes mangled names after creating suspend function views, but before default argument
|
||||||
|
// stub insertion. It would be nice if this part of the continuation lowering happened earlier in the pipeline.
|
||||||
|
// TODO: Move suspend function view creation before JvmInlineClassLowering.
|
||||||
|
if (irFunction.isSuspend)
|
||||||
|
InfoForMangling(FqNameUnsafe("kotlin.coroutines.Continuation"), isInline = false, isNullable = false)
|
||||||
|
else null
|
||||||
|
),
|
||||||
|
returnTypeInfo = if (alwaysMangleReturnType || (mangleReturnTypes && irFunction.hasMangledReturnType)) {
|
||||||
|
irFunction.returnType.asInfoForMangling()
|
||||||
|
} else null
|
||||||
|
)
|
||||||
|
|
||||||
fun hashSuffix(irFunction: IrFunction, mangleReturnTypes: Boolean, useOldMangleRules: Boolean): String {
|
return when {
|
||||||
val signatureElementsForMangling =
|
signatureForMangling != null -> md5base64(signatureForMangling)
|
||||||
irFunction.fullValueParameterList.mapTo(mutableListOf()) { it.type.eraseToString(useOldMangleRules) }
|
(irFunction.parent as? IrClass)?.isInline == true && irFunction.origin != IrDeclarationOrigin.IR_BUILTINS_STUB -> "impl"
|
||||||
if (irFunction.isSuspend) {
|
else -> null
|
||||||
// The JVM backend computes mangled names after creating suspend function views, but before default argument
|
|
||||||
// stub insertion. It would be nice if this part of the continuation lowering happened earlier in the pipeline.
|
|
||||||
// TODO: Move suspend function view creation before JvmInlineClassLowering.
|
|
||||||
signatureElementsForMangling += if (useOldMangleRules) "Lkotlin.coroutines.Continuation;"
|
|
||||||
else NOT_INLINE_CLASS_PARAMETER_PLACEHOLDER
|
|
||||||
}
|
}
|
||||||
val signatureString = signatureElementsForMangling.joinToString(separator = if (useOldMangleRules) ", " else "") +
|
|
||||||
if (mangleReturnTypes && irFunction.hasMangledReturnType && !useOldMangleRules)
|
|
||||||
":${irFunction.returnType.eraseToString(useOldMangleRules)}" else ""
|
|
||||||
return md5base64(signatureString)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun returnHashSuffix(irFunction: IrFunction) =
|
fun hashReturnSuffix(irFunction: IrFunction): String =
|
||||||
md5base64(":${irFunction.returnType.eraseToString(false)}")
|
hashSuffix(
|
||||||
|
irFunction,
|
||||||
|
mangleReturnTypes = true,
|
||||||
|
useOldMangleRules = false,
|
||||||
|
alwaysMangleReturnType = true
|
||||||
|
)!!
|
||||||
|
|
||||||
private fun IrType.eraseToString(useOldMangleRules: Boolean) =
|
private fun IrType.asInfoForMangling(): InfoForMangling =
|
||||||
if (useOldMangleRules) {
|
InfoForMangling(
|
||||||
buildString {
|
erasedUpperBound.fqNameWhenAvailable!!.toUnsafe(),
|
||||||
append('L')
|
isInline = getClass()?.isInline == true,
|
||||||
append(erasedUpperBound.fqNameWhenAvailable!!)
|
isNullable = isNullable()
|
||||||
if (isNullable()) append('?')
|
)
|
||||||
append(';')
|
|
||||||
}
|
private val IrFunction.propertyName: Name
|
||||||
} else {
|
get() = (this as IrSimpleFunction).correspondingPropertySymbol!!.owner.name
|
||||||
if (getClass()?.isInline == true) buildString {
|
|
||||||
append('L')
|
|
||||||
append(erasedUpperBound.fqNameWhenAvailable!!)
|
|
||||||
if (isNullable()) append('?')
|
|
||||||
append(';')
|
|
||||||
} else NOT_INLINE_CLASS_PARAMETER_PLACEHOLDER
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val IrType.requiresMangling: Boolean
|
internal val IrType.requiresMangling: Boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user