Introduce & use FirJvmSerializerExtension & FirBasedClassCodegen
#KT-38156 In Process
This commit is contained in:
@@ -5,6 +5,9 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
compile(project(":kotlin-annotations-jvm"))
|
||||
compile(project(":compiler:fir:fir-serialization"))
|
||||
compile(project(":compiler:fir:fir2ir"))
|
||||
compile(project(":compiler:fir:fir2ir:jvm-backend"))
|
||||
compile(project(":compiler:backend"))
|
||||
compile(project(":compiler:ir.tree"))
|
||||
compile(project(":compiler:ir.psi2ir"))
|
||||
|
||||
+12
-23
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.backend.FirMetadataSource
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedClassDescriptor
|
||||
@@ -204,7 +205,11 @@ abstract class ClassCodegen protected constructor(
|
||||
companion object {
|
||||
fun getOrCreate(irClass: IrClass, context: JvmBackendContext, parentFunction: IrFunction? = null): ClassCodegen =
|
||||
context.classCodegens.getOrPut(irClass) {
|
||||
DescriptorBasedClassCodegen(irClass, context, parentFunction)
|
||||
if (irClass.metadata is FirMetadataSource) {
|
||||
FirBasedClassCodegen(irClass, context, parentFunction)
|
||||
} else {
|
||||
DescriptorBasedClassCodegen(irClass, context, parentFunction)
|
||||
}
|
||||
}.also {
|
||||
assert(parentFunction == null || it.parentFunction == parentFunction) {
|
||||
"inconsistent parent function for ${irClass.render()}:\n" +
|
||||
@@ -217,6 +222,8 @@ abstract class ClassCodegen protected constructor(
|
||||
name.splitToSequence('/').any { identifier -> identifier.any { it in JvmSimpleNameBacktickChecker.INVALID_CHARS } }
|
||||
}
|
||||
|
||||
protected abstract fun bindFieldMetadata(field: IrField, fieldType: Type, fieldName: String)
|
||||
|
||||
private fun generateField(field: IrField) {
|
||||
if (field.isFakeOverride) return
|
||||
|
||||
@@ -244,10 +251,7 @@ abstract class ClassCodegen protected constructor(
|
||||
}.genAnnotations(field, fieldType, field.type)
|
||||
}
|
||||
|
||||
val descriptor = field.metadata?.descriptor
|
||||
if (descriptor != null) {
|
||||
state.globalSerializationBindings.put(JvmSerializationBindings.FIELD_FOR_PROPERTY, descriptor, fieldType to fieldName)
|
||||
}
|
||||
bindFieldMetadata(field, fieldType, fieldName)
|
||||
}
|
||||
|
||||
private val generatedInlineMethods = mutableMapOf<IrFunction, SMAPAndMethodNode>()
|
||||
@@ -266,6 +270,8 @@ abstract class ClassCodegen protected constructor(
|
||||
return SMAPAndMethodNode(copy, smap)
|
||||
}
|
||||
|
||||
protected abstract fun bindMethodMetadata(method: IrFunction, signature: Method)
|
||||
|
||||
private fun generateMethod(method: IrFunction, classSMAP: DefaultSourceMapper) {
|
||||
if (method.isFakeOverride) {
|
||||
jvmSignatureClashDetector.trackFakeOverrideMethod(method)
|
||||
@@ -299,24 +305,7 @@ abstract class ClassCodegen protected constructor(
|
||||
jvmSignatureClashDetector.trackMethod(method, RawSignature(node.name, node.desc, MemberKind.METHOD))
|
||||
|
||||
val signature = Method(node.name, node.desc)
|
||||
when (val metadata = method.metadata) {
|
||||
is MetadataSource.Property -> {
|
||||
// We can't check for JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS because for interface methods
|
||||
// moved to DefaultImpls, origin is changed to DEFAULT_IMPLS
|
||||
// TODO: fix origin somehow, because otherwise $annotations methods in interfaces also don't have ACC_SYNTHETIC
|
||||
assert(method.name.asString().endsWith(JvmAbi.ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX)) { method.dump() }
|
||||
|
||||
state.globalSerializationBindings.put(
|
||||
JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY, metadata.descriptor, signature
|
||||
)
|
||||
}
|
||||
is MetadataSource.Function -> {
|
||||
visitor.serializationBindings.put(JvmSerializationBindings.METHOD_FOR_FUNCTION, metadata.descriptor, signature)
|
||||
}
|
||||
null -> {
|
||||
}
|
||||
else -> error("Incorrect metadata source $metadata for:\n${method.dump()}")
|
||||
}
|
||||
bindMethodMetadata(method, signature)
|
||||
}
|
||||
|
||||
private fun generateInnerAndOuterClasses() {
|
||||
|
||||
+33
-4
@@ -9,17 +9,19 @@ 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.JvmSerializationBindings
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
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.ir.util.*
|
||||
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.serialization.DescriptorSerializer
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
|
||||
class DescriptorBasedClassCodegen internal constructor(
|
||||
irClass: IrClass,
|
||||
@@ -110,4 +112,31 @@ class DescriptorBasedClassCodegen internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindMethodMetadata(method: IrFunction, signature: Method) {
|
||||
when (val metadata = method.metadata) {
|
||||
is MetadataSource.Property -> {
|
||||
// We can't check for JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS because for interface methods
|
||||
// moved to DefaultImpls, origin is changed to DEFAULT_IMPLS
|
||||
// TODO: fix origin somehow, because otherwise $annotations methods in interfaces also don't have ACC_SYNTHETIC
|
||||
assert(method.name.asString().endsWith(JvmAbi.ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX)) { method.dump() }
|
||||
|
||||
state.globalSerializationBindings.put(
|
||||
JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY, metadata.descriptor, signature
|
||||
)
|
||||
}
|
||||
is MetadataSource.Function -> {
|
||||
visitor.serializationBindings.put(JvmSerializationBindings.METHOD_FOR_FUNCTION, metadata.descriptor, signature)
|
||||
}
|
||||
null -> {
|
||||
}
|
||||
else -> error("Incorrect metadata source $metadata for:\n${method.dump()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindFieldMetadata(field: IrField, fieldType: Type, fieldName: String) {
|
||||
val descriptor = field.metadata?.descriptor
|
||||
if (descriptor != null) {
|
||||
state.globalSerializationBindings.put(JvmSerializationBindings.FIELD_FOR_PROPERTY, descriptor, fieldType to fieldName)
|
||||
}
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.JvmSerializationBindings
|
||||
import org.jetbrains.kotlin.fir.backend.FirMetadataSource
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmSerializerExtension
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.serialization.FirElementSerializer
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isFileClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
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.metadata.jvm.serialization.JvmStringTable
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
|
||||
class FirBasedClassCodegen internal constructor(
|
||||
irClass: IrClass,
|
||||
context: JvmBackendContext,
|
||||
parentFunction: IrFunction? = null
|
||||
) : ClassCodegen(irClass, context, parentFunction) {
|
||||
|
||||
private val session = (irClass.metadata as FirMetadataSource).session
|
||||
|
||||
private val serializerExtension = FirJvmSerializerExtension(session, visitor.serializationBindings, state, typeMapper)
|
||||
private val serializer: FirElementSerializer? =
|
||||
when (val metadata = irClass.metadata) {
|
||||
is FirMetadataSource.Class -> FirElementSerializer.create(
|
||||
metadata.klass, serializerExtension, (parentClassCodegen as? FirBasedClassCodegen)?.serializer
|
||||
)
|
||||
is FirMetadataSource.Function -> FirElementSerializer.createForLambda(session, serializerExtension)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun FirFunction<*>.copyToFreeAnonymousFunction(): FirAnonymousFunction {
|
||||
val function = this
|
||||
return buildAnonymousFunction {
|
||||
session = function.session
|
||||
symbol = FirAnonymousFunctionSymbol()
|
||||
returnTypeRef = function.returnTypeRef
|
||||
receiverTypeRef = function.receiverTypeRef
|
||||
isLambda = false
|
||||
valueParameters.addAll(function.valueParameters)
|
||||
typeParameters.addAll(function.typeParameters.filterIsInstance<FirTypeParameter>())
|
||||
}
|
||||
}
|
||||
|
||||
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 FirMetadataSource.Class -> {
|
||||
val classProto = serializer!!.classProto(irClass).build()
|
||||
writeKotlinMetadata(visitor, state, KotlinClassHeader.Kind.CLASS, extraFlags) {
|
||||
AsmUtil.writeAnnotationData(it, classProto, serializer.stringTable as JvmStringTable)
|
||||
}
|
||||
|
||||
assert(irClass !in context.classNameOverride) {
|
||||
"JvmPackageName is not supported for classes: ${irClass.render()}"
|
||||
}
|
||||
}
|
||||
is FirMetadataSource.Function -> {
|
||||
val fakeAnonymousFunction = metadata.function.copyToFreeAnonymousFunction()
|
||||
val functionProto = serializer!!.functionProto(fakeAnonymousFunction)?.build()
|
||||
writeKotlinMetadata(visitor, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, extraFlags) {
|
||||
if (functionProto != null) {
|
||||
AsmUtil.writeAnnotationData(it, functionProto, serializer.stringTable as JvmStringTable)
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindMethodMetadata(method: IrFunction, signature: Method) {
|
||||
when (val metadata = method.metadata) {
|
||||
is FirMetadataSource.Variable -> {
|
||||
// We can't check for JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS because for interface methods
|
||||
// moved to DefaultImpls, origin is changed to DEFAULT_IMPLS
|
||||
// TODO: fix origin somehow, because otherwise $annotations methods in interfaces also don't have ACC_SYNTHETIC
|
||||
assert(method.name.asString().endsWith(JvmAbi.ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX)) { method.dump() }
|
||||
|
||||
state.globalSerializationBindings.put(
|
||||
FirJvmSerializerExtension.SYNTHETIC_METHOD_FOR_FIR_VARIABLE, metadata.variable, signature
|
||||
)
|
||||
}
|
||||
is FirMetadataSource.Function -> {
|
||||
visitor.serializationBindings.put(FirJvmSerializerExtension.METHOD_FOR_FIR_FUNCTION, metadata.function, signature)
|
||||
}
|
||||
null -> {
|
||||
}
|
||||
else -> error("Incorrect metadata source $metadata for:\n${method.dump()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindFieldMetadata(field: IrField, fieldType: Type, fieldName: String) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user