Disable kx.ser plugin inside descriptors serialization in the IDE

Since IDE does not perform any serialization of descriptors, and
metadata written to the 'serializationDescriptorSerializer'
deleted only on call to DescriptorSerializer,
enabling this extension in the IDE effectively causes memory leaks.

 #KT-39624 Fixed

Pass SerializationDescriptorSerializerPlugin to other extensions directly

instead of using static val in companion.
This commit is contained in:
Leonid Startsev
2020-10-15 22:42:06 +03:00
parent 4ec90b18bc
commit 8d999a2c13
16 changed files with 69 additions and 47 deletions
@@ -4,7 +4,6 @@
<syntheticResolveExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEResolveExtension"/>
<jsSyntheticTranslateExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEJsExtension"/>
<irGenerationExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEIrExtension"/>
<DescriptorSerializerPlugin implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorPluginForKotlinxSerialization"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEContainerContributor"/>
<quickFixContributor implementation="org.jetbrains.kotlinx.serialization.idea.quickfixes.SerializationQuickFixContributor"/>
</extensions>
@@ -10,15 +10,17 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
abstract class SerializerCodegen(
protected val serializerDescriptor: ClassDescriptor,
bindingContext: BindingContext
bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
protected val serialName: String = serializableDescriptor.serialName()
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor)
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor, metadataPlugin)
protected val serializableProperties = properties.serializableProperties
private fun checkSerializability() {
@@ -29,7 +29,7 @@ class SerializerForEnumsGenerator(
compilerContext: SerializationPluginContext,
bindingContext: BindingContext
) :
SerializerIrGenerator(irClass, compilerContext, bindingContext) {
SerializerIrGenerator(irClass, compilerContext, bindingContext, null) {
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
fun irThis(): IrExpression =
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS
@@ -44,15 +45,20 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UN
// Is creating synthetic origin is a good idea or not?
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER")
open class SerializerIrGenerator(val irClass: IrClass, final override val compilerContext: SerializationPluginContext, bindingContext: BindingContext) :
SerializerCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
open class SerializerIrGenerator(
val irClass: IrClass,
final override val compilerContext: SerializationPluginContext,
bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) :
SerializerCodegen(irClass.descriptor, bindingContext, metadataPlugin), IrBuilderExtension {
protected val serializableIrClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).owner
protected val irAnySerialDescProperty = anySerialDescProperty?.let { compilerContext.symbolTable.referenceProperty(it) }
protected open val serialDescImplClass: ClassDescriptor = serializerDescriptor
.getClassFromInternalSerializationPackage(SERIAL_DESCRIPTOR_CLASS_IMPL)
.getClassFromInternalSerializationPackage(SERIAL_DESCRIPTOR_CLASS_IMPL)
override fun generateSerialDesc() {
val desc: PropertyDescriptor = generatedSerialDescPropertyDescriptor ?: return
@@ -493,13 +499,14 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
fun generate(
irClass: IrClass,
context: SerializationPluginContext,
bindingContext: BindingContext
bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) {
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
if (serializableDesc.isSerializableEnum()) {
SerializerForEnumsGenerator(irClass, context, bindingContext).generate()
} else {
SerializerIrGenerator(irClass, context, bindingContext).generate()
SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin).generate()
}
irClass.patchDeclarationParents(irClass.parent)
}
@@ -20,7 +20,7 @@ class SerializerForEnumsTranslator(
descriptor: ClassDescriptor,
translator: DeclarationBodyVisitor,
context: TranslationContext
) : SerializerJsTranslator(descriptor, translator, context) {
) : SerializerJsTranslator(descriptor, translator, context, null) {
override fun generateSave(function: FunctionDescriptor) = generateFunction(function) { jsFun, ctx ->
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS)
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(anySerialDescProperty!!), JsThisRef())
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
@@ -32,8 +33,9 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ty
open class SerializerJsTranslator(
descriptor: ClassDescriptor,
val translator: DeclarationBodyVisitor,
val context: TranslationContext
) : SerializerCodegen(descriptor, context.bindingContext()) {
val context: TranslationContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) : SerializerCodegen(descriptor, context.bindingContext(), metadataPlugin) {
internal fun generateFunction(descriptor: FunctionDescriptor, bodyGen: JsBlockBuilder.(JsFunction, TranslationContext) -> Unit) {
val f = context.buildFunction(descriptor, bodyGen)
@@ -351,7 +353,11 @@ open class SerializerJsTranslator(
// deserialization constructor call
// todo: external deserialization with primary constructor and setters calls after resolution of KT-11586
val constrDesc = KSerializerDescriptorResolver.createLoadConstructorDescriptor(serializableDescriptor, context.bindingContext())
val constrDesc = KSerializerDescriptorResolver.createLoadConstructorDescriptor(
serializableDescriptor,
context.bindingContext(),
null
)
val constrRef = context.getInnerNameForDescriptor(constrDesc).makeRef()
val args: MutableList<JsExpression> = bitMasks.toMutableList()
args += localProps
@@ -363,13 +369,14 @@ open class SerializerJsTranslator(
fun translate(
descriptor: ClassDescriptor,
translator: DeclarationBodyVisitor,
context: TranslationContext
context: TranslationContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) {
val serializableDesc = getSerializableClassDescriptorBySerializer(descriptor) ?: return
if (serializableDesc.isSerializableEnum()) {
SerializerForEnumsTranslator(descriptor, translator, context).generate()
} else {
SerializerJsTranslator(descriptor, translator, context).generate()
SerializerJsTranslator(descriptor, translator, context, metadataPlugin).generate()
}
}
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
import org.jetbrains.org.objectweb.asm.Label
@@ -21,8 +22,9 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
open class SerializerCodegenImpl(
protected val codegen: ImplementationBodyCodegen,
serializableClass: ClassDescriptor
) : SerializerCodegen(codegen.descriptor, codegen.bindingContext) {
serializableClass: ClassDescriptor,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) : SerializerCodegen(codegen.descriptor, codegen.bindingContext, metadataPlugin) {
private val serialDescField = "\$\$serialDesc"
@@ -34,12 +36,12 @@ open class SerializerCodegenImpl(
private val staticDescriptor = serializableDescriptor.declaredTypeParameters.isEmpty()
companion object {
fun generateSerializerExtensions(codegen: ImplementationBodyCodegen) {
fun generateSerializerExtensions(codegen: ImplementationBodyCodegen, metadataPlugin: SerializationDescriptorSerializerPlugin?) {
val serializableClass = getSerializableClassDescriptorBySerializer(codegen.descriptor) ?: return
val serializerCodegen = if (serializableClass.isSerializableEnum()) {
SerializerForEnumsCodegen(codegen, serializableClass)
} else {
SerializerCodegenImpl(codegen, serializableClass)
SerializerCodegenImpl(codegen, serializableClass, metadataPlugin)
}
serializerCodegen.generate()
}
@@ -12,7 +12,7 @@ import org.jetbrains.org.objectweb.asm.Type
class SerializerForEnumsCodegen(
codegen: ImplementationBodyCodegen,
serializableClass: ClassDescriptor
) : SerializerCodegenImpl(codegen, serializableClass) {
) : SerializerCodegenImpl(codegen, serializableClass, null) {
override fun generateSave(function: FunctionDescriptor) = codegen.generateMethod(function) { _, _ ->
// fun save(output: KOutput, obj : T)
val outputVar = 1
@@ -23,11 +23,11 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCode
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCompanionCodegenImpl
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerCodegenImpl
open class SerializationCodegenExtension : ExpressionCodegenExtension {
open class SerializationCodegenExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : ExpressionCodegenExtension {
override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) {
SerialInfoCodegenImpl.generateSerialInfoImplBody(codegen)
SerializableCodegenImpl.generateSerializableExtensions(codegen)
SerializerCodegenImpl.generateSerializerExtensions(codegen)
SerializerCodegenImpl.generateSerializerExtensions(codegen, metadataPlugin)
SerializableCompanionCodegenImpl.generateSerializableExtensions(codegen)
}
@@ -30,19 +30,22 @@ class SerializationComponentRegistrar : ComponentRegistrar {
}
companion object {
internal val serializationDescriptorSerializer = SerializationDescriptorPluginForKotlinxSerialization()
fun registerExtensions(project: Project) {
SyntheticResolveExtension.registerExtension(project, SerializationResolveExtension())
ExpressionCodegenExtension.registerExtension(project, SerializationCodegenExtension())
JsSyntheticTranslateExtension.registerExtension(project, SerializationJsExtension())
IrGenerationExtension.registerExtension(project, SerializationLoweringExtension())
StorageComponentContainerContributor.registerExtension(project, SerializationPluginComponentContainerContributor())
// This method is never called in the IDE, therefore this extension is not available there.
// Since IDE does not perform any serialization of descriptors, metadata written to the 'serializationDescriptorSerializer'
// is never deleted, effectively causing memory leaks.
// So we create SerializationDescriptorSerializerPlugin only outside of IDE.
val serializationDescriptorSerializer = SerializationDescriptorSerializerPlugin()
DescriptorSerializerPlugin.registerExtension(project, serializationDescriptorSerializer)
registerProtoExtensions()
SyntheticResolveExtension.registerExtension(project, SerializationResolveExtension(serializationDescriptorSerializer))
ExpressionCodegenExtension.registerExtension(project, SerializationCodegenExtension(serializationDescriptorSerializer))
JsSyntheticTranslateExtension.registerExtension(project, SerializationJsExtension(serializationDescriptorSerializer))
IrGenerationExtension.registerExtension(project, SerializationLoweringExtension(serializationDescriptorSerializer))
StorageComponentContainerContributor.registerExtension(project, SerializationPluginComponentContainerContributor())
}
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.serialization.SerializerExtension
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
class SerializationDescriptorPluginForKotlinxSerialization : DescriptorSerializerPlugin {
class SerializationDescriptorSerializerPlugin : DescriptorSerializerPlugin {
private val descriptorMetadataMap: MutableMap<ClassDescriptor, SerializableProperties> = hashMapOf()
private val ClassDescriptor.needSaveProgramOrder: Boolean
@@ -25,9 +25,9 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializableCompa
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializableJsTranslator
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializerJsTranslator
open class SerializationJsExtension: JsSyntheticTranslateExtension {
open class SerializationJsExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null): JsSyntheticTranslateExtension {
override fun generateClassSyntheticParts(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) {
SerializerJsTranslator.translate(descriptor, translator, context)
SerializerJsTranslator.translate(descriptor, translator, context, metadataPlugin)
SerializableJsTranslator.translate(declaration, descriptor, context)
SerializableCompanionJsTranslator.translate(descriptor, translator, context)
}
@@ -40,22 +40,23 @@ fun ClassLoweringPass.runOnFileInOrder(irFile: IrFile) {
typealias SerializationPluginContext = IrPluginContext
private class SerializerClassLowering(
val context: SerializationPluginContext
val context: SerializationPluginContext,
val metadataPlugin: SerializationDescriptorSerializerPlugin?
) :
IrElementTransformerVoid(), ClassLoweringPass {
override fun lower(irClass: IrClass) {
SerializableIrGenerator.generate(irClass, context, context.bindingContext)
SerializerIrGenerator.generate(irClass, context, context.bindingContext)
SerializerIrGenerator.generate(irClass, context, context.bindingContext, metadataPlugin)
SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext)
}
}
open class SerializationLoweringExtension : IrGenerationExtension {
open class SerializationLoweringExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : IrGenerationExtension {
override fun generate(
moduleFragment: IrModuleFragment,
pluginContext: IrPluginContext
) {
val serializerClassLowering = SerializerClassLowering(pluginContext)
val serializerClassLowering = SerializerClassLowering(pluginContext, metadataPlugin)
for (file in moduleFragment.files)
serializerClassLowering.runOnFileInOrder(file)
}
@@ -34,7 +34,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoFqName
import java.util.*
open class SerializationResolveExtension : SyntheticResolveExtension {
open class SerializationResolveExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : SyntheticResolveExtension {
override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List<Name> = when {
thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && thisDescriptor.platform?.isJvm() == true -> listOf(SerialEntityNames.IMPL_NAME)
(thisDescriptor.shouldHaveGeneratedSerializer) && !thisDescriptor.hasCompanionObjectAsSerializer ->
@@ -87,7 +87,7 @@ open class SerializationResolveExtension : SyntheticResolveExtension {
if (thisDescriptor.isInternalSerializable) {
// do not add synthetic deserialization constructor if .deserialize method is customized
if (thisDescriptor.hasCompanionObjectAsSerializer && SerializerCodegen.getSyntheticLoadMember(thisDescriptor.companionObjectDescriptor!!) == null) return
result.add(KSerializerDescriptorResolver.createLoadConstructorDescriptor(thisDescriptor, bindingContext))
result.add(KSerializerDescriptorResolver.createLoadConstructorDescriptor(thisDescriptor, bindingContext, metadataPlugin))
}
}
@@ -16,13 +16,11 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.konan.isNative
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.descriptorUtil.platform
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
@@ -31,6 +29,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SimpleSyntheticPropertyDescriptor
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.IMPL_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_CLASS_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
@@ -288,7 +287,8 @@ object KSerializerDescriptorResolver {
fun createLoadConstructorDescriptor(
classDescriptor: ClassDescriptor,
bindingContext: BindingContext
bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
): ClassConstructorDescriptor {
if (!classDescriptor.isInternalSerializable) throw IllegalArgumentException()
@@ -302,7 +302,7 @@ object KSerializerDescriptorResolver {
val markerDesc = classDescriptor.getKSerializerConstructorMarker()
val markerType = markerDesc.toSimpleType(nullable = true)
val serializableProperties = bindingContext.serializablePropertiesFor(classDescriptor).serializableProperties
val serializableProperties = bindingContext.serializablePropertiesFor(classDescriptor, metadataPlugin).serializableProperties
val parameterDescsAsProps = serializableProperties.map { it.descriptor }
val bitMaskSlotsCount = serializableProperties.bitMaskSlotCount()
var i = 0
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) {
@@ -88,9 +89,9 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
internal fun List<SerializableProperty>.bitMaskSlotCount() = size / 32 + 1
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor): SerializableProperties {
internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor, serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null): SerializableProperties {
val props = this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)
SerializationComponentRegistrar.serializationDescriptorSerializer.putIfNeeded(classDescriptor, props)
serializationDescriptorSerializer?.putIfNeeded(classDescriptor, props)
return props
}