diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/extensions/ExpressionCodegenExtension.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/extensions/ExpressionCodegenExtension.kt index d022609427a..8a2d96eb1ef 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/extensions/ExpressionCodegenExtension.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/extensions/ExpressionCodegenExtension.kt @@ -8,17 +8,10 @@ package org.jetbrains.kotlin.codegen.extensions import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen import org.jetbrains.kotlin.codegen.StackValue -import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper -import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor 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.tree.InsnList -import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode interface ExpressionCodegenExtension { companion object : ProjectExtensionDescriptor( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt index 6d3ed519115..a79bcd83e67 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt @@ -42,7 +42,7 @@ class PsiInlineCodegen( ) : InlineCodegen( codegen, state, signature, typeParameterMappings, sourceCompiler, ReifiedTypeInliner( - typeParameterMappings, PsiInlineIntrinsicsSupport(state, reportErrorsOn, codegen.typeSystem), codegen.typeSystem, + typeParameterMappings, PsiInlineIntrinsicsSupport(state, reportErrorsOn), codegen.typeSystem, state.languageVersionSettings, state.unifiedNullChecks ), ), CallGenerator { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt index b8adca3ad51..fa4622ebb5a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.codegen.inline import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.codegen.* -import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.ClassDescriptor 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_SUSPEND_TYPE import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.org.objectweb.asm.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.commons.InstructionAdapter -import org.jetbrains.org.objectweb.asm.tree.InsnList -import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode class PsiInlineIntrinsicsSupport( override val state: GenerationState, private val reportErrorsOn: KtElement, - private val typeSystem: TypeSystemCommonBackendContext ) : ReifiedTypeInliner.IntrinsicsSupport { - private val pluginExtensions = ExpressionCodegenExtension.getInstances(state.project) - override fun putClassInstance(v: InstructionAdapter, type: KotlinType) { DescriptorAsmUtil.putJavaLangClassInstance(v, state.typeMapper.mapType(type), type, state.typeMapper) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index 8f1dcc51913..9452fcc773d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -66,7 +66,7 @@ class ReifiedTypeInliner( fun reportSuspendTypeUnsupported() 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 } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrGenerationExtension.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrGenerationExtension.kt index 07914bd1c24..b9ab77d8554 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrGenerationExtension.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrGenerationExtension.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.backend.common.extensions +import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.linkage.IrDeserializer @@ -17,7 +18,7 @@ interface IrGenerationExtension : IrDeserializer.IrLinkerExtension { fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) - fun getPlatformIntrinsicExtension(): IrIntrinsicExtension? = null + fun getPlatformIntrinsicExtension(backendContext: BackendContext): IrIntrinsicExtension? = null } /** diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt index e662ac9d6ad..e0814b9f539 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt @@ -44,7 +44,7 @@ class IrInlineIntrinsicsSupport( get() = classCodegen.context.state 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) { 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()) } - override fun rewritePluginDefinedOperationMarker(v: InstructionAdapter, next: AbstractInsnNode, instructions: InsnList, type: IrType): Boolean { - return pluginExtensions.any { it.rewritePluginDefinedOperationMarker(v, next, instructions, type, classCodegen.context) } + override fun rewritePluginDefinedOperationMarker(v: InstructionAdapter, stubConstNull: AbstractInsnNode, instructions: InsnList, type: IrType): Boolean { + return pluginExtensions.any { it.rewritePluginDefinedOperationMarker(v, stubConstNull, instructions, type) } } } diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/JvmIrIntrinsicExtension.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/JvmIrIntrinsicExtension.kt index 8b9577bc621..574ed8ac8de 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/JvmIrIntrinsicExtension.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/JvmIrIntrinsicExtension.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.backend.jvm.codegen 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.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.types.IrType @@ -20,12 +19,13 @@ interface JvmIrIntrinsicExtension : IrIntrinsicExtension { /** * Should return `true` if marker was processed. * 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( v: InstructionAdapter, - next: AbstractInsnNode, + stubConstNull: AbstractInsnNode, instructions: InsnList, - type: IrType, - jvmBackendContext: JvmBackendContext + type: IrType ): Boolean } \ No newline at end of file diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt index b5b2bfb9d3e..6ed6f6f535a 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt @@ -288,7 +288,7 @@ open class JvmIrCodegenFactory( context.localDeclarationsLoweringData = mutableMapOf() } 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) } context.getIntrinsic = { symbol: IrFunctionSymbol -> intrinsics.getIntrinsic(symbol) ?: generationExtensions.firstNotNullOfOrNull { it.getIntrinsic(symbol) } diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt index 8f6172f024d..f55485a6940 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt @@ -19,9 +19,9 @@ import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.pluginIn import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies 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.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* 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.VarInsnNode -class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContext) : SerializationBaseContext { +class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContext) : SerializationBaseContext, JvmIrIntrinsicExtension { sealed class IntrinsicType(val methodDescriptor: String) { object Simple : IntrinsicType(stubCallDescriptor) @@ -69,35 +69,7 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex } } - companion object { - 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() { + inner class ReifiedSerializerMethod(private val withModule: Boolean) : IntrinsicMethod() { override fun invoke( expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, @@ -115,7 +87,7 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex codegen.markLineNumber(expression) IntrinsicType.Simple } - SerializationJvmIrIntrinsicSupport(codegen.context).generateSerializerForType( + generateSerializerForType( argument, mv, 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 module = jvmBackendContext.state.module @@ -143,14 +144,16 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex return module.findClassAcrossModuleDependencies(classId)?.let { jvmBackendContext.referenceClass(it) } } - private val currentVersion = VersionReader.getVersionsForCurrentModuleFromTrace(module, jvmBackendContext.state.bindingTrace) - ?.implementationVersion + private val currentVersion by lazy { + VersionReader.getVersionsForCurrentModuleFromTrace(module, jvmBackendContext.state.bindingTrace) + ?.implementationVersion + } 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 - get() = currentVersion != null && currentVersion >= ApiVersion.parse("1.2.0")!! + get() = currentVersion != null && currentVersion!! >= ApiVersion.parse("1.2.0")!! private fun findTypeSerializerOrContext(argType: IrType): IrClassSymbol? = emptyGenerator.findTypeSerializerOrContextUnchecked(this, argType) @@ -181,7 +184,7 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex * We need to remove instructions from 1 to 5 * Instructions 0, -1 -2 and -3 would be removed by inliner. */ - fun rewritePluginDefinedReifiedOperationMarker( + override fun rewritePluginDefinedOperationMarker( v: InstructionAdapter, stubConstNull: AbstractInsnNode, instructions: InsnList, diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt index dbad1f2a8f4..da8ccedb683 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt @@ -8,10 +8,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.* 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.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl 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.types.KotlinType 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.representativeUpperBound 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 // use iv == null to check only (do not emit serializer onto stack) -internal fun AbstractSerialGenerator?.stackValueSerializerInstance( - expressionCodegen: ExpressionCodegen?, typeMapper: KotlinTypeMapper, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?, - iv: InstructionAdapter?, - genericIndex: Int? = null, - insertExceptionOnNoSerializer: Boolean = false, - genericSerializerFieldGetter: (InstructionAdapter.(Int, KotlinType) -> Unit)? = null, +internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCodegen: ExpressionCodegen, classCodegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?, + iv: InstructionAdapter?, + genericIndex: Int? = null, + genericSerializerFieldGetter: (InstructionAdapter.(Int, KotlinType) -> Unit)? = null ): Boolean { if (maybeSerializer == null && genericIndex != null) { // get field from serializer object iv?.run { genericSerializerFieldGetter?.invoke(this, genericIndex, kType) } return true } - val serializer = maybeSerializer ?: run { - if (insertExceptionOnNoSerializer) iv?.apply { - aconst(kType.getJetTypeFqName(false)) - invokestatic( - "kotlinx/serialization/SerializersKt", - "noCompiledSerializer", - "(Ljava/lang/String;)Lkotlinx/serialization/KSerializer;", - false - ) - } - return false - } + val serializer = maybeSerializer ?: return false if (serializer.kind == ClassKind.OBJECT) { // singleton serializer -- just get it if (iv != null) - StackValue.singleton(serializer, typeMapper).put(kSerializerType, iv) + StackValue.singleton(serializer, classCodegen.typeMapper).put(kSerializerType, iv) return true } // serializer is not singleton object and shall be instantiated 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 argSerializer = - if (argType.isTypeParameter()) null else findTypeSerializerOrContextUnchecked(module, argType) + val argSerializer = if (argType.isTypeParameter()) null else { + findTypeSerializerOrContext(module, argType, sourceElement = classCodegen.descriptor.findPsi()) + ?: return false + } // check if it can be properly serialized with its args recursively if (!stackValueSerializerInstance( expressionCodegen, - typeMapper, + classCodegen, module, argType, argSerializer, null, argType.genericIndex, - insertExceptionOnNoSerializer = false, genericSerializerFieldGetter ) - ) { - // bail out only if we do not need to insert exception - if (!insertExceptionOnNoSerializer) return false - } + ) + return false Pair(argType, argSerializer) } // new serializer if needed iv?.apply { - val serializerType = typeMapper.mapClass(serializer) + val serializerType = classCodegen.typeMapper.mapClass(serializer) val classDescriptor = kType.toClassDescriptor!! if (serializer.classId == enumSerializerId && !classDescriptor.useGeneratedEnumSerializer) { // runtime contains enum serializer factory functions 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() if (classDescriptor.isEnumWithSerialInfoAnnotation()) { @@ -360,7 +323,7 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance( } else { fillArray(annotationType, annotations) { _, 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( stackValueSerializerInstance( expressionCodegen, - typeMapper, + classCodegen, module, argType, argSerializer, this, argType.genericIndex, - insertExceptionOnNoSerializer, genericSerializerFieldGetter - ) || insertExceptionOnNoSerializer + ) ) // wrap into nullable serializer if argType is nullable if (argType.isMarkedNullable) wrapStackValueIntoNullableSerializer() @@ -419,16 +381,16 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance( // support legacy serializer instantiation by constructor for old runtimes aconst(serialName) 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;") - invokestatic(enumJavaType.internalName, "values", "()[${enumJavaType.descriptor}", false) + invokestatic(enumJavaType.internalName, "values","()[${enumJavaType.descriptor}", false) checkcast(javaEnumArray) signature.append(javaEnumArray.descriptor) } contextSerializerId, polymorphicSerializerId -> { // a special way to instantiate enum -- need a enum KClass reference // 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) signature.append(AsmTypes.K_CLASS_TYPE.descriptor) if (serializer.classId == contextSerializerId && serializer.constructors.any { it.valueParameters.size == 3 }) { @@ -448,7 +410,7 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance( } referenceArraySerializerId -> { // 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) signature.append(AsmTypes.K_CLASS_TYPE.descriptor) // Reference array serializer still needs serializer for its argument type @@ -457,13 +419,13 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance( sealedSerializerId -> { aconst(serialName) 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) signature.append(AsmTypes.K_CLASS_TYPE.descriptor) val (subClasses, subSerializers) = allSealedSerializableSubclassesFor(kType.toClassDescriptor!!, module) // KClasses vararg 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) } signature.append(AsmTypes.K_CLASS_ARRAY_TYPE.descriptor) @@ -473,7 +435,7 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance( assert( stackValueSerializerInstance( expressionCodegen, - typeMapper, + classCodegen, module, argType, argSerializer, @@ -484,12 +446,11 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance( assert( stackValueSerializerInstance( expressionCodegen, - typeMapper, + classCodegen, module, (genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound, module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer), - this, - insertExceptionOnNoSerializer = insertExceptionOnNoSerializer + this ) ) } @@ -501,7 +462,7 @@ internal fun AbstractSerialGenerator?.stackValueSerializerInstance( objectSerializerId -> { aconst(serialName) 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;") } // all serializers get arguments with serializers of their generic types diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt index 12209967758..e41e5b0e165 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt @@ -5,6 +5,7 @@ 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.CompilationException 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.runOnFilePostfix 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.descriptors.findClassAcrossModuleDependencies import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.declarations.* 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.IrElementVisitorVoid 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.SerialEntityNames 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 /** @@ -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( private val metadataPlugin: SerializationDescriptorSerializerPlugin? = null ) : IrGenerationExtension { - private var disableIntrinsics = false + private var intrinsicsState = SerializationIntrinsicsState.NORMAL - constructor(metadataPlugin: SerializationDescriptorSerializerPlugin, disableIntrinsics: Boolean) : this(metadataPlugin) { - this.disableIntrinsics = disableIntrinsics + constructor(metadataPlugin: SerializationDescriptorSerializerPlugin, intrinsicsState: SerializationIntrinsicsState) : this(metadataPlugin) { + this.intrinsicsState = intrinsicsState } override fun generate( @@ -148,21 +149,27 @@ open class SerializationLoweringExtension @JvmOverloads constructor( moduleFragment.files.forEach(pass2::runOnFileInOrder) } - override fun getPlatformIntrinsicExtension(): IrIntrinsicExtension? { - return if (disableIntrinsics) null else object : JvmIrIntrinsicExtension { - override fun getIntrinsic(symbol: IrFunctionSymbol): IntrinsicMethod? = - SerializationJvmIrIntrinsicSupport.intrinsicForMethod(symbol.owner) + override fun getPlatformIntrinsicExtension(backendContext: BackendContext): IrIntrinsicExtension? { + val ctx = backendContext as? JvmBackendContext ?: return null + if (!canEnableIntrinsics(ctx)) return null + return SerializationJvmIrIntrinsicSupport(ctx) + } - override fun rewritePluginDefinedOperationMarker( - v: InstructionAdapter, - next: AbstractInsnNode, - instructions: InsnList, - type: IrType, - jvmBackendContext: JvmBackendContext - ): Boolean { - return SerializationJvmIrIntrinsicSupport(jvmBackendContext).rewritePluginDefinedReifiedOperationMarker( - v, next, instructions, type - ) + private fun canEnableIntrinsics(ctx: JvmBackendContext): Boolean { + return when (intrinsicsState) { + SerializationIntrinsicsState.FORCE_ENABLED -> true + SerializationIntrinsicsState.DISABLED -> false + SerializationIntrinsicsState.NORMAL -> { + val module = ctx.state.module + if (module.findClassAcrossModuleDependencies( + ClassId( + SerializationPackages.packageFqName, + SerialEntityNames.KSERIALIZER_NAME + ) + ) == null + ) return false + module.getPackage(SerializationPackages.packageFqName).memberScope.getFunctionNames() + .any { it.asString() == SerializationJvmIrIntrinsicSupport.noCompiledSerializerMethodName } } } } diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.cli/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt b/plugins/kotlinx-serialization/kotlinx-serialization.cli/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt index 73a481f3d03..167957fae9d 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.cli/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.cli/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt @@ -53,13 +53,14 @@ class SerializationComponentRegistrar : CompilerPluginRegistrar() { 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 get() = false 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. // Since IDE does not perform any serialization of descriptors, metadata written to the 'serializationDescriptorSerializer' // is never deleted, effectively causing memory leaks. @@ -72,7 +73,7 @@ class SerializationComponentRegistrar : CompilerPluginRegistrar() { ExpressionCodegenExtension.registerExtension(SerializationCodegenExtension(serializationDescriptorSerializer)) JsSyntheticTranslateExtension.registerExtension(SerializationJsExtension(serializationDescriptorSerializer)) - IrGenerationExtension.registerExtension(SerializationLoweringExtension(serializationDescriptorSerializer, disableIntrinsics)) + IrGenerationExtension.registerExtension(SerializationLoweringExtension(serializationDescriptorSerializer, intrinsicsState)) StorageComponentContainerContributor.registerExtension(SerializationPluginComponentContainerContributor()) } diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/VersionReader.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/VersionReader.kt index 640a9ac504d..2c79be1fe0f 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/VersionReader.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/diagnostic/VersionReader.kt @@ -6,12 +6,15 @@ package org.jetbrains.kotlinx.serialization.compiler.diagnostic 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.BindingTrace import org.jetbrains.kotlin.util.slicedMap.Slices import org.jetbrains.kotlin.util.slicedMap.WritableSlice 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 object VersionReader { @@ -30,7 +33,12 @@ object VersionReader { } 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) } diff --git a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/serializationConfiguration.kt b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/serializationConfiguration.kt index 2416672fd29..d36a90f4fc6 100644 --- a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/serializationConfiguration.kt +++ b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/serializationConfiguration.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.test.services.EnvironmentConfigurator import org.jetbrains.kotlin.test.services.RuntimeClasspathProvider import org.jetbrains.kotlin.test.services.TestServices 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 java.io.File @@ -34,7 +35,7 @@ class SerializationEnvironmentConfigurator( module: TestModule, configuration: CompilerConfiguration ) { - SerializationComponentRegistrar.registerExtensions(this) + SerializationComponentRegistrar.registerExtensions(this, SerializationIntrinsicsState.FORCE_ENABLED) FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar()) } }