Determine more precise conditions when to enable serialization intrinsic

Disable it if we do not have required `noCompiledSerializer` function in
runtime. Leave it enabled in tests.

Rollback some changes for old backend as it is unsupported now.
This commit is contained in:
Leonid Startsev
2022-09-05 19:40:51 +02:00
committed by Space
parent 637e8c7d8a
commit 033538161e
14 changed files with 128 additions and 160 deletions
@@ -8,17 +8,10 @@ package org.jetbrains.kotlin.codegen.extensions
import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
interface ExpressionCodegenExtension { interface ExpressionCodegenExtension {
companion object : ProjectExtensionDescriptor<ExpressionCodegenExtension>( companion object : ProjectExtensionDescriptor<ExpressionCodegenExtension>(
@@ -42,7 +42,7 @@ class PsiInlineCodegen(
) : InlineCodegen<ExpressionCodegen>( ) : InlineCodegen<ExpressionCodegen>(
codegen, state, signature, typeParameterMappings, sourceCompiler, codegen, state, signature, typeParameterMappings, sourceCompiler,
ReifiedTypeInliner( ReifiedTypeInliner(
typeParameterMappings, PsiInlineIntrinsicsSupport(state, reportErrorsOn, codegen.typeSystem), codegen.typeSystem, typeParameterMappings, PsiInlineIntrinsicsSupport(state, reportErrorsOn), codegen.typeSystem,
state.languageVersionSettings, state.unifiedNullChecks state.languageVersionSettings, state.unifiedNullChecks
), ),
), CallGenerator { ), CallGenerator {
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -20,22 +19,16 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_SUSPEND_TYPE import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_SUSPEND_TYPE
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.kotlin.types.model.TypeParameterMarker
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.Type.INT_TYPE import org.jetbrains.org.objectweb.asm.Type.INT_TYPE
import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
class PsiInlineIntrinsicsSupport( class PsiInlineIntrinsicsSupport(
override val state: GenerationState, override val state: GenerationState,
private val reportErrorsOn: KtElement, private val reportErrorsOn: KtElement,
private val typeSystem: TypeSystemCommonBackendContext
) : ReifiedTypeInliner.IntrinsicsSupport<KotlinType> { ) : ReifiedTypeInliner.IntrinsicsSupport<KotlinType> {
private val pluginExtensions = ExpressionCodegenExtension.getInstances(state.project)
override fun putClassInstance(v: InstructionAdapter, type: KotlinType) { override fun putClassInstance(v: InstructionAdapter, type: KotlinType) {
DescriptorAsmUtil.putJavaLangClassInstance(v, state.typeMapper.mapType(type), type, state.typeMapper) DescriptorAsmUtil.putJavaLangClassInstance(v, state.typeMapper.mapType(type), type, state.typeMapper)
} }
@@ -66,7 +66,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
fun reportSuspendTypeUnsupported() fun reportSuspendTypeUnsupported()
fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name) fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name)
fun rewritePluginDefinedOperationMarker(v: InstructionAdapter, next: AbstractInsnNode, instructions: InsnList, type: KT): Boolean = fun rewritePluginDefinedOperationMarker(v: InstructionAdapter, stubConstNull: AbstractInsnNode, instructions: InsnList, type: KT): Boolean =
false false
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.backend.common.extensions package org.jetbrains.kotlin.backend.common.extensions
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.linkage.IrDeserializer import org.jetbrains.kotlin.ir.linkage.IrDeserializer
@@ -17,7 +18,7 @@ interface IrGenerationExtension : IrDeserializer.IrLinkerExtension {
fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext)
fun getPlatformIntrinsicExtension(): IrIntrinsicExtension? = null fun getPlatformIntrinsicExtension(backendContext: BackendContext): IrIntrinsicExtension? = null
} }
/** /**
@@ -44,7 +44,7 @@ class IrInlineIntrinsicsSupport(
get() = classCodegen.context.state get() = classCodegen.context.state
private val pluginExtensions = IrGenerationExtension.getInstances(classCodegen.context.state.project) private val pluginExtensions = IrGenerationExtension.getInstances(classCodegen.context.state.project)
.mapNotNull { it.getPlatformIntrinsicExtension() as? JvmIrIntrinsicExtension } .mapNotNull { it.getPlatformIntrinsicExtension(classCodegen.context) as? JvmIrIntrinsicExtension }
override fun putClassInstance(v: InstructionAdapter, type: IrType) { override fun putClassInstance(v: InstructionAdapter, type: IrType) {
ExpressionCodegen.generateClassInstance(v, type, classCodegen.typeMapper, wrapPrimitives = false) ExpressionCodegen.generateClassInstance(v, type, classCodegen.typeMapper, wrapPrimitives = false)
@@ -127,7 +127,7 @@ class IrInlineIntrinsicsSupport(
.report(JvmBackendErrors.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND, typeParameterName.asString()) .report(JvmBackendErrors.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND, typeParameterName.asString())
} }
override fun rewritePluginDefinedOperationMarker(v: InstructionAdapter, next: AbstractInsnNode, instructions: InsnList, type: IrType): Boolean { override fun rewritePluginDefinedOperationMarker(v: InstructionAdapter, stubConstNull: AbstractInsnNode, instructions: InsnList, type: IrType): Boolean {
return pluginExtensions.any { it.rewritePluginDefinedOperationMarker(v, next, instructions, type, classCodegen.context) } return pluginExtensions.any { it.rewritePluginDefinedOperationMarker(v, stubConstNull, instructions, type) }
} }
} }
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.backend.jvm.codegen package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.common.extensions.IrIntrinsicExtension import org.jetbrains.kotlin.backend.common.extensions.IrIntrinsicExtension
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.intrinsics.IntrinsicMethod import org.jetbrains.kotlin.backend.jvm.intrinsics.IntrinsicMethod
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
@@ -20,12 +19,13 @@ interface JvmIrIntrinsicExtension : IrIntrinsicExtension {
/** /**
* Should return `true` if marker was processed. * Should return `true` if marker was processed.
* If this method returns `false`, a regular `TYPE_OF` intrinsic would be inserted. * If this method returns `false`, a regular `TYPE_OF` intrinsic would be inserted.
*
* This is plugin's responsibility to remove any calls to MagicApiIntrinsics.voidMagicApiCall and its arguments.
*/ */
fun rewritePluginDefinedOperationMarker( fun rewritePluginDefinedOperationMarker(
v: InstructionAdapter, v: InstructionAdapter,
next: AbstractInsnNode, stubConstNull: AbstractInsnNode,
instructions: InsnList, instructions: InsnList,
type: IrType, type: IrType
jvmBackendContext: JvmBackendContext
): Boolean ): Boolean
} }
@@ -288,7 +288,7 @@ open class JvmIrCodegenFactory(
context.localDeclarationsLoweringData = mutableMapOf() context.localDeclarationsLoweringData = mutableMapOf()
} }
val generationExtensions = IrGenerationExtension.getInstances(state.project) val generationExtensions = IrGenerationExtension.getInstances(state.project)
.mapNotNull { it.getPlatformIntrinsicExtension() as? JvmIrIntrinsicExtension } .mapNotNull { it.getPlatformIntrinsicExtension(context) as? JvmIrIntrinsicExtension }
val intrinsics by lazy { IrIntrinsicMethods(irModuleFragment.irBuiltins, context.ir.symbols) } val intrinsics by lazy { IrIntrinsicMethods(irModuleFragment.irBuiltins, context.ir.symbols) }
context.getIntrinsic = { symbol: IrFunctionSymbol -> context.getIntrinsic = { symbol: IrFunctionSymbol ->
intrinsics.getIntrinsic(symbol) ?: generationExtensions.firstNotNullOfOrNull { it.getIntrinsic(symbol) } intrinsics.getIntrinsic(symbol) ?: generationExtensions.firstNotNullOfOrNull { it.getIntrinsic(symbol) }
@@ -19,9 +19,9 @@ import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.pluginIn
import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
@@ -56,7 +56,7 @@ import org.jetbrains.org.objectweb.asm.tree.InsnList
import org.jetbrains.org.objectweb.asm.tree.LdcInsnNode import org.jetbrains.org.objectweb.asm.tree.LdcInsnNode
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContext) : SerializationBaseContext { class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContext) : SerializationBaseContext, JvmIrIntrinsicExtension {
sealed class IntrinsicType(val methodDescriptor: String) { sealed class IntrinsicType(val methodDescriptor: String) {
object Simple : IntrinsicType(stubCallDescriptor) object Simple : IntrinsicType(stubCallDescriptor)
@@ -69,35 +69,7 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex
} }
} }
companion object { inner class ReifiedSerializerMethod(private val withModule: Boolean) : IntrinsicMethod() {
fun intrinsicForMethod(method: IrFunction): IntrinsicMethod? {
if (method.fqNameWhenAvailable?.asString() != "kotlinx.serialization.SerializersKt.serializer"
|| method.dispatchReceiverParameter != null
|| method.typeParameters.size != 1
|| method.valueParameters.isNotEmpty()
) return null
val receiver = method.extensionReceiverParameter
return if (receiver == null)
ReifiedSerializerMethod(withModule = false)
else if (receiver.type.classFqName?.asString() == "kotlinx.serialization.modules.SerializersModule")
ReifiedSerializerMethod(withModule = true)
else null
}
val serializersModuleType: Type = Type.getObjectType("kotlinx/serialization/modules/SerializersModule")
val kTypeType: Type = AsmTypes.K_TYPE
val stubCallDescriptorWithModule = "(${serializersModuleType.descriptor}${kTypeType.descriptor})${kSerializerType.descriptor}"
val stubCallDescriptor = "(${kTypeType.descriptor})${kSerializerType.descriptor}"
const val serializersKtInternalName = "kotlinx/serialization/SerializersKt"
const val callMethodName = "serializer"
const val noCompiledSerializerMethodName = "noCompiledSerializer"
const val magicMarkerStringPrefix = "kotlinx.serialization.serializer."
}
class ReifiedSerializerMethod(private val withModule: Boolean) : IntrinsicMethod() {
override fun invoke( override fun invoke(
expression: IrFunctionAccessExpression, expression: IrFunctionAccessExpression,
codegen: ExpressionCodegen, codegen: ExpressionCodegen,
@@ -115,7 +87,7 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex
codegen.markLineNumber(expression) codegen.markLineNumber(expression)
IntrinsicType.Simple IntrinsicType.Simple
} }
SerializationJvmIrIntrinsicSupport(codegen.context).generateSerializerForType( generateSerializerForType(
argument, argument,
mv, mv,
intrinsicType intrinsicType
@@ -128,6 +100,35 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex
} }
} }
companion object {
val serializersModuleType: Type = Type.getObjectType("kotlinx/serialization/modules/SerializersModule")
val kTypeType: Type = AsmTypes.K_TYPE
val stubCallDescriptorWithModule = "(${serializersModuleType.descriptor}${kTypeType.descriptor})${kSerializerType.descriptor}"
val stubCallDescriptor = "(${kTypeType.descriptor})${kSerializerType.descriptor}"
const val serializersKtInternalName = "kotlinx/serialization/SerializersKt"
const val callMethodName = "serializer"
const val noCompiledSerializerMethodName = "noCompiledSerializer"
const val magicMarkerStringPrefix = "kotlinx.serialization.serializer."
}
override fun getIntrinsic(symbol: IrFunctionSymbol): IntrinsicMethod? {
val method = symbol.owner
if (method.fqNameWhenAvailable?.asString() != "kotlinx.serialization.SerializersKt.serializer"
|| method.dispatchReceiverParameter != null
|| method.typeParameters.size != 1
|| method.valueParameters.isNotEmpty()
) return null
val receiver = method.extensionReceiverParameter
return if (receiver == null)
ReifiedSerializerMethod(withModule = false)
else if (receiver.type.classFqName?.asString() == "kotlinx.serialization.modules.SerializersModule")
ReifiedSerializerMethod(withModule = true)
else null
}
private val emptyGenerator: BaseIrGenerator? = null private val emptyGenerator: BaseIrGenerator? = null
private val module = jvmBackendContext.state.module private val module = jvmBackendContext.state.module
@@ -143,14 +144,16 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex
return module.findClassAcrossModuleDependencies(classId)?.let { jvmBackendContext.referenceClass(it) } return module.findClassAcrossModuleDependencies(classId)?.let { jvmBackendContext.referenceClass(it) }
} }
private val currentVersion = VersionReader.getVersionsForCurrentModuleFromTrace(module, jvmBackendContext.state.bindingTrace) private val currentVersion by lazy {
?.implementationVersion VersionReader.getVersionsForCurrentModuleFromTrace(module, jvmBackendContext.state.bindingTrace)
?.implementationVersion
}
override val runtimeHasEnumSerializerFactoryFunctions: Boolean override val runtimeHasEnumSerializerFactoryFunctions: Boolean
get() = currentVersion != null && currentVersion > ApiVersion.parse("1.4.0")!! get() = currentVersion != null && currentVersion!! > ApiVersion.parse("1.4.0")!!
private val hasNewContextSerializerSignature: Boolean private val hasNewContextSerializerSignature: Boolean
get() = currentVersion != null && currentVersion >= ApiVersion.parse("1.2.0")!! get() = currentVersion != null && currentVersion!! >= ApiVersion.parse("1.2.0")!!
private fun findTypeSerializerOrContext(argType: IrType): IrClassSymbol? = private fun findTypeSerializerOrContext(argType: IrType): IrClassSymbol? =
emptyGenerator.findTypeSerializerOrContextUnchecked(this, argType) emptyGenerator.findTypeSerializerOrContextUnchecked(this, argType)
@@ -181,7 +184,7 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex
* We need to remove instructions from 1 to 5 * We need to remove instructions from 1 to 5
* Instructions 0, -1 -2 and -3 would be removed by inliner. * Instructions 0, -1 -2 and -3 would be removed by inliner.
*/ */
fun rewritePluginDefinedReifiedOperationMarker( override fun rewritePluginDefinedOperationMarker(
v: InstructionAdapter, v: InstructionAdapter,
stubConstNull: AbstractInsnNode, stubConstNull: AbstractInsnNode,
instructions: InsnList, instructions: InsnList,
@@ -8,10 +8,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.context.ClassContext import org.jetbrains.kotlin.codegen.context.ClassContext
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapperBase
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
@@ -35,7 +32,6 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
import org.jetbrains.kotlinx.serialization.compiler.backend.common.* import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
@@ -251,89 +247,56 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(
} }
} }
internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
expressionCodegen: ExpressionCodegen, codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
iv: InstructionAdapter?,
genericIndex: Int? = null,
genericSerializerFieldGetter: (InstructionAdapter.(Int, KotlinType) -> Unit)? = null
): Boolean {
return stackValueSerializerInstance(
expressionCodegen,
codegen.typeMapper,
module,
kType,
maybeSerializer,
iv,
genericIndex,
false,
genericSerializerFieldGetter
)
}
// returns false is cannot not use serializer // returns false is cannot not use serializer
// use iv == null to check only (do not emit serializer onto stack) // use iv == null to check only (do not emit serializer onto stack)
internal fun AbstractSerialGenerator?.stackValueSerializerInstance( internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCodegen: ExpressionCodegen, classCodegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
expressionCodegen: ExpressionCodegen?, typeMapper: KotlinTypeMapper, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?, iv: InstructionAdapter?,
iv: InstructionAdapter?, genericIndex: Int? = null,
genericIndex: Int? = null, genericSerializerFieldGetter: (InstructionAdapter.(Int, KotlinType) -> Unit)? = null
insertExceptionOnNoSerializer: Boolean = false,
genericSerializerFieldGetter: (InstructionAdapter.(Int, KotlinType) -> Unit)? = null,
): Boolean { ): Boolean {
if (maybeSerializer == null && genericIndex != null) { if (maybeSerializer == null && genericIndex != null) {
// get field from serializer object // get field from serializer object
iv?.run { genericSerializerFieldGetter?.invoke(this, genericIndex, kType) } iv?.run { genericSerializerFieldGetter?.invoke(this, genericIndex, kType) }
return true return true
} }
val serializer = maybeSerializer ?: run { val serializer = maybeSerializer ?: return false
if (insertExceptionOnNoSerializer) iv?.apply {
aconst(kType.getJetTypeFqName(false))
invokestatic(
"kotlinx/serialization/SerializersKt",
"noCompiledSerializer",
"(Ljava/lang/String;)Lkotlinx/serialization/KSerializer;",
false
)
}
return false
}
if (serializer.kind == ClassKind.OBJECT) { if (serializer.kind == ClassKind.OBJECT) {
// singleton serializer -- just get it // singleton serializer -- just get it
if (iv != null) if (iv != null)
StackValue.singleton(serializer, typeMapper).put(kSerializerType, iv) StackValue.singleton(serializer, classCodegen.typeMapper).put(kSerializerType, iv)
return true return true
} }
// serializer is not singleton object and shall be instantiated // serializer is not singleton object and shall be instantiated
val argSerializers = kType.arguments.map { projection -> val argSerializers = kType.arguments.map { projection ->
// check if any type argument is not serializable // bail out from stackValueSerializerInstance if any type argument is not serializable
val argType = projection.type val argType = projection.type
val argSerializer = val argSerializer = if (argType.isTypeParameter()) null else {
if (argType.isTypeParameter()) null else findTypeSerializerOrContextUnchecked(module, argType) findTypeSerializerOrContext(module, argType, sourceElement = classCodegen.descriptor.findPsi())
?: return false
}
// check if it can be properly serialized with its args recursively // check if it can be properly serialized with its args recursively
if (!stackValueSerializerInstance( if (!stackValueSerializerInstance(
expressionCodegen, expressionCodegen,
typeMapper, classCodegen,
module, module,
argType, argType,
argSerializer, argSerializer,
null, null,
argType.genericIndex, argType.genericIndex,
insertExceptionOnNoSerializer = false,
genericSerializerFieldGetter genericSerializerFieldGetter
) )
) { )
// bail out only if we do not need to insert exception return false
if (!insertExceptionOnNoSerializer) return false
}
Pair(argType, argSerializer) Pair(argType, argSerializer)
} }
// new serializer if needed // new serializer if needed
iv?.apply { iv?.apply {
val serializerType = typeMapper.mapClass(serializer) val serializerType = classCodegen.typeMapper.mapClass(serializer)
val classDescriptor = kType.toClassDescriptor!! val classDescriptor = kType.toClassDescriptor!!
if (serializer.classId == enumSerializerId && !classDescriptor.useGeneratedEnumSerializer) { if (serializer.classId == enumSerializerId && !classDescriptor.useGeneratedEnumSerializer) {
// runtime contains enum serializer factory functions // runtime contains enum serializer factory functions
val javaEnumArray = Type.getType("[Ljava/lang/Enum;") val javaEnumArray = Type.getType("[Ljava/lang/Enum;")
val enumJavaType = typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT) val enumJavaType = classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
val serialName = classDescriptor.serialName() val serialName = classDescriptor.serialName()
if (classDescriptor.isEnumWithSerialInfoAnnotation()) { if (classDescriptor.isEnumWithSerialInfoAnnotation()) {
@@ -360,7 +323,7 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
} else { } else {
fillArray(annotationType, annotations) { _, annotation -> fillArray(annotationType, annotations) { _, annotation ->
val (annotationClass, args, consParams) = annotation val (annotationClass, args, consParams) = annotation
expressionCodegen?.generateSyntheticAnnotationOnStack(annotationClass, args, consParams) ?: nop() expressionCodegen.generateSyntheticAnnotationOnStack(annotationClass, args, consParams)
} }
} }
} }
@@ -398,15 +361,14 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
assert( assert(
stackValueSerializerInstance( stackValueSerializerInstance(
expressionCodegen, expressionCodegen,
typeMapper, classCodegen,
module, module,
argType, argType,
argSerializer, argSerializer,
this, this,
argType.genericIndex, argType.genericIndex,
insertExceptionOnNoSerializer,
genericSerializerFieldGetter genericSerializerFieldGetter
) || insertExceptionOnNoSerializer )
) )
// wrap into nullable serializer if argType is nullable // wrap into nullable serializer if argType is nullable
if (argType.isMarkedNullable) wrapStackValueIntoNullableSerializer() if (argType.isMarkedNullable) wrapStackValueIntoNullableSerializer()
@@ -419,16 +381,16 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
// support legacy serializer instantiation by constructor for old runtimes // support legacy serializer instantiation by constructor for old runtimes
aconst(serialName) aconst(serialName)
signature.append("Ljava/lang/String;") signature.append("Ljava/lang/String;")
val enumJavaType = typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT) val enumJavaType = classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
val javaEnumArray = Type.getType("[Ljava/lang/Enum;") val javaEnumArray = Type.getType("[Ljava/lang/Enum;")
invokestatic(enumJavaType.internalName, "values", "()[${enumJavaType.descriptor}", false) invokestatic(enumJavaType.internalName, "values","()[${enumJavaType.descriptor}", false)
checkcast(javaEnumArray) checkcast(javaEnumArray)
signature.append(javaEnumArray.descriptor) signature.append(javaEnumArray.descriptor)
} }
contextSerializerId, polymorphicSerializerId -> { contextSerializerId, polymorphicSerializerId -> {
// a special way to instantiate enum -- need a enum KClass reference // a special way to instantiate enum -- need a enum KClass reference
// GENERIC_ARGUMENT forces boxing in order to obtain KClass // GENERIC_ARGUMENT forces boxing in order to obtain KClass
aconst(typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)) aconst(classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this) AsmUtil.wrapJavaClassIntoKClass(this)
signature.append(AsmTypes.K_CLASS_TYPE.descriptor) signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
if (serializer.classId == contextSerializerId && serializer.constructors.any { it.valueParameters.size == 3 }) { if (serializer.classId == contextSerializerId && serializer.constructors.any { it.valueParameters.size == 3 }) {
@@ -448,7 +410,7 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
} }
referenceArraySerializerId -> { referenceArraySerializerId -> {
// a special way to instantiate reference array serializer -- need an element KClass reference // a special way to instantiate reference array serializer -- need an element KClass reference
aconst(typeMapper.mapType(kType.arguments[0].type, null, TypeMappingMode.GENERIC_ARGUMENT)) aconst(classCodegen.typeMapper.mapType(kType.arguments[0].type, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this) AsmUtil.wrapJavaClassIntoKClass(this)
signature.append(AsmTypes.K_CLASS_TYPE.descriptor) signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
// Reference array serializer still needs serializer for its argument type // Reference array serializer still needs serializer for its argument type
@@ -457,13 +419,13 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
sealedSerializerId -> { sealedSerializerId -> {
aconst(serialName) aconst(serialName)
signature.append("Ljava/lang/String;") signature.append("Ljava/lang/String;")
aconst(typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)) aconst(classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this) AsmUtil.wrapJavaClassIntoKClass(this)
signature.append(AsmTypes.K_CLASS_TYPE.descriptor) signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
val (subClasses, subSerializers) = allSealedSerializableSubclassesFor(kType.toClassDescriptor!!, module) val (subClasses, subSerializers) = allSealedSerializableSubclassesFor(kType.toClassDescriptor!!, module)
// KClasses vararg // KClasses vararg
fillArray(AsmTypes.K_CLASS_TYPE, subClasses) { _, type -> fillArray(AsmTypes.K_CLASS_TYPE, subClasses) { _, type ->
aconst(typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT)) aconst(classCodegen.typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this) AsmUtil.wrapJavaClassIntoKClass(this)
} }
signature.append(AsmTypes.K_CLASS_ARRAY_TYPE.descriptor) signature.append(AsmTypes.K_CLASS_ARRAY_TYPE.descriptor)
@@ -473,7 +435,7 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
assert( assert(
stackValueSerializerInstance( stackValueSerializerInstance(
expressionCodegen, expressionCodegen,
typeMapper, classCodegen,
module, module,
argType, argType,
argSerializer, argSerializer,
@@ -484,12 +446,11 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
assert( assert(
stackValueSerializerInstance( stackValueSerializerInstance(
expressionCodegen, expressionCodegen,
typeMapper, classCodegen,
module, module,
(genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound, (genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound,
module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer), module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer),
this, this
insertExceptionOnNoSerializer = insertExceptionOnNoSerializer
) )
) )
} }
@@ -501,7 +462,7 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance(
objectSerializerId -> { objectSerializerId -> {
aconst(serialName) aconst(serialName)
signature.append("Ljava/lang/String;") signature.append("Ljava/lang/String;")
StackValue.singleton(kType.toClassDescriptor!!, typeMapper).put(Type.getType("Ljava/lang/Object;"), iv) StackValue.singleton(kType.toClassDescriptor!!, classCodegen.typeMapper).put(Type.getType("Ljava/lang/Object;"), iv)
signature.append("Ljava/lang/Object;") signature.append("Ljava/lang/Object;")
} }
// all serializers get arguments with serializers of their generic types // all serializers get arguments with serializers of their generic types
@@ -5,6 +5,7 @@
package org.jetbrains.kotlinx.serialization.compiler.extensions package org.jetbrains.kotlinx.serialization.compiler.extensions
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.CompilationException import org.jetbrains.kotlin.backend.common.CompilationException
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
@@ -12,15 +13,12 @@ import org.jetbrains.kotlin.backend.common.extensions.IrIntrinsicExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.JvmIrIntrinsicExtension
import org.jetbrains.kotlin.backend.jvm.intrinsics.IntrinsicMethod
import org.jetbrains.kotlin.backend.jvm.ir.fileParent import org.jetbrains.kotlin.backend.jvm.ir.fileParent
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -33,9 +31,6 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializationJvmI
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.InsnList
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
/** /**
@@ -128,14 +123,20 @@ private class SerializerClassPreLowering(
} }
} }
enum class SerializationIntrinsicsState {
NORMAL, // depends on whether we have noCompiledSerializer function in runtime
DISABLED, // disabled if corresponding CLI flag passed
FORCE_ENABLED // used for test purposes ONLY
}
open class SerializationLoweringExtension @JvmOverloads constructor( open class SerializationLoweringExtension @JvmOverloads constructor(
private val metadataPlugin: SerializationDescriptorSerializerPlugin? = null private val metadataPlugin: SerializationDescriptorSerializerPlugin? = null
) : IrGenerationExtension { ) : IrGenerationExtension {
private var disableIntrinsics = false private var intrinsicsState = SerializationIntrinsicsState.NORMAL
constructor(metadataPlugin: SerializationDescriptorSerializerPlugin, disableIntrinsics: Boolean) : this(metadataPlugin) { constructor(metadataPlugin: SerializationDescriptorSerializerPlugin, intrinsicsState: SerializationIntrinsicsState) : this(metadataPlugin) {
this.disableIntrinsics = disableIntrinsics this.intrinsicsState = intrinsicsState
} }
override fun generate( override fun generate(
@@ -148,21 +149,27 @@ open class SerializationLoweringExtension @JvmOverloads constructor(
moduleFragment.files.forEach(pass2::runOnFileInOrder) moduleFragment.files.forEach(pass2::runOnFileInOrder)
} }
override fun getPlatformIntrinsicExtension(): IrIntrinsicExtension? { override fun getPlatformIntrinsicExtension(backendContext: BackendContext): IrIntrinsicExtension? {
return if (disableIntrinsics) null else object : JvmIrIntrinsicExtension { val ctx = backendContext as? JvmBackendContext ?: return null
override fun getIntrinsic(symbol: IrFunctionSymbol): IntrinsicMethod? = if (!canEnableIntrinsics(ctx)) return null
SerializationJvmIrIntrinsicSupport.intrinsicForMethod(symbol.owner) return SerializationJvmIrIntrinsicSupport(ctx)
}
override fun rewritePluginDefinedOperationMarker( private fun canEnableIntrinsics(ctx: JvmBackendContext): Boolean {
v: InstructionAdapter, return when (intrinsicsState) {
next: AbstractInsnNode, SerializationIntrinsicsState.FORCE_ENABLED -> true
instructions: InsnList, SerializationIntrinsicsState.DISABLED -> false
type: IrType, SerializationIntrinsicsState.NORMAL -> {
jvmBackendContext: JvmBackendContext val module = ctx.state.module
): Boolean { if (module.findClassAcrossModuleDependencies(
return SerializationJvmIrIntrinsicSupport(jvmBackendContext).rewritePluginDefinedReifiedOperationMarker( ClassId(
v, next, instructions, type SerializationPackages.packageFqName,
) SerialEntityNames.KSERIALIZER_NAME
)
) == null
) return false
module.getPackage(SerializationPackages.packageFqName).memberScope.getFunctionNames()
.any { it.asString() == SerializationJvmIrIntrinsicSupport.noCompiledSerializerMethodName }
} }
} }
} }
@@ -53,13 +53,14 @@ class SerializationComponentRegistrar : CompilerPluginRegistrar() {
Companion.registerExtensions(this, loadDisableIntrinsic(configuration)) Companion.registerExtensions(this, loadDisableIntrinsic(configuration))
} }
private fun loadDisableIntrinsic(configuration: CompilerConfiguration) = configuration.get(DISABLE_INTRINSIC) ?: false private fun loadDisableIntrinsic(configuration: CompilerConfiguration) =
if (configuration.get(DISABLE_INTRINSIC) == true) SerializationIntrinsicsState.DISABLED else SerializationIntrinsicsState.NORMAL
override val supportsK2: Boolean override val supportsK2: Boolean
get() = false get() = false
companion object { companion object {
fun registerExtensions(extensionStorage: ExtensionStorage, disableIntrinsics: Boolean = false) = with(extensionStorage) { fun registerExtensions(extensionStorage: ExtensionStorage, intrinsicsState: SerializationIntrinsicsState = SerializationIntrinsicsState.NORMAL) = with(extensionStorage) {
// This method is never called in the IDE, therefore this extension is not available there. // 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' // Since IDE does not perform any serialization of descriptors, metadata written to the 'serializationDescriptorSerializer'
// is never deleted, effectively causing memory leaks. // is never deleted, effectively causing memory leaks.
@@ -72,7 +73,7 @@ class SerializationComponentRegistrar : CompilerPluginRegistrar() {
ExpressionCodegenExtension.registerExtension(SerializationCodegenExtension(serializationDescriptorSerializer)) ExpressionCodegenExtension.registerExtension(SerializationCodegenExtension(serializationDescriptorSerializer))
JsSyntheticTranslateExtension.registerExtension(SerializationJsExtension(serializationDescriptorSerializer)) JsSyntheticTranslateExtension.registerExtension(SerializationJsExtension(serializationDescriptorSerializer))
IrGenerationExtension.registerExtension(SerializationLoweringExtension(serializationDescriptorSerializer, disableIntrinsics)) IrGenerationExtension.registerExtension(SerializationLoweringExtension(serializationDescriptorSerializer, intrinsicsState))
StorageComponentContainerContributor.registerExtension(SerializationPluginComponentContainerContributor()) StorageComponentContainerContributor.registerExtension(SerializationPluginComponentContainerContributor())
} }
@@ -6,12 +6,15 @@
package org.jetbrains.kotlinx.serialization.compiler.diagnostic package org.jetbrains.kotlinx.serialization.compiler.diagnostic
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.util.slicedMap.Slices import org.jetbrains.kotlin.util.slicedMap.Slices
import org.jetbrains.kotlin.util.slicedMap.WritableSlice import org.jetbrains.kotlin.util.slicedMap.WritableSlice
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
import org.jetbrains.kotlinx.serialization.compiler.resolve.getClassFromSerializationPackage import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
import java.io.File import java.io.File
object VersionReader { object VersionReader {
@@ -30,7 +33,12 @@ object VersionReader {
} }
fun getVersionsForCurrentModule(module: ModuleDescriptor): RuntimeVersions? { fun getVersionsForCurrentModule(module: ModuleDescriptor): RuntimeVersions? {
val markerClass = module.getClassFromSerializationPackage(SerialEntityNames.KSERIALIZER_CLASS) val markerClass = module.findClassAcrossModuleDependencies(
ClassId(
SerializationPackages.packageFqName,
Name.identifier(SerialEntityNames.KSERIALIZER_CLASS)
)
) ?: return null
return CommonVersionReader.computeRuntimeVersions(markerClass.source) return CommonVersionReader.computeRuntimeVersions(markerClass.source)
} }
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
import org.jetbrains.kotlin.test.services.RuntimeClasspathProvider import org.jetbrains.kotlin.test.services.RuntimeClasspathProvider
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIntrinsicsState
import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationExtensionRegistrar import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationExtensionRegistrar
import java.io.File import java.io.File
@@ -34,7 +35,7 @@ class SerializationEnvironmentConfigurator(
module: TestModule, module: TestModule,
configuration: CompilerConfiguration configuration: CompilerConfiguration
) { ) {
SerializationComponentRegistrar.registerExtensions(this) SerializationComponentRegistrar.registerExtensions(this, SerializationIntrinsicsState.FORCE_ENABLED)
FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar()) FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar())
} }
} }