JVM IR: move java.lang.annotation symbols to JvmSymbols.javaAnnotations

Since a separate instance of AdditionalClassAnnotationLowering is
created for each source file, symbols for these classes were created as
many times as there were source files in the module.

Also inline some variables in the process and move around some methods.
This commit is contained in:
Alexander Udalov
2021-07-23 21:23:36 +02:00
parent 50f7594d9e
commit 56866e6927
3 changed files with 134 additions and 159 deletions
@@ -8,6 +8,7 @@
package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.ir.addChild
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
import org.jetbrains.kotlin.builtins.StandardNames
@@ -15,23 +16,27 @@ import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_CALL_RESULT_NAME
import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME
import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_FUNCTION_CREATE_METHOD_NAME
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.InlineClassRepresentation
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrEnumEntryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrEnumEntrySymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
@@ -942,6 +947,92 @@ class JvmSymbols(
val runSuspendFunction: IrSimpleFunctionSymbol =
kotlinCoroutinesJvmInternalRunSuspendKt.functionByName("runSuspend")
val javaAnnotations = JavaAnnotations()
inner class JavaAnnotations {
private val javaLangAnnotation: FqName = FqName("java.lang.annotation")
private val javaLangAnnotationPackage: IrPackageFragment =
IrExternalPackageFragmentImpl.createEmptyExternalPackageFragment(context.state.module, javaLangAnnotation)
private fun buildClass(
fqName: FqName,
classKind: ClassKind = ClassKind.ANNOTATION_CLASS,
): IrClass = context.irFactory.buildClass {
check(fqName.parent() == javaLangAnnotation) { fqName }
name = fqName.shortName()
kind = classKind
}.apply {
val irClass = this
parent = javaLangAnnotationPackage
javaLangAnnotationPackage.addChild(this)
thisReceiver = buildValueParameter(this) {
name = Name.identifier("\$this")
type = IrSimpleTypeImpl(irClass.symbol, false, emptyList(), emptyList())
}
}
private fun buildAnnotationConstructor(annotationClass: IrClass): IrConstructor =
annotationClass.addConstructor { isPrimary = true }
private fun buildEnumEntry(enumClass: IrClass, entryName: String): IrEnumEntry {
return IrEnumEntryImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB,
IrEnumEntrySymbolImpl(),
Name.identifier(entryName)
).apply {
parent = enumClass
enumClass.addChild(this)
}
}
val documentedConstructor = buildAnnotationConstructor(buildClass(JvmAnnotationNames.DOCUMENTED_ANNOTATION))
val retentionPolicyEnum = buildClass(JvmAnnotationNames.RETENTION_POLICY_ENUM, classKind = ClassKind.ENUM_CLASS)
val rpRuntime = buildEnumEntry(retentionPolicyEnum, "RUNTIME")
val retentionConstructor = buildAnnotationConstructor(buildClass(JvmAnnotationNames.RETENTION_ANNOTATION)).apply {
addValueParameter("value", retentionPolicyEnum.defaultType, IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB)
}
val elementTypeEnum = buildClass(JvmAnnotationNames.ELEMENT_TYPE_ENUM, classKind = ClassKind.ENUM_CLASS)
private val etMethod = buildEnumEntry(elementTypeEnum, "METHOD")
val targetConstructor = buildAnnotationConstructor(buildClass(JvmAnnotationNames.TARGET_ANNOTATION)).apply {
addValueParameter("value", elementTypeEnum.defaultType, IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB)
}
val repeatableConstructor = buildAnnotationConstructor(buildClass(JvmAnnotationNames.REPEATABLE_ANNOTATION)).apply {
addValueParameter("value", irBuiltIns.kClassClass.starProjectedType, IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB)
}
val annotationRetentionMap = mapOf(
KotlinRetention.SOURCE to buildEnumEntry(retentionPolicyEnum, "SOURCE"),
KotlinRetention.BINARY to buildEnumEntry(retentionPolicyEnum, "CLASS"),
KotlinRetention.RUNTIME to rpRuntime
)
private val jvm6TargetMap = mutableMapOf(
KotlinTarget.CLASS to buildEnumEntry(elementTypeEnum, "TYPE"),
KotlinTarget.ANNOTATION_CLASS to buildEnumEntry(elementTypeEnum, "ANNOTATION_TYPE"),
KotlinTarget.CONSTRUCTOR to buildEnumEntry(elementTypeEnum, "CONSTRUCTOR"),
KotlinTarget.LOCAL_VARIABLE to buildEnumEntry(elementTypeEnum, "LOCAL_VARIABLE"),
KotlinTarget.FUNCTION to etMethod,
KotlinTarget.PROPERTY_GETTER to etMethod,
KotlinTarget.PROPERTY_SETTER to etMethod,
KotlinTarget.FIELD to buildEnumEntry(elementTypeEnum, "FIELD"),
KotlinTarget.VALUE_PARAMETER to buildEnumEntry(elementTypeEnum, "PARAMETER")
)
private val jvm8TargetMap = jvm6TargetMap + mutableMapOf(
KotlinTarget.TYPE_PARAMETER to buildEnumEntry(elementTypeEnum, "TYPE_PARAMETER"),
KotlinTarget.TYPE to buildEnumEntry(elementTypeEnum, "TYPE_USE")
)
fun getAnnotationTargetMap(target: JvmTarget): Map<KotlinTarget, IrEnumEntry> =
if (target == JvmTarget.JVM_1_6) jvm6TargetMap else jvm8TargetMap
}
companion object {
val FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME =
IrBuiltIns.KOTLIN_INTERNAL_IR_FQN.child(Name.identifier("FlexibleNullability"))
@@ -6,22 +6,13 @@
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.ir.addChild
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrEnumEntryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue
@@ -29,15 +20,12 @@ import org.jetbrains.kotlin.ir.expressions.IrVararg
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetEnumValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrEnumEntrySymbolImpl
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.getAnnotation
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.isAnnotationClass
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.lang.annotation.ElementType
@@ -49,76 +37,7 @@ internal val additionalClassAnnotationPhase = makeIrFilePhase(
)
private class AdditionalClassAnnotationLowering(private val context: JvmBackendContext) : ClassLoweringPass {
private val jvmTarget = context.state.target
// TODO: import IR structures from the library?
private val annotationPackage: IrPackageFragment = IrExternalPackageFragmentImpl.createEmptyExternalPackageFragment(
context.ir.irModule.descriptor,
FqName("java.lang.annotation")
)
private fun buildAnnotationClass(
className: String,
classKind: ClassKind = ClassKind.ANNOTATION_CLASS
): IrClass = context.irFactory.buildClass {
name = Name.identifier(className)
kind = classKind
}.apply {
val irClass = this
parent = annotationPackage
annotationPackage.addChild(this)
thisReceiver = buildValueParameter(this) {
name = Name.identifier("\$this")
type = IrSimpleTypeImpl(irClass.symbol, false, emptyList(), emptyList())
}
}
private fun buildAnnotationConstructor(annotationClass: IrClass): IrConstructor = context.irFactory.buildConstructor {
isPrimary = true
}.apply {
parent = annotationClass
annotationClass.addChild(this)
returnType = annotationClass.defaultType
}
private fun buildEnumEntry(enumClass: IrClass, entryName: String): IrEnumEntry {
return IrEnumEntryImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB,
IrEnumEntrySymbolImpl(),
Name.identifier(entryName)
).apply {
parent = enumClass
enumClass.addChild(this)
}
}
private val documentedConstructor = buildAnnotationConstructor(buildAnnotationClass("Documented"))
private val retentionPolicyEnum = buildAnnotationClass("RetentionPolicy", classKind = ClassKind.ENUM_CLASS)
private val rpSource = buildEnumEntry(retentionPolicyEnum, "SOURCE")
private val rpClass = buildEnumEntry(retentionPolicyEnum, "CLASS")
private val rpRuntime = buildEnumEntry(retentionPolicyEnum, "RUNTIME")
private val retentionConstructor = buildAnnotationConstructor(buildAnnotationClass("Retention")).apply {
addValueParameter("value", retentionPolicyEnum.defaultType, IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB)
}
private val elementTypeEnum = buildAnnotationClass("ElementType", classKind = ClassKind.ENUM_CLASS)
private val etAnnotationType = buildEnumEntry(elementTypeEnum, "ANNOTATION_TYPE")
private val etConstructor = buildEnumEntry(elementTypeEnum, "CONSTRUCTOR")
private val etField = buildEnumEntry(elementTypeEnum, "FIELD")
private val etLocalVariable = buildEnumEntry(elementTypeEnum, "LOCAL_VARIABLE")
private val etMethod = buildEnumEntry(elementTypeEnum, "METHOD")
private val etParameter = buildEnumEntry(elementTypeEnum, "PARAMETER")
private val etType = buildEnumEntry(elementTypeEnum, "TYPE")
private val etTypeParameter = buildEnumEntry(elementTypeEnum, "TYPE_PARAMETER")
private val etTypeUse = buildEnumEntry(elementTypeEnum, "TYPE_USE")
private val targetConstructor = buildAnnotationConstructor(buildAnnotationClass("Target")).apply {
addValueParameter("value", elementTypeEnum.defaultType, IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB)
}
private val symbols = context.ir.symbols.javaAnnotations
override fun lower(irClass: IrClass) {
if (!irClass.isAnnotationClass) return
@@ -130,68 +49,39 @@ private class AdditionalClassAnnotationLowering(private val context: JvmBackendC
private fun generateDocumentedAnnotation(irClass: IrClass) {
if (!irClass.hasAnnotation(StandardNames.FqNames.mustBeDocumented) ||
irClass.hasAnnotation(FqName("java.lang.annotation.Documented"))
irClass.hasAnnotation(JvmAnnotationNames.DOCUMENTED_ANNOTATION)
) return
irClass.annotations +=
IrConstructorCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, documentedConstructor.returnType, documentedConstructor.symbol, 0
UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbols.documentedConstructor.returnType, symbols.documentedConstructor.symbol, 0
)
}
private val annotationRetentionMap = mapOf(
KotlinRetention.SOURCE to rpSource,
KotlinRetention.BINARY to rpClass,
KotlinRetention.RUNTIME to rpRuntime
)
private fun generateRetentionAnnotation(irClass: IrClass) {
if (irClass.hasAnnotation(FqName("java.lang.annotation.Retention"))) return
val kotlinRetentionPolicyCall = irClass.getAnnotation(FqName("kotlin.annotation.Retention"))
if (irClass.hasAnnotation(JvmAnnotationNames.RETENTION_ANNOTATION)) return
val kotlinRetentionPolicyCall = irClass.getAnnotation(StandardNames.FqNames.retention)
val kotlinRetentionPolicyName =
kotlinRetentionPolicyCall?.getValueArgument(0)?.safeAs<IrGetEnumValue>()?.symbol?.owner?.name?.asString()
val kotlinRetentionPolicy = kotlinRetentionPolicyName?.let { KotlinRetention.valueOf(it) }
val javaRetentionPolicy = kotlinRetentionPolicy?.let { annotationRetentionMap[it] } ?: rpRuntime
val javaRetentionPolicy = kotlinRetentionPolicy?.let { symbols.annotationRetentionMap[it] } ?: symbols.rpRuntime
irClass.annotations +=
IrConstructorCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, retentionConstructor.returnType, retentionConstructor.symbol, 0
UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbols.retentionConstructor.returnType, symbols.retentionConstructor.symbol, 0
).apply {
putValueArgument(
0,
IrGetEnumValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, retentionPolicyEnum.defaultType, javaRetentionPolicy.symbol
UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbols.retentionPolicyEnum.defaultType, javaRetentionPolicy.symbol
)
)
}
}
private val jvm6TargetMap = mutableMapOf(
KotlinTarget.CLASS to etType,
KotlinTarget.ANNOTATION_CLASS to etAnnotationType,
KotlinTarget.CONSTRUCTOR to etConstructor,
KotlinTarget.LOCAL_VARIABLE to etLocalVariable,
KotlinTarget.FUNCTION to etMethod,
KotlinTarget.PROPERTY_GETTER to etMethod,
KotlinTarget.PROPERTY_SETTER to etMethod,
KotlinTarget.FIELD to etField,
KotlinTarget.VALUE_PARAMETER to etParameter
)
private val jvm8TargetMap = jvm6TargetMap + mutableMapOf(
KotlinTarget.TYPE_PARAMETER to etTypeParameter,
KotlinTarget.TYPE to etTypeUse
)
private val annotationTargetMaps: Map<JvmTarget, Map<KotlinTarget, IrEnumEntry>> =
JvmTarget.values().associate { target ->
target to (if (target == JvmTarget.JVM_1_6) jvm6TargetMap else jvm8TargetMap)
}
private fun generateTargetAnnotation(irClass: IrClass) {
if (irClass.hasAnnotation(JvmAnnotationNames.TARGET_ANNOTATION)) return
val annotationTargetMap = annotationTargetMaps[jvmTarget]
?: throw AssertionError("No annotation target map for JVM target $jvmTarget")
val annotationTargetMap = symbols.getAnnotationTargetMap(context.state.target)
val targets = irClass.applicableTargetSet() ?: return
val javaTargets = targets.mapNotNullTo(HashSet()) { annotationTargetMap[it] }.sortedBy {
@@ -200,46 +90,40 @@ private class AdditionalClassAnnotationLowering(private val context: JvmBackendC
val vararg = IrVarargImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
type = context.irBuiltIns.arrayClass.typeWith(elementTypeEnum.defaultType),
varargElementType = elementTypeEnum.defaultType
type = context.irBuiltIns.arrayClass.typeWith(symbols.elementTypeEnum.defaultType),
varargElementType = symbols.elementTypeEnum.defaultType
)
for (target in javaTargets) {
vararg.elements.add(
IrGetEnumValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, elementTypeEnum.defaultType, target.symbol
UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbols.elementTypeEnum.defaultType, target.symbol
)
)
}
irClass.annotations +=
IrConstructorCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, targetConstructor.returnType, targetConstructor.symbol, 0
UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbols.targetConstructor.returnType, symbols.targetConstructor.symbol, 0
).apply {
putValueArgument(0, vararg)
}
// TODO
}
private fun IrConstructorCall.getValueArgument(name: Name): IrExpression? {
val index = symbol.owner.valueParameters.find { it.name == name }?.index ?: return null
return getValueArgument(index)
}
private fun IrClass.applicableTargetSet(): Set<KotlinTarget>? {
val targetEntry = getAnnotation(StandardNames.FqNames.target) ?: return null
return loadAnnotationTargets(targetEntry)
}
private fun loadAnnotationTargets(targetEntry: IrConstructorCall): Set<KotlinTarget>? {
val valueArgument = targetEntry.getValueArgument(Name.identifier(Target::allowedTargets.name))
as? IrVararg ?: return null
return valueArgument.elements.filterIsInstance<IrGetEnumValue>().mapNotNull {
KotlinTarget.valueOrNull(it.symbol.owner.name.asString())
}.toSet()
}
}
// To be generalized to IrMemberAccessExpression as soon as properties get symbols.
private fun IrConstructorCall.getValueArgument(name: Name): IrExpression? {
val index = symbol.owner.valueParameters.find { it.name == name }?.index ?: return null
return getValueArgument(index)
}
// Copied and modified from AnnotationChecker.kt
private val TARGET_ALLOWED_TARGETS = Name.identifier("allowedTargets")
private fun IrClass.applicableTargetSet(): Set<KotlinTarget>? {
val targetEntry = getAnnotation(StandardNames.FqNames.target) ?: return null
return loadAnnotationTargets(targetEntry)
}
private fun loadAnnotationTargets(targetEntry: IrConstructorCall): Set<KotlinTarget>? {
val valueArgument = targetEntry.getValueArgument(TARGET_ALLOWED_TARGETS)
as? IrVararg ?: return null
return valueArgument.elements.filterIsInstance<IrGetEnumValue>().mapNotNull {
KotlinTarget.valueOrNull(it.symbol.owner.name.asString())
}.toSet()
}
@@ -20,9 +20,7 @@ import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.*;
@SuppressWarnings("PointlessBitwiseExpression")
public final class JvmAnnotationNames {
@@ -49,10 +47,12 @@ public final class JvmAnnotationNames {
public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
public static final FqName TARGET_ANNOTATION = new FqName(Target.class.getCanonicalName());
public static final FqName RETENTION_ANNOTATION = new FqName(Retention.class.getCanonicalName());
public static final FqName DEPRECATED_ANNOTATION = new FqName(Deprecated.class.getCanonicalName());
public static final FqName DOCUMENTED_ANNOTATION = new FqName(Documented.class.getCanonicalName());
public static final FqName TARGET_ANNOTATION = new FqName(Target.class.getName());
public static final FqName ELEMENT_TYPE_ENUM = new FqName(ElementType.class.getName());
public static final FqName RETENTION_ANNOTATION = new FqName(Retention.class.getName());
public static final FqName RETENTION_POLICY_ENUM = new FqName(RetentionPolicy.class.getName());
public static final FqName DEPRECATED_ANNOTATION = new FqName(Deprecated.class.getName());
public static final FqName DOCUMENTED_ANNOTATION = new FqName(Documented.class.getName());
public static final FqName REPEATABLE_ANNOTATION = new FqName("java.lang.annotation.Repeatable");
public static final FqName JETBRAINS_NOT_NULL_ANNOTATION = new FqName("org.jetbrains.annotations.NotNull");