IR: separate ClassCodegen & DescriptorBasedClassCodegen
This commit is contained in:
+7
-88
@@ -11,10 +11,8 @@ import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
|
|||||||
import org.jetbrains.kotlin.backend.jvm.lower.buildAssertionsDisabledField
|
import org.jetbrains.kotlin.backend.jvm.lower.buildAssertionsDisabledField
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.hasAssertionsDisabledField
|
import org.jetbrains.kotlin.backend.jvm.lower.hasAssertionsDisabledField
|
||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.*
|
import org.jetbrains.kotlin.codegen.inline.*
|
||||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
|
||||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
|
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
@@ -30,8 +28,6 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
|
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
|
||||||
@@ -40,23 +36,22 @@ import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME
|
|||||||
import org.jetbrains.kotlin.resolve.jvm.checkers.JvmSimpleNameBacktickChecker
|
import org.jetbrains.kotlin.resolve.jvm.checkers.JvmSimpleNameBacktickChecker
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.*
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature
|
||||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class ClassCodegen private constructor(
|
abstract class ClassCodegen protected constructor(
|
||||||
internal val irClass: IrClass,
|
internal val irClass: IrClass,
|
||||||
val context: JvmBackendContext,
|
val context: JvmBackendContext,
|
||||||
private val parentFunction: IrFunction? = null
|
private val parentFunction: IrFunction? = null
|
||||||
) : InnerClassConsumer {
|
) : InnerClassConsumer {
|
||||||
private val parentClassCodegen = (parentFunction?.parentAsClass ?: irClass.parent as? IrClass)?.let { getOrCreate(it, context) }
|
protected val parentClassCodegen = (parentFunction?.parentAsClass ?: irClass.parent as? IrClass)?.let { getOrCreate(it, context) }
|
||||||
private val withinInline: Boolean = parentClassCodegen?.withinInline == true || parentFunction?.isInline == true
|
private val withinInline: Boolean = parentClassCodegen?.withinInline == true || parentFunction?.isInline == true
|
||||||
|
|
||||||
private val state get() = context.state
|
protected val state get() = context.state
|
||||||
private val typeMapper get() = context.typeMapper
|
protected val typeMapper get() = context.typeMapper
|
||||||
|
|
||||||
val type: Type = typeMapper.mapClass(irClass)
|
val type: Type = typeMapper.mapClass(irClass)
|
||||||
|
|
||||||
@@ -79,7 +74,7 @@ class ClassCodegen private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val visitor = state.factory.newVisitor(classOrigin, type, irClass.fileParent.loadSourceFilesInfo()).apply {
|
protected val visitor = state.factory.newVisitor(classOrigin, type, irClass.fileParent.loadSourceFilesInfo()).apply {
|
||||||
val signature = getSignature(irClass, type, irClass.getSuperClassInfo(typeMapper), typeMapper)
|
val signature = getSignature(irClass, type, irClass.getSuperClassInfo(typeMapper), typeMapper)
|
||||||
// Ensure that the backend only produces class names that would be valid in the frontend for JVM.
|
// Ensure that the backend only produces class names that would be valid in the frontend for JVM.
|
||||||
if (context.state.classBuilderMode.generateBodies && signature.hasInvalidName()) {
|
if (context.state.classBuilderMode.generateBodies && signature.hasInvalidName()) {
|
||||||
@@ -98,15 +93,6 @@ class ClassCodegen private constructor(
|
|||||||
|
|
||||||
internal var writeSourceMap: Boolean = withinInline
|
internal var writeSourceMap: Boolean = withinInline
|
||||||
|
|
||||||
private val serializerExtension = JvmSerializerExtension(visitor.serializationBindings, state, typeMapper)
|
|
||||||
private val serializer: DescriptorSerializer? =
|
|
||||||
when (val metadata = irClass.metadata) {
|
|
||||||
is MetadataSource.Class -> DescriptorSerializer.create(metadata.descriptor, serializerExtension, parentClassCodegen?.serializer)
|
|
||||||
is MetadataSource.File -> DescriptorSerializer.createTopLevel(serializerExtension)
|
|
||||||
is MetadataSource.Function -> DescriptorSerializer.createForLambda(serializerExtension)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
private var regeneratedObjectNameGenerators = mutableMapOf<String, NameGenerator>()
|
private var regeneratedObjectNameGenerators = mutableMapOf<String, NameGenerator>()
|
||||||
|
|
||||||
fun getRegeneratedObjectNameGenerator(function: IrFunction): NameGenerator {
|
fun getRegeneratedObjectNameGenerator(function: IrFunction): NameGenerator {
|
||||||
@@ -205,74 +191,7 @@ class ClassCodegen private constructor(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateKotlinMetadataAnnotation() {
|
abstract protected fun generateKotlinMetadataAnnotation()
|
||||||
val localDelegatedProperties = (irClass.attributeOwnerId as? IrClass)?.let(context.localDelegatedProperties::get)
|
|
||||||
if (localDelegatedProperties != null && localDelegatedProperties.isNotEmpty()) {
|
|
||||||
state.bindingTrace.record(CodegenBinding.DELEGATED_PROPERTIES_WITH_METADATA, type, localDelegatedProperties.map { it.descriptor })
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: if `-Xmultifile-parts-inherit` is enabled, write the corresponding flag for parts and facades to [Metadata.extraInt].
|
|
||||||
var extraFlags = JvmAnnotationNames.METADATA_JVM_IR_FLAG
|
|
||||||
if (state.isIrWithStableAbi) {
|
|
||||||
extraFlags += JvmAnnotationNames.METADATA_JVM_IR_STABLE_ABI_FLAG
|
|
||||||
}
|
|
||||||
|
|
||||||
when (val metadata = irClass.metadata) {
|
|
||||||
is MetadataSource.Class -> {
|
|
||||||
val classProto = serializer!!.classProto(metadata.descriptor).build()
|
|
||||||
writeKotlinMetadata(visitor, state, KotlinClassHeader.Kind.CLASS, extraFlags) {
|
|
||||||
AsmUtil.writeAnnotationData(it, serializer, classProto)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(irClass !in context.classNameOverride) {
|
|
||||||
"JvmPackageName is not supported for classes: ${irClass.render()}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is MetadataSource.File -> {
|
|
||||||
val packageFqName = irClass.getPackageFragment()!!.fqName
|
|
||||||
val packageProto = serializer!!.packagePartProto(packageFqName, metadata.descriptors)
|
|
||||||
|
|
||||||
serializerExtension.serializeJvmPackage(packageProto, type)
|
|
||||||
|
|
||||||
val facadeClassName = context.multifileFacadeForPart[irClass.attributeOwnerId]
|
|
||||||
val kind = if (facadeClassName != null) KotlinClassHeader.Kind.MULTIFILE_CLASS_PART else KotlinClassHeader.Kind.FILE_FACADE
|
|
||||||
writeKotlinMetadata(visitor, state, kind, extraFlags) { av ->
|
|
||||||
AsmUtil.writeAnnotationData(av, serializer, packageProto.build())
|
|
||||||
|
|
||||||
if (facadeClassName != null) {
|
|
||||||
av.visit(JvmAnnotationNames.METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME, facadeClassName.internalName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (irClass in context.classNameOverride) {
|
|
||||||
av.visit(JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME, irClass.fqNameWhenAvailable!!.parent().asString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is MetadataSource.Function -> {
|
|
||||||
val fakeDescriptor = createFreeFakeLambdaDescriptor(metadata.descriptor)
|
|
||||||
val functionProto = serializer!!.functionProto(fakeDescriptor)?.build()
|
|
||||||
writeKotlinMetadata(visitor, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, extraFlags) {
|
|
||||||
if (functionProto != null) {
|
|
||||||
AsmUtil.writeAnnotationData(it, serializer, functionProto)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
val entry = irClass.fileParent.fileEntry
|
|
||||||
if (entry is MultifileFacadeFileEntry) {
|
|
||||||
val partInternalNames = entry.partFiles.mapNotNull { partFile ->
|
|
||||||
val fileClass = partFile.declarations.singleOrNull { it.isFileClass } as IrClass?
|
|
||||||
if (fileClass != null) typeMapper.mapClass(fileClass).internalName else null
|
|
||||||
}
|
|
||||||
MultifileClassCodegenImpl.writeMetadata(
|
|
||||||
visitor, state, extraFlags, partInternalNames, type, irClass.fqNameWhenAvailable!!.parent()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
writeSyntheticClassMetadata(visitor, state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrFile.loadSourceFilesInfo(): List<File> {
|
private fun IrFile.loadSourceFilesInfo(): List<File> {
|
||||||
val entry = fileEntry
|
val entry = fileEntry
|
||||||
@@ -285,7 +204,7 @@ class ClassCodegen private constructor(
|
|||||||
companion object {
|
companion object {
|
||||||
fun getOrCreate(irClass: IrClass, context: JvmBackendContext, parentFunction: IrFunction? = null): ClassCodegen =
|
fun getOrCreate(irClass: IrClass, context: JvmBackendContext, parentFunction: IrFunction? = null): ClassCodegen =
|
||||||
context.classCodegens.getOrPut(irClass) {
|
context.classCodegens.getOrPut(irClass) {
|
||||||
ClassCodegen(irClass, context, parentFunction)
|
DescriptorBasedClassCodegen(irClass, context, parentFunction)
|
||||||
}.also {
|
}.also {
|
||||||
assert(parentFunction == null || it.parentFunction == parentFunction) {
|
assert(parentFunction == null || it.parentFunction == parentFunction) {
|
||||||
"inconsistent parent function for ${irClass.render()}:\n" +
|
"inconsistent parent function for ${irClass.render()}:\n" +
|
||||||
|
|||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.backend.jvm.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
|
||||||
|
import org.jetbrains.kotlin.codegen.*
|
||||||
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||||
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.MetadataSource
|
||||||
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
|
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||||
|
import org.jetbrains.kotlin.ir.util.isFileClass
|
||||||
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||||
|
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||||
|
|
||||||
|
class DescriptorBasedClassCodegen internal constructor(
|
||||||
|
irClass: IrClass,
|
||||||
|
context: JvmBackendContext,
|
||||||
|
parentFunction: IrFunction? = null
|
||||||
|
) : ClassCodegen(irClass, context, parentFunction) {
|
||||||
|
|
||||||
|
private val serializerExtension = JvmSerializerExtension(visitor.serializationBindings, state, typeMapper)
|
||||||
|
private val serializer: DescriptorSerializer? =
|
||||||
|
when (val metadata = irClass.metadata) {
|
||||||
|
is MetadataSource.Class -> DescriptorSerializer.create(
|
||||||
|
metadata.descriptor, serializerExtension, (parentClassCodegen as? DescriptorBasedClassCodegen)?.serializer
|
||||||
|
)
|
||||||
|
is MetadataSource.File -> DescriptorSerializer.createTopLevel(serializerExtension)
|
||||||
|
is MetadataSource.Function -> DescriptorSerializer.createForLambda(serializerExtension)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateKotlinMetadataAnnotation() {
|
||||||
|
|
||||||
|
val localDelegatedProperties = (irClass.attributeOwnerId as? IrClass)?.let(context.localDelegatedProperties::get)
|
||||||
|
if (localDelegatedProperties != null && localDelegatedProperties.isNotEmpty()) {
|
||||||
|
state.bindingTrace.record(
|
||||||
|
CodegenBinding.DELEGATED_PROPERTIES_WITH_METADATA, type, localDelegatedProperties.map { it.descriptor }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: if `-Xmultifile-parts-inherit` is enabled, write the corresponding flag for parts and facades to [Metadata.extraInt].
|
||||||
|
var extraFlags = JvmAnnotationNames.METADATA_JVM_IR_FLAG
|
||||||
|
if (state.isIrWithStableAbi) {
|
||||||
|
extraFlags += JvmAnnotationNames.METADATA_JVM_IR_STABLE_ABI_FLAG
|
||||||
|
}
|
||||||
|
|
||||||
|
when (val metadata = irClass.metadata) {
|
||||||
|
is MetadataSource.Class -> {
|
||||||
|
val classProto = serializer!!.classProto(metadata.descriptor).build()
|
||||||
|
writeKotlinMetadata(visitor, state, KotlinClassHeader.Kind.CLASS, extraFlags) {
|
||||||
|
AsmUtil.writeAnnotationData(it, serializer, classProto)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(irClass !in context.classNameOverride) {
|
||||||
|
"JvmPackageName is not supported for classes: ${irClass.render()}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is MetadataSource.File -> {
|
||||||
|
val packageFqName = irClass.getPackageFragment()!!.fqName
|
||||||
|
val packageProto = serializer!!.packagePartProto(packageFqName, metadata.descriptors)
|
||||||
|
|
||||||
|
serializerExtension.serializeJvmPackage(packageProto, type)
|
||||||
|
|
||||||
|
val facadeClassName = context.multifileFacadeForPart[irClass.attributeOwnerId]
|
||||||
|
val kind = if (facadeClassName != null) KotlinClassHeader.Kind.MULTIFILE_CLASS_PART else KotlinClassHeader.Kind.FILE_FACADE
|
||||||
|
writeKotlinMetadata(visitor, state, kind, extraFlags) { av ->
|
||||||
|
AsmUtil.writeAnnotationData(av, serializer, packageProto.build())
|
||||||
|
|
||||||
|
if (facadeClassName != null) {
|
||||||
|
av.visit(JvmAnnotationNames.METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME, facadeClassName.internalName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irClass in context.classNameOverride) {
|
||||||
|
av.visit(JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME, irClass.fqNameWhenAvailable!!.parent().asString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is MetadataSource.Function -> {
|
||||||
|
val fakeDescriptor = createFreeFakeLambdaDescriptor(metadata.descriptor)
|
||||||
|
val functionProto = serializer!!.functionProto(fakeDescriptor)?.build()
|
||||||
|
writeKotlinMetadata(visitor, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, extraFlags) {
|
||||||
|
if (functionProto != null) {
|
||||||
|
AsmUtil.writeAnnotationData(it, serializer, functionProto)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val entry = irClass.fileParent.fileEntry
|
||||||
|
if (entry is MultifileFacadeFileEntry) {
|
||||||
|
val partInternalNames = entry.partFiles.mapNotNull { partFile ->
|
||||||
|
val fileClass = partFile.declarations.singleOrNull { it.isFileClass } as IrClass?
|
||||||
|
if (fileClass != null) typeMapper.mapClass(fileClass).internalName else null
|
||||||
|
}
|
||||||
|
MultifileClassCodegenImpl.writeMetadata(
|
||||||
|
visitor, state, extraFlags, partInternalNames, type, irClass.fqNameWhenAvailable!!.parent()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
writeSyntheticClassMetadata(visitor, state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user