IC mangling: Old JVM BE: 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-04 21:16:03 +01:00
parent c62093f54c
commit 546eea1982
4 changed files with 136 additions and 28 deletions
@@ -2684,7 +2684,19 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
fd = ArgumentGeneratorKt.getFunctionWithDefaultArguments(fd);
}
return typeMapper.mapToCallableMethod(fd, superCall, null, resolvedCall);
CallableMethod method = typeMapper.mapToCallableMethod(fd, superCall, null, resolvedCall);
if (method.getAsmMethod().getName().contains("-")) {
Boolean classFileContainsMethod =
InlineClassesCodegenUtilKt.classFileContainsMethod(fd, state, method.getAsmMethod());
if (classFileContainsMethod != null && !classFileContainsMethod) {
typeMapper.setUseOldManglingRulesForFunctionAcceptingInlineClass(true);
method = typeMapper.mapToCallableMethod(fd, superCall, null, resolvedCall);
typeMapper.setUseOldManglingRulesForFunctionAcceptingInlineClass(false);
}
}
return method;
}
public void invokeMethodWithArguments(
@@ -2900,6 +2912,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
sourceCompiler.initializeInlineFunctionContext(functionDescriptor);
JvmMethodSignature signature = typeMapper.mapSignatureWithGeneric(functionDescriptor, sourceCompiler.getContextKind());
if (signature.getAsmMethod().getName().contains("-")) {
Boolean classFileContainsMethod =
InlineClassesCodegenUtilKt.classFileContainsMethod(functionDescriptor, state, signature.getAsmMethod());
if (classFileContainsMethod != null && !classFileContainsMethod) {
typeMapper.setUseOldManglingRulesForFunctionAcceptingInlineClass(true);
signature = typeMapper.mapSignatureWithGeneric(functionDescriptor, sourceCompiler.getContextKind());
typeMapper.setUseOldManglingRulesForFunctionAcceptingInlineClass(false);
}
}
Type methodOwner = typeMapper.mapImplementationOwner(functionDescriptor);
if (isDefaultCompilation) {
return new InlineCodegenForDefaultBody(functionDescriptor, this, state, methodOwner, signature, sourceCompiler);
@@ -5,15 +5,28 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.underlyingRepresentation
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassVisitor
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.commons.Method
fun KotlinType.isInlineClassWithUnderlyingTypeAnyOrAnyN(): Boolean {
if (!isInlineClassType()) return false
@@ -26,4 +39,39 @@ fun CallableDescriptor.isGenericParameter(): Boolean {
if (containingDeclaration is AnonymousFunctionDescriptor) return true
val index = containingDeclaration.valueParameters.indexOf(this)
return containingDeclaration.overriddenDescriptors.any { it.original.valueParameters[index].type.isTypeParameter() }
}
fun classFileContainsMethod(descriptor: FunctionDescriptor, state: GenerationState, method: Method): Boolean? {
if (descriptor !is DeserializedSimpleFunctionDescriptor) return null
val classId: ClassId = when {
descriptor.containingDeclaration is DeserializedClassDescriptor -> {
(descriptor.containingDeclaration as DeserializedClassDescriptor).classId ?: return null
}
descriptor.containerSource is JvmPackagePartSource -> {
(descriptor.containerSource as JvmPackagePartSource).classId
}
else -> {
return null
}
}
val bytes = VirtualFileFinder.getInstance(state.project, state.module).findVirtualFileWithHeader(classId)
?.contentsToByteArray() ?: return null
var found = false
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.API_VERSION) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor? {
if (name == method.name && descriptor == method.descriptor) {
found = true
}
return super.visitMethod(access, name, descriptor, signature, exceptions)
}
}, ClassReader.SKIP_FRAMES)
return found
}
@@ -91,6 +91,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
) : KotlinTypeMapperBase() {
private val isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
val jvmDefaultMode = languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode)
var useOldManglingRulesForFunctionAcceptingInlineClass: Boolean = false
private val typeMappingConfiguration = object : TypeMappingConfiguration<Type> {
override fun commonSupertype(types: Collection<KotlinType>): KotlinType {
@@ -636,7 +637,11 @@ class KotlinTypeMapper @JvmOverloads constructor(
// so that we don't have to repeat the same logic in reflection
// in case of properties without getter methods.
if (kind !== OwnerKind.PROPERTY_REFERENCE_SIGNATURE || descriptor.isPropertyWithGetterSignaturePresent()) {
val suffix = getManglingSuffixBasedOnKotlinSignature(descriptor, shouldMangleByReturnType)
val suffix = getManglingSuffixBasedOnKotlinSignature(
descriptor,
shouldMangleByReturnType,
useOldManglingRulesForFunctionAcceptingInlineClass
)
if (suffix != null) {
newName += suffix
} else if (kind === OwnerKind.ERASED_INLINE_CLASS) {
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -14,14 +13,14 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForParameterTypes
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberOrNullableType
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
import java.security.MessageDigest
import java.util.*
fun getManglingSuffixBasedOnKotlinSignature(
descriptor: CallableMemberDescriptor,
shouldMangleByReturnType: Boolean
shouldMangleByReturnType: Boolean,
useOldManglingRules: Boolean
): String? {
if (descriptor !is FunctionDescriptor) return null
if (descriptor is ConstructorDescriptor) return null
@@ -33,41 +32,76 @@ fun getManglingSuffixBasedOnKotlinSignature(
val unwrappedDescriptor = descriptor.unwrapInitialDescriptorForSuspendFunction()
// If a function accepts inline class parameters, mangle its name.
if (requiresFunctionNameManglingForParameterTypes(descriptor) ||
(shouldMangleByReturnType && requiresFunctionNameManglingForReturnType(unwrappedDescriptor))
) {
if (useOldManglingRules) {
if (requiresFunctionNameManglingForParameterTypes(descriptor)) {
return "-" + md5base64(collectSignatureForMangling(descriptor, useOldManglingRules))
}
// 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) +
if (shouldMangleByReturnType && requiresFunctionNameManglingForReturnType(unwrappedDescriptor))
":" + getSignatureElementForMangling(unwrappedDescriptor.returnType!!)
else ""
return "-" + md5base64(signature)
if (shouldMangleByReturnType) {
if (requiresFunctionNameManglingForReturnType(unwrappedDescriptor)) {
return "-" + md5base64(
":" + getSignatureElementForMangling(
unwrappedDescriptor.returnType!!, useOldManglingRules
)
)
}
}
} 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, useOldManglingRules) +
if (shouldMangleByReturnType && requiresFunctionNameManglingForReturnType(unwrappedDescriptor))
":" + getSignatureElementForMangling(unwrappedDescriptor.returnType!!, useOldManglingRules)
else ""
return "-" + md5base64(signature)
}
}
return null
}
private fun collectSignatureForMangling(descriptor: CallableMemberDescriptor): String {
private fun collectSignatureForMangling(descriptor: CallableMemberDescriptor, useOldManglingRules: Boolean): String {
val types = listOfNotNull(descriptor.extensionReceiverParameter?.type) + descriptor.valueParameters.map { it.type }
return types.joinToString { getSignatureElementForMangling(it) }
return types.joinToString { getSignatureElementForMangling(it, useOldManglingRules) }
}
private fun getSignatureElementForMangling(type: KotlinType): String = buildString {
private fun getSignatureElementForMangling(type: KotlinType, useOldManglingRules: Boolean): String = buildString {
val descriptor = type.constructor.declarationDescriptor ?: return ""
when (descriptor) {
is ClassDescriptor -> if (descriptor.isInline) {
append('L')
append(descriptor.fqNameUnsafe)
if (type.isMarkedNullable) append('?')
append(';')
} else {
append('x')
}
if (useOldManglingRules) {
when (descriptor) {
is ClassDescriptor -> {
append('L')
append(descriptor.fqNameUnsafe)
if (type.isMarkedNullable) append('?')
append(';')
}
is TypeParameterDescriptor -> {
append(getSignatureElementForMangling(descriptor.representativeUpperBound))
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('x')
}
is TypeParameterDescriptor -> {
append(getSignatureElementForMangling(descriptor.representativeUpperBound, useOldManglingRules))
}
}
}
}