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); 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( public void invokeMethodWithArguments(
@@ -2900,6 +2912,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
sourceCompiler.initializeInlineFunctionContext(functionDescriptor); sourceCompiler.initializeInlineFunctionContext(functionDescriptor);
JvmMethodSignature signature = typeMapper.mapSignatureWithGeneric(functionDescriptor, sourceCompiler.getContextKind()); 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); Type methodOwner = typeMapper.mapImplementationOwner(functionDescriptor);
if (isDefaultCompilation) { if (isDefaultCompilation) {
return new InlineCodegenForDefaultBody(functionDescriptor, this, state, methodOwner, signature, sourceCompiler); return new InlineCodegenForDefaultBody(functionDescriptor, this, state, methodOwner, signature, sourceCompiler);
@@ -5,15 +5,28 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor 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.isInlineClassType
import org.jetbrains.kotlin.resolve.underlyingRepresentation 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.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter 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 { fun KotlinType.isInlineClassWithUnderlyingTypeAnyOrAnyN(): Boolean {
if (!isInlineClassType()) return false if (!isInlineClassType()) return false
@@ -27,3 +40,38 @@ fun CallableDescriptor.isGenericParameter(): Boolean {
val index = containingDeclaration.valueParameters.indexOf(this) val index = containingDeclaration.valueParameters.indexOf(this)
return containingDeclaration.overriddenDescriptors.any { it.original.valueParameters[index].type.isTypeParameter() } 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() { ) : KotlinTypeMapperBase() {
private val isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) private val isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
val jvmDefaultMode = languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode) val jvmDefaultMode = languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode)
var useOldManglingRulesForFunctionAcceptingInlineClass: Boolean = false
private val typeMappingConfiguration = object : TypeMappingConfiguration<Type> { private val typeMappingConfiguration = object : TypeMappingConfiguration<Type> {
override fun commonSupertype(types: Collection<KotlinType>): KotlinType { 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 // so that we don't have to repeat the same logic in reflection
// in case of properties without getter methods. // in case of properties without getter methods.
if (kind !== OwnerKind.PROPERTY_REFERENCE_SIGNATURE || descriptor.isPropertyWithGetterSignaturePresent()) { if (kind !== OwnerKind.PROPERTY_REFERENCE_SIGNATURE || descriptor.isPropertyWithGetterSignaturePresent()) {
val suffix = getManglingSuffixBasedOnKotlinSignature(descriptor, shouldMangleByReturnType) val suffix = getManglingSuffixBasedOnKotlinSignature(
descriptor,
shouldMangleByReturnType,
useOldManglingRulesForFunctionAcceptingInlineClass
)
if (suffix != null) { if (suffix != null) {
newName += suffix newName += suffix
} else if (kind === OwnerKind.ERASED_INLINE_CLASS) { } else if (kind === OwnerKind.ERASED_INLINE_CLASS) {
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.codegen.state package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
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.resolve.DescriptorUtils 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.requiresFunctionNameManglingForParameterTypes
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberOrNullableType
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
import java.security.MessageDigest import java.security.MessageDigest
import java.util.* import java.util.*
fun getManglingSuffixBasedOnKotlinSignature( fun getManglingSuffixBasedOnKotlinSignature(
descriptor: CallableMemberDescriptor, descriptor: CallableMemberDescriptor,
shouldMangleByReturnType: Boolean shouldMangleByReturnType: Boolean,
useOldManglingRules: Boolean
): String? { ): String? {
if (descriptor !is FunctionDescriptor) return null if (descriptor !is FunctionDescriptor) return null
if (descriptor is ConstructorDescriptor) return null if (descriptor is ConstructorDescriptor) return null
@@ -33,41 +32,76 @@ fun getManglingSuffixBasedOnKotlinSignature(
val unwrappedDescriptor = descriptor.unwrapInitialDescriptorForSuspendFunction() val unwrappedDescriptor = descriptor.unwrapInitialDescriptorForSuspendFunction()
// If a function accepts inline class parameters, mangle its name. if (useOldManglingRules) {
if (requiresFunctionNameManglingForParameterTypes(descriptor) || if (requiresFunctionNameManglingForParameterTypes(descriptor)) {
(shouldMangleByReturnType && requiresFunctionNameManglingForReturnType(unwrappedDescriptor)) return "-" + md5base64(collectSignatureForMangling(descriptor, useOldManglingRules))
) { }
// If a class member function returns inline class value, mangle its name. // 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', // 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. // should unwrap it and take original return type instead.
val signature = collectSignatureForMangling(descriptor) + if (shouldMangleByReturnType) {
if (shouldMangleByReturnType && requiresFunctionNameManglingForReturnType(unwrappedDescriptor)) if (requiresFunctionNameManglingForReturnType(unwrappedDescriptor)) {
":" + getSignatureElementForMangling(unwrappedDescriptor.returnType!!) return "-" + md5base64(
else "" ":" + getSignatureElementForMangling(
return "-" + md5base64(signature) 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 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 } 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 "" val descriptor = type.constructor.declarationDescriptor ?: return ""
when (descriptor) { if (useOldManglingRules) {
is ClassDescriptor -> if (descriptor.isInline) { when (descriptor) {
append('L') is ClassDescriptor -> {
append(descriptor.fqNameUnsafe) append('L')
if (type.isMarkedNullable) append('?') append(descriptor.fqNameUnsafe)
append(';') if (type.isMarkedNullable) append('?')
} else { append(';')
append('x') }
}
is TypeParameterDescriptor -> { is TypeParameterDescriptor -> {
append(getSignatureElementForMangling(descriptor.representativeUpperBound)) 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))
}
} }
} }
} }