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:
-7
@@ -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<ExpressionCodegenExtension>(
|
||||
|
||||
@@ -42,7 +42,7 @@ class PsiInlineCodegen(
|
||||
) : InlineCodegen<ExpressionCodegen>(
|
||||
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 {
|
||||
|
||||
@@ -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<KotlinType> {
|
||||
private val pluginExtensions = ExpressionCodegenExtension.getInstances(state.project)
|
||||
|
||||
override fun putClassInstance(v: InstructionAdapter, type: KotlinType) {
|
||||
DescriptorAsmUtil.putJavaLangClassInstance(v, state.typeMapper.mapType(type), type, state.typeMapper)
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -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
|
||||
}
|
||||
+1
-1
@@ -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) }
|
||||
|
||||
+40
-37
@@ -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,
|
||||
|
||||
+29
-68
@@ -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
|
||||
|
||||
+31
-24
@@ -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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -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())
|
||||
}
|
||||
|
||||
+10
-2
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user