IC mangling: JVM_IR: Fallback to old mangling rules

if classfile does not contain functions mangled in the new way.
This commit is contained in:
Ilmir Usmanov
2020-11-05 03:31:21 +01:00
parent 546eea1982
commit 23184bae05
5 changed files with 71 additions and 23 deletions
@@ -133,7 +133,7 @@ class JvmBackendContext(
val staticDefaultStubs = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory)
val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory, this)
internal fun referenceClass(descriptor: ClassDescriptor): IrClassSymbol =
symbolTable.lazyWrapper.referenceClass(descriptor)
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.Method
class IrFrameMap : FrameMapBase<IrSymbol>() {
private val typeMap = mutableMapOf<IrSymbol, Type>()
@@ -376,3 +377,13 @@ val IrMemberAccessExpression<*>.psiElement: PsiElement?
fun IrSimpleType.isRawType(): Boolean =
hasAnnotation(JvmGeneratorExtensions.RAW_TYPE_ANNOTATION_FQ_NAME)
@OptIn(ObsoleteDescriptorBasedAPI::class)
internal fun classFileContainsMethod(function: IrFunction, context: JvmBackendContext, name: String): Boolean? {
val originalDescriptor = context.methodSignatureMapper.mapSignatureWithGeneric(function).asmMethod.descriptor
val descriptor = if (function.isSuspend)
listOf(*Type.getArgumentTypes(originalDescriptor), Type.getObjectType("kotlin/coroutines/Continuation"))
.joinToString(prefix = "(", postfix = ")", separator = "") + AsmTypes.OBJECT_TYPE
else originalDescriptor
return classFileContainsMethod(function.descriptor, context.state, Method(name, descriptor))
}
@@ -369,7 +369,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
name = if (samSuperType == null && callee.returnType.erasedUpperBound.isInline && context.state.functionsWithInlineClassReturnTypesMangled) {
// For functions with inline class return type we need to mangle the invoke method.
// Otherwise, bridge lowering may fail to generate bridges for inline class types erasing to Any.
val suffix = InlineClassAbi.hashSuffix(callee, true)
val suffix = InlineClassAbi.hashSuffix(callee, mangleReturnTypes = true, useOldMangleRules = false)
Name.identifier("${superMethod.owner.name.asString()}-${suffix}")
} else superMethod.owner.name
returnType = callee.returnType
@@ -62,7 +62,7 @@ object InlineClassAbi {
* Returns a mangled name for a function taking inline class arguments
* to avoid clashes between overloaded methods.
*/
fun mangledNameFor(irFunction: IrFunction, mangleReturnTypes: Boolean): Name {
fun mangledNameFor(irFunction: IrFunction, mangleReturnTypes: Boolean, useOldMangleRules: Boolean): Name {
if (irFunction is IrConstructor) {
// Note that we might drop this convention and use standard mangling for constructors too, see KT-37186.
assert(irFunction.constructedClass.isInline) {
@@ -71,14 +71,28 @@ object InlineClassAbi {
return Name.identifier("constructor-impl")
}
val suffix = when {
irFunction.fullValueParameterList.any { it.type.requiresMangling } || (mangleReturnTypes && irFunction.hasMangledReturnType) ->
hashSuffix(irFunction, mangleReturnTypes)
(irFunction.parent as? IrClass)?.isInline == true &&
irFunction.origin != IrDeclarationOrigin.IR_BUILTINS_STUB ->
"impl"
else ->
return irFunction.name
val suffix = if (useOldMangleRules) {
when {
irFunction.fullValueParameterList.any { it.type.requiresMangling } ->
hashSuffix(irFunction, false, useOldMangleRules)
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, useOldMangleRules)
(irFunction.parent as? IrClass)?.isInline == true &&
irFunction.origin != IrDeclarationOrigin.IR_BUILTINS_STUB ->
"impl"
else ->
return irFunction.name
}
}
val base = when {
@@ -98,26 +112,40 @@ object InlineClassAbi {
private val IrFunction.propertyName: Name
get() = (this as IrSimpleFunction).correspondingPropertySymbol!!.owner.name
fun hashSuffix(irFunction: IrFunction, mangleReturnTypes: Boolean): String {
fun hashSuffix(irFunction: IrFunction, mangleReturnTypes: Boolean, useOldMangleRules: Boolean): String {
val signatureElementsForMangling =
irFunction.fullValueParameterList.mapTo(mutableListOf()) { it.type.eraseToString() }
irFunction.fullValueParameterList.mapTo(mutableListOf()) { it.type.eraseToString(useOldMangleRules) }
if (irFunction.isSuspend) {
// 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 += "x"
signatureElementsForMangling += if (useOldMangleRules) "Lkotlin.coroutines.Continuation;" else "x"
}
val signatureString = signatureElementsForMangling.joinToString() +
if (mangleReturnTypes && irFunction.hasMangledReturnType) ":${irFunction.returnType.eraseToString()}" else ""
if (mangleReturnTypes && irFunction.hasMangledReturnType && !useOldMangleRules)
":${irFunction.returnType.eraseToString(useOldMangleRules)}" else ""
return md5base64(signatureString)
}
private fun IrType.eraseToString() = if (getClass()?.isInline == true) buildString {
append('L')
append(erasedUpperBound.fqNameWhenAvailable!!)
if (isNullable()) append('?')
append(';')
} else "x"
private fun returnHashSuffix(irFunction: IrFunction) =
md5base64(":${irFunction.returnType.eraseToString(false)}")
private fun IrType.eraseToString(useOldMangleRules: Boolean) =
if (useOldMangleRules) {
buildString {
append('L')
append(erasedUpperBound.fqNameWhenAvailable!!)
if (isNullable()) append('?')
append(';')
}
} else {
if (getClass()?.isInline == true) buildString {
append('L')
append(erasedUpperBound.fqNameWhenAvailable!!)
if (isNullable()) append('?')
append(';')
} else "x"
}
}
internal val IrType.requiresMangling: Boolean
@@ -9,7 +9,9 @@ import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParameters
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.classFileContainsMethod
import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi.mangledNameFor
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
@@ -33,7 +35,11 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
/**
* Keeps track of replacement functions and inline class box/unbox functions.
*/
class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean, private val irFactory: IrFactory) {
class MemoizedInlineClassReplacements(
private val mangleReturnTypes: Boolean,
private val irFactory: IrFactory,
private val context: JvmBackendContext
) {
private val storageManager = LockBasedStorageManager("inline-class-replacements")
private val propertyMap = mutableMapOf<IrPropertySymbol, IrProperty>()
@@ -215,7 +221,10 @@ class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean, pr
if (noFakeOverride) {
isFakeOverride = false
}
name = mangledNameFor(function, mangleReturnTypes)
name = mangledNameFor(function, mangleReturnTypes, false)
if (name.asString().contains("-") && classFileContainsMethod(function, context, name.asString()) == false) {
name = mangledNameFor(function, mangleReturnTypes, true)
}
returnType = function.returnType
}.apply {
parent = function.parent