JVM IR: implement MethodSignatureMapper.mapSignature directly

As well as mapFieldSignature, mapReturnType, mapAsmMethod and smaller
methods. This removes yet another dependency on KotlinTypeMapper in the
IR backend.
This commit is contained in:
Alexander Udalov
2019-08-26 14:49:08 +02:00
parent 46ced326b8
commit 36c242764f
3 changed files with 219 additions and 39 deletions
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.firstOverridden
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.Variance
@@ -73,15 +72,18 @@ val CallableDescriptor?.isMethodWithDeclarationSiteWildcards: Boolean
get() {
if (this !is CallableMemberDescriptor) return false
return original.firstOverridden(useOriginal = true) {
METHODS_WITH_DECLARATION_SITE_WILDCARDS.contains(it.propertyIfAccessor.fqNameOrNull())
it.propertyIfAccessor.fqNameOrNull().isMethodWithDeclarationSiteWildcardsFqName
} != null
}
val FqName?.isMethodWithDeclarationSiteWildcardsFqName: Boolean
get() = this in METHODS_WITH_DECLARATION_SITE_WILDCARDS
private fun FqName.child(name: String): FqName = child(Name.identifier(name))
private val METHODS_WITH_DECLARATION_SITE_WILDCARDS = setOf(
BUILTIN_NAMES.mutableCollection.child("addAll"),
BUILTIN_NAMES.mutableList.child("addAll"),
BUILTIN_NAMES.mutableMap.child("putAll")
BUILTIN_NAMES.mutableCollection.child("addAll"),
BUILTIN_NAMES.mutableList.child("addAll"),
BUILTIN_NAMES.mutableMap.child("putAll")
)
fun TypeMappingMode.updateArgumentModeFromAnnotations(
@@ -108,25 +110,35 @@ fun TypeMappingMode.updateArgumentModeFromAnnotations(
}
internal fun extractTypeMappingModeFromAnnotation(
callableDescriptor: CallableDescriptor?,
outerType: KotlinType,
isForAnnotationParameter: Boolean
callableDescriptor: CallableDescriptor?,
outerType: KotlinType,
isForAnnotationParameter: Boolean
): TypeMappingMode? =
(outerType.suppressWildcardsMode(SimpleClassicTypeSystemContext) ?: callableDescriptor?.suppressWildcardsMode())?.let {
if (outerType.arguments.isNotEmpty())
TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
skipDeclarationSiteWildcards = it,
isForAnnotationParameter = isForAnnotationParameter,
needInlineClassWrapping = !outerType.isInlineClassType()
)
else
TypeMappingMode.DEFAULT
}
SimpleClassicTypeSystemContext.extractTypeMappingModeFromAnnotation(
callableDescriptor?.suppressWildcardsMode(), outerType, isForAnnotationParameter
)
fun TypeSystemCommonBackendContext.extractTypeMappingModeFromAnnotation(
callableSuppressWildcardsMode: Boolean?,
outerType: KotlinTypeMarker,
isForAnnotationParameter: Boolean
): TypeMappingMode? {
val suppressWildcards =
outerType.suppressWildcardsMode(this) ?: callableSuppressWildcardsMode ?: return null
if (outerType.argumentsCount() == 0) return TypeMappingMode.DEFAULT
return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
skipDeclarationSiteWildcards = suppressWildcards,
isForAnnotationParameter = isForAnnotationParameter,
needInlineClassWrapping = !outerType.typeConstructor().isInlineClass()
)
}
private fun DeclarationDescriptor.suppressWildcardsMode(): Boolean? =
parentsWithSelf.mapNotNull {
it.annotations.findAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME)
}.firstOrNull()?.suppressWildcardsMode()
parentsWithSelf.mapNotNull {
it.annotations.findAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME)
}.firstOrNull()?.suppressWildcardsMode()
private fun KotlinTypeMarker.suppressWildcardsMode(typeSystem: TypeSystemCommonBackendContext): Boolean? =
with(typeSystem) {
@@ -5,21 +5,35 @@
package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.common.lower.allOverridden
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.replaceValueParametersIn
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.codegen.state.JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.codegen.state.extractTypeMappingModeFromAnnotation
import org.jetbrains.kotlin.codegen.state.isMethodWithDeclarationSiteWildcardsFqName
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunctionBase
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.isFakeOverride
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.java.getOverriddenBuiltinReflectingJvmDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.load.kotlin.forceSingleValueParameterBoxing
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
@@ -27,31 +41,181 @@ import org.jetbrains.org.objectweb.asm.commons.Method
class MethodSignatureMapper(context: JvmBackendContext) {
private val typeMapper: IrTypeMapper = context.typeMapper
private val typeSystem: IrTypeSystemContext = typeMapper.typeSystem
private val kotlinTypeMapper: KotlinTypeMapper = context.state.typeMapper
fun mapAsmMethod(irFunction: IrFunction): Method =
kotlinTypeMapper.mapAsmMethod(irFunction.descriptor)
fun mapAsmMethod(function: IrFunction): Method =
mapSignatureSkipGeneric(function).asmMethod
fun mapFieldSignature(irField: IrField): String? =
kotlinTypeMapper.mapFieldSignature(irField.type.toKotlinType(), irField.descriptor)
fun mapFieldSignature(field: IrField): String? {
val sw = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
if (field.correspondingPropertySymbol?.owner?.isVar == true) {
writeParameterType(sw, field.type, field)
} else {
mapReturnType(field, field.type, sw)
}
return sw.makeJavaGenericSignature()
}
fun mapFunctionName(irFunction: IrFunction): String =
kotlinTypeMapper.mapFunctionName(irFunction.descriptor, OwnerKind.IMPLEMENTATION)
fun mapAnnotationParameterName(field: IrField): String =
kotlinTypeMapper.mapAnnotationParameterName(field.descriptor)
mapFunctionName(field.correspondingPropertySymbol!!.owner.getter ?: error("No getter for annotation property: ${field.render()}"))
fun mapReturnType(irField: IrField): Type =
kotlinTypeMapper.mapReturnType(irField.descriptor)
fun mapReturnType(declaration: IrDeclaration, sw: JvmSignatureWriter? = null): Type {
if (declaration !is IrFunction) {
require(declaration is IrField) { "Unsupported declaration: $declaration" }
return mapReturnType(declaration, declaration.type, sw)
}
fun mapReturnType(irFunction: IrFunction): Type =
kotlinTypeMapper.mapReturnType(irFunction.descriptor)
return when {
hasVoidReturnType(declaration) -> {
sw?.writeAsmType(Type.VOID_TYPE)
Type.VOID_TYPE
}
forceBoxedReturnType(declaration) -> {
typeMapper.mapType(declaration.returnType, TypeMappingMode.RETURN_TYPE_BOXED, sw)
}
else -> mapReturnType(declaration, declaration.returnType, sw)
}
}
fun mapSignatureSkipGeneric(f: IrFunction): JvmMethodSignature =
kotlinTypeMapper.mapSignatureSkipGeneric(f.descriptor, OwnerKind.IMPLEMENTATION)
private fun mapReturnType(declaration: IrDeclaration, returnType: IrType, sw: JvmSignatureWriter?): Type {
val isAnnotationMethod = declaration.parent.let { it is IrClass && it.isAnnotationClass }
if (sw == null || sw.skipGenericSignature()) {
return typeMapper.mapType(returnType, TypeMappingMode.getModeForReturnTypeNoGeneric(isAnnotationMethod), sw)
}
fun mapSignatureWithGeneric(f: IrFunction): JvmMethodGenericSignature =
kotlinTypeMapper.mapSignatureWithGeneric(f.descriptor, OwnerKind.IMPLEMENTATION)
val typeMappingModeFromAnnotation =
typeSystem.extractTypeMappingModeFromAnnotation(declaration.suppressWildcardsMode(), returnType, isAnnotationMethod)
if (typeMappingModeFromAnnotation != null) {
return typeMapper.mapType(returnType, typeMappingModeFromAnnotation, sw)
}
val mappingMode = TypeMappingMode.getOptimalModeForReturnType(returnType.toKotlinType(), isAnnotationMethod)
return typeMapper.mapType(returnType, mappingMode, sw)
}
private fun hasVoidReturnType(function: IrFunction): Boolean =
function is IrConstructor || (function.returnType.isUnit() && !function.isPropertyGetter)
private val IrFunction.isPropertyGetter: Boolean
get() = isPropertyAccessor && valueParameters.isEmpty()
// Copied from KotlinTypeMapper.forceBoxedReturnType.
private fun forceBoxedReturnType(function: IrFunction): Boolean {
if (isBoxMethodForInlineClass(function)) return true
return isJvmPrimitive(function.returnType) &&
function is IrSimpleFunction && function.allOverridden().any { !isJvmPrimitive(it.returnType) }
}
private fun isBoxMethodForInlineClass(function: IrFunction): Boolean =
function.parent.let { it is IrClass && it.isInline } &&
function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_INLINE_CLASS_MEMBER &&
function.name.asString() == "box-impl"
private fun isJvmPrimitive(type: IrType): Boolean {
if (type.isPrimitiveType()) return true
return type.getClass()?.isInline == true && AsmUtil.isPrimitive(typeMapper.mapType(type))
}
fun mapSignatureSkipGeneric(function: IrFunction): JvmMethodSignature =
mapSignature(function, true)
fun mapSignatureWithGeneric(function: IrFunction): JvmMethodGenericSignature =
mapSignature(function, false)
private fun mapSignature(function: IrFunction, skipGenericSignature: Boolean): JvmMethodGenericSignature {
if (function is IrLazyFunctionBase && function.initialSignatureFunction != null) {
// Overrides of special builtin in Kotlin classes always have special signature
if (function.descriptor.getOverriddenBuiltinReflectingJvmDescriptor() == null ||
function.descriptor.containingDeclaration.original is JavaClassDescriptor
) {
return mapSignature(function.initialSignatureFunction!!, skipGenericSignature)
}
}
val sw = if (skipGenericSignature) JvmSignatureWriter() else BothSignatureWriter(BothSignatureWriter.Mode.METHOD)
typeMapper.writeFormalTypeParameters(function.typeParameters, sw)
sw.writeParametersStart()
val receiverParameter = function.extensionReceiverParameter
if (receiverParameter != null) {
writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function)
}
for (parameter in function.valueParameters) {
val type = if (forceSingleValueParameterBoxing(function.descriptor)) parameter.type.makeNullable() else parameter.type
writeParameter(sw, JvmMethodParameterKind.VALUE, type, function)
}
sw.writeReturnType()
mapReturnType(function, sw)
sw.writeReturnTypeEnd()
val signature = sw.makeJvmMethodSignature(mapFunctionName(function))
val specialSignatureInfo = with(BuiltinMethodsWithSpecialGenericSignature) { function.descriptor.getSpecialSignatureInfo() }
if (specialSignatureInfo != null) {
val newGenericSignature = specialSignatureInfo.replaceValueParametersIn(signature.genericsSignature)
return JvmMethodGenericSignature(signature.asmMethod, signature.valueParameters, newGenericSignature)
}
return signature
}
private fun writeParameter(sw: JvmSignatureWriter, kind: JvmMethodParameterKind, type: IrType, function: IrFunction) {
sw.writeParameterType(kind)
writeParameterType(sw, type, function)
sw.writeParameterTypeEnd()
}
private fun writeParameterType(sw: JvmSignatureWriter, type: IrType, declaration: IrDeclaration) {
if (sw.skipGenericSignature()) {
typeMapper.mapType(type, TypeMappingMode.DEFAULT, sw)
return
}
val mode = with(typeSystem) {
extractTypeMappingModeFromAnnotation(declaration.suppressWildcardsMode(), type, isForAnnotationParameter = false)
?: if (declaration.isMethodWithDeclarationSiteWildcards && type.argumentsCount() != 0) {
TypeMappingMode.GENERIC_ARGUMENT // Render all wildcards
} else {
TypeMappingMode.getOptimalModeForValueParameter(type.toKotlinType())
}
}
typeMapper.mapType(type, mode, sw)
}
private val IrDeclaration.isMethodWithDeclarationSiteWildcards: Boolean
get() = this is IrSimpleFunction && allOverridden().any {
it.fqNameWhenAvailable.isMethodWithDeclarationSiteWildcardsFqName
}
private fun IrDeclaration.suppressWildcardsMode(): Boolean? =
parentsWithSelf.mapNotNull { declaration ->
when (declaration) {
is IrField -> {
// Annotations on properties (JvmSuppressWildcards has PROPERTY, not FIELD, in its targets) have been moved
// to the synthetic "$annotations" method, but the copy can still be found via the property symbol.
declaration.correspondingPropertySymbol?.owner?.getSuppressWildcardsAnnotationValue()
}
is IrAnnotationContainer -> declaration.getSuppressWildcardsAnnotationValue()
else -> null
}
}.firstOrNull()
private fun IrAnnotationContainer.getSuppressWildcardsAnnotationValue(): Boolean? =
getAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME)?.run {
if (valueArgumentsCount > 0) (getValueArgument(0) as? IrConst<*>)?.value as? Boolean ?: true else null
}
fun mapToCallableMethod(expression: IrFunctionAccessExpression): IrCallableMethod {
val callee = expression.symbol.owner
@@ -32,6 +32,10 @@ abstract class IrLazyFunctionBase(
IrLazyDeclarationBase(startOffset, endOffset, origin, stubGenerator, typeTranslator),
IrFunction {
val initialSignatureFunction: IrFunction? by lazyVar {
descriptor.initialSignatureDescriptor?.takeIf { it != descriptor }?.original?.let(stubGenerator::generateFunctionStub)
}
override var dispatchReceiverParameter: IrValueParameter? by lazyVar {
typeTranslator.buildWithScope(this) {
descriptor.dispatchReceiverParameter?.generateReceiverParameterStub()?.also { it.parent = this@IrLazyFunctionBase }