Lazy delegate for serializer in objects, sealed and abstract classes

Fixes Kotlin/kotlinx.serialization#585
This commit is contained in:
Sergey Shanshin
2021-03-03 21:41:37 +03:00
committed by GitHub
parent 89ce629352
commit bf6dda2d99
15 changed files with 423 additions and 68 deletions
@@ -17,7 +17,6 @@ abstract class SerializableCodegen(
bindingContext: BindingContext bindingContext: BindingContext
) : AbstractSerialGenerator(bindingContext, serializableDescriptor) { ) : AbstractSerialGenerator(bindingContext, serializableDescriptor) {
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor) protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor)
protected val staticDescriptor = serializableDescriptor.declaredTypeParameters.isEmpty()
fun generate() { fun generate() {
generateSyntheticInternalConstructor() generateSyntheticInternalConstructor()
@@ -21,9 +21,8 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_PROVIDER_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_PROVIDER_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.isKSerializer
abstract class SerializableCompanionCodegen( abstract class SerializableCompanionCodegen(
protected val companionDescriptor: ClassDescriptor, protected val companionDescriptor: ClassDescriptor,
@@ -44,8 +43,17 @@ abstract class SerializableCompanionCodegen(
"Can't find synthesized 'Companion.serializer()' function to generate, " + "Can't find synthesized 'Companion.serializer()' function to generate, " +
"probably clash with user-defined function has occurred" "probably clash with user-defined function has occurred"
) )
generateSerializerGetter(serializerGetterDescriptor)
if (serializableDescriptor.isSerializableObject || serializableDescriptor.isSealedSerializableClass() || serializableDescriptor.isAbstractSerializableClass()) {
generateLazySerializerGetter(serializerGetterDescriptor)
} else {
generateSerializerGetter(serializerGetterDescriptor)
}
} }
protected abstract fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) protected abstract fun generateSerializerGetter(methodDescriptor: FunctionDescriptor)
protected open fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
generateSerializerGetter(methodDescriptor)
}
} }
@@ -101,6 +101,8 @@ fun ClassDescriptor.serialName(): String {
return annotations.serialNameValue ?: fqNameUnsafe.asString() return annotations.serialNameValue ?: fqNameUnsafe.asString()
} }
internal val ClassDescriptor.isStaticSerializable: Boolean get() = this.declaredTypeParameters.isEmpty()
/** /**
* Returns class descriptor for ContextSerializer or PolymorphicSerializer * Returns class descriptor for ContextSerializer or PolymorphicSerializer
* if [annotations] contains @Contextual or @Polymorphic annotation * if [annotations] contains @Contextual or @Polymorphic annotation
@@ -105,6 +105,26 @@ interface IrBuilderExtension {
return function return function
} }
fun IrClass.createSingletonLambda(
returnType: IrType,
startOffset: Int,
endOffset: Int,
bodyGen: IrBlockBodyBuilder.() -> Unit
): IrSimpleFunction {
val function = compilerContext.irFactory.buildFun {
this.startOffset = startOffset
this.endOffset = endOffset
this.returnType = returnType
name = Name.identifier("<anonymous>")
visibility = DescriptorVisibilities.LOCAL
origin = SERIALIZABLE_PLUGIN_ORIGIN
}
function.body =
DeclarationIrBuilder(compilerContext, function.symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset, bodyGen)
return function
}
fun IrBuilderWithScope.irInvoke( fun IrBuilderWithScope.irInvoke(
dispatchReceiver: IrExpression? = null, dispatchReceiver: IrExpression? = null,
callee: IrFunctionSymbol, callee: IrFunctionSymbol,
@@ -147,6 +167,16 @@ interface IrBuilderExtension {
} }
} }
fun ClassDescriptor.referenceFunctionSymbol(
functionName: String,
predicate: (IrSimpleFunction) -> Boolean = { true }
): IrFunctionSymbol {
val irClass = compilerContext.referenceClass(fqNameSafe)?.owner ?: error("Couldn't load class $this")
val simpleFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>()
return simpleFunctions.filter { it.name.asString() == functionName }.single { predicate(it) }.symbol
}
fun IrBuilderWithScope.createPrimitiveArrayOfExpression( fun IrBuilderWithScope.createPrimitiveArrayOfExpression(
elementPrimitiveType: IrType, elementPrimitiveType: IrType,
arrayElements: List<IrExpression> arrayElements: List<IrExpression>
@@ -7,20 +7,22 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.builders.irInt
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.ir.util.module
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
@@ -34,6 +36,25 @@ class SerializableCompanionIrGenerator(
bindingContext: BindingContext bindingContext: BindingContext
) : SerializableCompanionCodegen(irClass.descriptor, bindingContext), IrBuilderExtension { ) : SerializableCompanionCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
private val lazyDescriptor = irClass.module.findClassAcrossModuleDependencies(
ClassId(FqName("kotlin"), Name.identifier("Lazy"))
)!!
private val lazySafeModeClassDescriptor = irClass.module.findClassAcrossModuleDependencies(
ClassId(FqName("kotlin"), Name.identifier("LazyThreadSafetyMode"))
)!!
private val lazyFunctionSymbol = compilerContext.referenceFunctions(FqName("kotlin").child(Name.identifier("lazy"))).single {
it.descriptor.valueParameters.size == 2 && it.descriptor.valueParameters[0].type == lazySafeModeClassDescriptor.defaultType
}
private val publicationEntryDescriptor = lazySafeModeClassDescriptor.enumEntries().single { it.name == Name.identifier("PUBLICATION") }
private val function0Descriptor = irClass.module.findClassAcrossModuleDependencies(
ClassId(FqName("kotlin"), Name.identifier("Function0"))
)!!
companion object { companion object {
fun generate( fun generate(
irClass: IrClass, irClass: IrClass,
@@ -84,6 +105,70 @@ class SerializableCompanionIrGenerator(
irSerializableClass.annotations += annotationCtorCall irSerializableClass.annotations += annotationCtorCall
} }
override fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
val serializerDescriptor = requireNotNull(
findTypeSerializer(
serializableDescriptor.module,
serializableDescriptor.toSimpleType()
)
)
val field = irClass.addField {
name = Name.identifier(SerialEntityNames.SERIALIZER_LAZY_DELEGATE_FIELD_NAME)
visibility = DescriptorVisibilities.PRIVATE
origin = SERIALIZABLE_PLUGIN_ORIGIN
isFinal = true
isStatic = true
type = lazyDescriptor.defaultType.toIrType()
}.apply {
val lambda = irClass.createSingletonLambda(serializerDescriptor.defaultType.toIrType(), startOffset, endOffset) {
val expr = serializerInstance(
this@SerializableCompanionIrGenerator,
serializerDescriptor, serializableDescriptor.module,
serializableDescriptor.defaultType
)
patchSerializableClassWithMarkerAnnotation(serializerDescriptor)
+irReturn(requireNotNull(expr))
}
val call = IrCallImpl(startOffset, endOffset, type, lazyFunctionSymbol, 0, 2)
call.putValueArgument(
0,
IrGetEnumValueImpl(
startOffset,
endOffset,
publicationEntryDescriptor.classValueType!!.toIrType(),
compilerContext.symbolTable.referenceEnumEntry(publicationEntryDescriptor)
),
)
call.putValueArgument(
1,
IrFunctionExpressionImpl(
startOffset,
endOffset,
function0Descriptor.defaultType.toIrType(),
lambda,
IrStatementOrigin.LAMBDA
),
)
initializer = irClass.factory.createExpressionBody(startOffset, endOffset, call)
}
val valueGetter = compilerContext.referenceClass(lazyDescriptor.fqNameSafe)!!.getPropertyGetter("value")!!
irClass.contributeFunction(methodDescriptor) {
+irReturn(
irGet(
serializerDescriptor.defaultType.toIrType(),
irGetField(null, field), valueGetter
)
)
}
generateSerializerFactoryIfNeeded(methodDescriptor)
}
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) { override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
irClass.contributeFunction(methodDescriptor) { getter -> irClass.contributeFunction(methodDescriptor) { getter ->
val serializer = requireNotNull( val serializer = requireNotNull(
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
@@ -27,13 +26,14 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.getOrPutNullable import org.jetbrains.kotlin.utils.getOrPutNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isStaticSerializable
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.INITIALIZED_DESCRIPTOR_FIELD_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESC_FIELD import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESC_FIELD
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.initializedDescriptorFieldName
class SerializableIrGenerator( class SerializableIrGenerator(
val irClass: IrClass, val irClass: IrClass,
@@ -41,7 +41,7 @@ class SerializableIrGenerator(
bindingContext: BindingContext bindingContext: BindingContext
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension { ) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
private val descriptorGenerationFunctionName = "createInitializedDescriptor" private val descriptorGenerationFunctionName = Name.identifier("createInitializedDescriptor")
private val serialDescClass: ClassDescriptor = serializableDescriptor.module private val serialDescClass: ClassDescriptor = serializableDescriptor.module
.getClassFromSerializationDescriptorsPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS) .getClassFromSerializationDescriptorsPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS)
@@ -49,7 +49,7 @@ class SerializableIrGenerator(
private val serialDescImplClass: ClassDescriptor = serializableDescriptor private val serialDescImplClass: ClassDescriptor = serializableDescriptor
.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL) .getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL)
private val addElementFun = serialDescImplClass.findFunctionSymbol(CallingConventions.addElement) private val addElementFun = serialDescImplClass.referenceFunctionSymbol(CallingConventions.addElement)
private fun IrClass.hasSerializableAnnotationWithoutArgs(): Boolean { private fun IrClass.hasSerializableAnnotationWithoutArgs(): Boolean {
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return false val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return false
@@ -170,7 +170,7 @@ class SerializableIrGenerator(
} }
private fun IrBlockBodyBuilder.getSerialDescriptorExpr(): IrExpression { private fun IrBlockBodyBuilder.getSerialDescriptorExpr(): IrExpression {
return if (serializableDescriptor.shouldHaveGeneratedSerializer && staticDescriptor) { return if (serializableDescriptor.isStaticSerializable) {
val serializer = serializableDescriptor.classSerializer!! val serializer = serializableDescriptor.classSerializer!!
val serialDescriptorGetter = compilerContext.referenceClass(serializer.fqNameSafe)!!.getPropertyGetter(SERIAL_DESC_FIELD)!! val serialDescriptorGetter = compilerContext.referenceClass(serializer.fqNameSafe)!!.getPropertyGetter(SERIAL_DESC_FIELD)!!
irGet( irGet(
@@ -187,7 +187,7 @@ class SerializableIrGenerator(
val serialDescItType = serialDescClass.defaultType.toIrType() val serialDescItType = serialDescClass.defaultType.toIrType()
val function = irClass.createInlinedFunction( val function = irClass.createInlinedFunction(
Name.identifier(descriptorGenerationFunctionName), descriptorGenerationFunctionName,
DescriptorVisibilities.PRIVATE, DescriptorVisibilities.PRIVATE,
SERIALIZABLE_PLUGIN_ORIGIN, SERIALIZABLE_PLUGIN_ORIGIN,
serialDescItType serialDescItType
@@ -203,7 +203,7 @@ class SerializableIrGenerator(
} }
return irClass.addField { return irClass.addField {
name = Name.identifier(initializedDescriptorFieldName) name = Name.identifier(INITIALIZED_DESCRIPTOR_FIELD_NAME)
visibility = DescriptorVisibilities.PRIVATE visibility = DescriptorVisibilities.PRIVATE
origin = SERIALIZABLE_PLUGIN_ORIGIN origin = SERIALIZABLE_PLUGIN_ORIGIN
isFinal = true isFinal = true
@@ -234,16 +234,6 @@ class SerializableIrGenerator(
) )
} }
private inline fun ClassDescriptor.findFunctionSymbol(
functionName: String,
predicate: (IrSimpleFunction) -> Boolean = { true }
): IrFunctionSymbol {
val irClass = compilerContext.referenceClass(fqNameSafe)?.owner ?: error("Couldn't load class $this")
val simpleFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>()
return simpleFunctions.filter { it.name.asString() == functionName }.single { predicate(it) }.symbol
}
private fun IrBlockBodyBuilder.generateSuperNonSerializableCall(superClass: IrClass) { private fun IrBlockBodyBuilder.generateSuperNonSerializableCall(superClass: IrClass) {
val ctorRef = superClass.declarations.filterIsInstance<IrConstructor>().singleOrNull { it.valueParameters.isEmpty() } val ctorRef = superClass.declarations.filterIsInstance<IrConstructor>().singleOrNull { it.valueParameters.isEmpty() }
?: error("Non-serializable parent of serializable $serializableDescriptor must have no arg constructor") ?: error("Non-serializable parent of serializable $serializableDescriptor must have no arg constructor")
@@ -36,7 +36,7 @@ class SerializerForEnumsGenerator(
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS) val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val encodeEnum = encoderClass.referenceMethod(CallingConventions.encodeEnum) val encodeEnum = encoderClass.referenceFunctionSymbol(CallingConventions.encodeEnum)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
val serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" } val serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" }
@@ -52,7 +52,7 @@ class SerializerForEnumsGenerator(
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS) val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val decode = decoderClass.referenceMethod(CallingConventions.decodeEnum) val decode = decoderClass.referenceFunctionSymbol(CallingConventions.decodeEnum)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
val serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" } val serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" }
@@ -109,7 +109,7 @@ class SerializerForEnumsGenerator(
copySerialInfoAnnotationsToDescriptor( copySerialInfoAnnotationsToDescriptor(
entry.annotations.mapNotNull(compilerContext.typeTranslator.constantValueGenerator::generateAnnotationConstructorCall), entry.annotations.mapNotNull(compilerContext.typeTranslator.constantValueGenerator::generateAnnotationConstructorCall),
localDescriptor, localDescriptor,
serialDescImplClass.referenceMethod(CallingConventions.addAnnotation) serialDescImplClass.referenceFunctionSymbol(CallingConventions.addAnnotation)
) )
} }
} }
@@ -32,7 +32,7 @@ class SerializerForInlineClassGenerator(
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS) val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val encodeInline = encoderClass.referenceMethod(CallingConventions.encodeInline) val encodeInline = encoderClass.referenceFunctionSymbol(CallingConventions.encodeInline)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
// val inlineEncoder = encoder.encodeInline() // val inlineEncoder = encoder.encodeInline()
@@ -45,14 +45,14 @@ class SerializerForInlineClassGenerator(
// inlineEncoder.encodeInt/String/SerializableValue // inlineEncoder.encodeInt/String/SerializableValue
val elementCall = formEncodeDecodePropertyCall(irGet(inlineEncoder), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti -> val elementCall = formEncodeDecodePropertyCall(irGet(inlineEncoder), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
val f = val f =
encoderClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}SerializableValue") encoderClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}SerializableValue")
f to listOf( f to listOf(
innerSerial, innerSerial,
value value
) )
}, { }, {
val f = val f =
encoderClass.referenceMethod("${CallingConventions.encode}${it.elementMethodPrefix}") encoderClass.referenceFunctionSymbol("${CallingConventions.encode}${it.elementMethodPrefix}")
val args = if (it.elementMethodPrefix != "Unit") listOf(value) else emptyList() val args = if (it.elementMethodPrefix != "Unit") listOf(value) else emptyList()
f to args f to args
}) })
@@ -67,7 +67,7 @@ class SerializerForInlineClassGenerator(
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS) val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS)
val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val decodeInline = decoderClass.referenceMethod(CallingConventions.decodeInline) val decodeInline = decoderClass.referenceFunctionSymbol(CallingConventions.decodeInline)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
// val inlineDecoder = decoder.decodeInline() // val inlineDecoder = decoder.decodeInline()
@@ -76,9 +76,9 @@ class SerializerForInlineClassGenerator(
val property = serializableProperties.first() val property = serializableProperties.first()
val inlinedType = property.type.toIrType() val inlinedType = property.type.toIrType()
val actualCall = formEncodeDecodePropertyCall(inlineDecoder, loadFunc.dispatchReceiverParameter!!, property, { innerSerial, sti -> val actualCall = formEncodeDecodePropertyCall(inlineDecoder, loadFunc.dispatchReceiverParameter!!, property, { innerSerial, sti ->
decoderClass.referenceMethod( "${CallingConventions.decode}${sti.elementMethodPrefix}SerializableValue") to listOf(innerSerial) decoderClass.referenceFunctionSymbol( "${CallingConventions.decode}${sti.elementMethodPrefix}SerializableValue") to listOf(innerSerial)
}, { }, {
decoderClass.referenceMethod("${CallingConventions.decode}${it.elementMethodPrefix}") to listOf() decoderClass.referenceFunctionSymbol("${CallingConventions.decode}${it.elementMethodPrefix}") to listOf()
}, returnTypeHint = inlinedType) }, returnTypeHint = inlinedType)
val value = coerceToBox(actualCall, loadFunc.returnType) val value = coerceToBox(actualCall, loadFunc.returnType)
+irReturn(value) +irReturn(value)
@@ -58,7 +58,7 @@ open class SerializerIrGenerator(
override fun generateSerialDesc() { override fun generateSerialDesc() {
val desc: PropertyDescriptor = generatedSerialDescPropertyDescriptor ?: return val desc: PropertyDescriptor = generatedSerialDescPropertyDescriptor ?: return
val addFuncS = serialDescImplClass.referenceMethod(CallingConventions.addElement) val addFuncS = serialDescImplClass.referenceFunctionSymbol(CallingConventions.addElement)
val thisAsReceiverParameter = irClass.thisReceiver!! val thisAsReceiverParameter = irClass.thisReceiver!!
lateinit var prop: IrProperty lateinit var prop: IrProperty
@@ -95,7 +95,7 @@ open class SerializerIrGenerator(
copySerialInfoAnnotationsToDescriptor( copySerialInfoAnnotationsToDescriptor(
serializableIrClass.annotations, serializableIrClass.annotations,
localDesc, localDesc,
serialDescImplClass.referenceMethod(CallingConventions.addClassAnnotation) serialDescImplClass.referenceFunctionSymbol(CallingConventions.addClassAnnotation)
) )
// save local descriptor to field // save local descriptor to field
@@ -145,7 +145,7 @@ open class SerializerIrGenerator(
copySerialInfoAnnotationsToDescriptor( copySerialInfoAnnotationsToDescriptor(
property.annotations, property.annotations,
localDescriptor, localDescriptor,
serialDescImplClass.referenceMethod(CallingConventions.addAnnotation) serialDescImplClass.referenceFunctionSymbol(CallingConventions.addAnnotation)
) )
} }
} }
@@ -233,12 +233,6 @@ open class SerializerIrGenerator(
/* Already implemented in .generateSerialClassDesc ? */ /* Already implemented in .generateSerialClassDesc ? */
} }
protected inline fun ClassDescriptor.referenceMethod(methodName: String, predicate: (IrSimpleFunction) -> Boolean = { true }): IrFunctionSymbol {
val irClass = compilerContext.referenceClass(fqNameSafe)?.owner ?: error("Couldn't load class $this")
val simpleFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>()
return simpleFunctions.filter { it.name.asString() == methodName }.single { predicate(it) }.symbol
}
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc -> override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
fun irThis(): IrExpression = fun irThis(): IrExpression =
@@ -252,7 +246,7 @@ open class SerializerIrGenerator(
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc") val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
// fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder // fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder
val beginFunc = encoderClass.referenceMethod(CallingConventions.begin) { it.valueParameters.size == 1 } val beginFunc = encoderClass.referenceFunctionSymbol(CallingConventions.begin) { it.valueParameters.size == 1 }
val call = irCall(beginFunc, type = kOutputClass.defaultType.toIrType()).mapValueParametersIndexed { _, _ -> val call = irCall(beginFunc, type = kOutputClass.defaultType.toIrType()).mapValueParametersIndexed { _, _ ->
irGet(localSerialDesc) irGet(localSerialDesc)
@@ -294,7 +288,7 @@ open class SerializerIrGenerator(
// output.writeXxxElementValue(classDesc, index, value) // output.writeXxxElementValue(classDesc, index, value)
val elementCall = formEncodeDecodePropertyCall(irGet(localOutput), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti -> val elementCall = formEncodeDecodePropertyCall(irGet(localOutput), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
val f = val f =
kOutputClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}") kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
f to listOf( f to listOf(
irGet(localSerialDesc), irGet(localSerialDesc),
irInt(index), irInt(index),
@@ -303,7 +297,7 @@ open class SerializerIrGenerator(
) )
}, { }, {
val f = val f =
kOutputClass.referenceMethod("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}") kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}")
val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index)) val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index))
if (it.elementMethodPrefix != "Unit") args.add(property.irGet()) if (it.elementMethodPrefix != "Unit") args.add(property.irGet())
f to args f to args
@@ -318,7 +312,7 @@ open class SerializerIrGenerator(
// if ( if (output.shouldEncodeElementDefault(this.descriptor, i)) true else {obj.prop != DEFAULT_VALUE} ) { // if ( if (output.shouldEncodeElementDefault(this.descriptor, i)) true else {obj.prop != DEFAULT_VALUE} ) {
// output.encodeIntElement(this.descriptor, i, obj.prop) // output.encodeIntElement(this.descriptor, i, obj.prop)
// block {obj.prop != DEFAULT_VALUE} may contain several statements // block {obj.prop != DEFAULT_VALUE} may contain several statements
val shouldEncodeFunc = kOutputClass.referenceMethod(CallingConventions.shouldEncodeDefault) val shouldEncodeFunc = kOutputClass.referenceFunctionSymbol(CallingConventions.shouldEncodeDefault)
val partA = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index)) val partA = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index))
val partB = irNotEquals(property.irGet(), initializerAdapter(property.irField.initializer!!)) val partB = irNotEquals(property.irGet(), initializerAdapter(property.irField.initializer!!))
// Ir infrastructure does not have dedicated symbol for ||, so // Ir infrastructure does not have dedicated symbol for ||, so
@@ -329,7 +323,7 @@ open class SerializerIrGenerator(
} }
// output.writeEnd(serialClassDesc) // output.writeEnd(serialClassDesc)
val wEndFunc = kOutputClass.referenceMethod(CallingConventions.end) val wEndFunc = kOutputClass.referenceFunctionSymbol(CallingConventions.end)
+irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc)) +irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc))
} }
@@ -424,7 +418,7 @@ open class SerializerIrGenerator(
} }
//input = input.beginStructure(...) //input = input.beginStructure(...)
val beginFunc = decoderClass.referenceMethod(CallingConventions.begin) { it.valueParameters.size == 1 } val beginFunc = decoderClass.referenceFunctionSymbol(CallingConventions.begin) { it.valueParameters.size == 1 }
val call = irInvoke( val call = irInvoke(
irGet(loadFunc.valueParameters[0]), irGet(loadFunc.valueParameters[0]),
beginFunc, beginFunc,
@@ -438,13 +432,13 @@ open class SerializerIrGenerator(
serializableProperties.mapIndexed { index, property -> serializableProperties.mapIndexed { index, property ->
val body = irBlock { val body = irBlock {
val decodeFuncToCall = formEncodeDecodePropertyCall(localInput.get(), loadFunc.dispatchReceiverParameter!!, property, {innerSerial, sti -> val decodeFuncToCall = formEncodeDecodePropertyCall(localInput.get(), loadFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
inputClass.referenceMethod( inputClass.referenceFunctionSymbol(
"${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}", {it.valueParameters.size == 4} "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}", {it.valueParameters.size == 4}
) to listOf( ) to listOf(
localSerialDesc.get(), irInt(index), innerSerial, serialPropertiesMap.getValue(property.descriptor).get() localSerialDesc.get(), irInt(index), innerSerial, serialPropertiesMap.getValue(property.descriptor).get()
) )
}, { }, {
inputClass.referenceMethod( inputClass.referenceFunctionSymbol(
"${CallingConventions.decode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}", {it.valueParameters.size == 2} "${CallingConventions.decode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}", {it.valueParameters.size == 2}
) to listOf( ) to listOf(
localSerialDesc.get(), irInt(index) localSerialDesc.get(), irInt(index)
@@ -464,7 +458,7 @@ open class SerializerIrGenerator(
} }
// if (decoder.decodeSequentially()) // if (decoder.decodeSequentially())
val decodeSequentiallyCall = irInvoke(localInput.get(), inputClass.referenceMethod(CallingConventions.decodeSequentially)) val decodeSequentiallyCall = irInvoke(localInput.get(), inputClass.referenceFunctionSymbol(CallingConventions.decodeSequentially))
val sequentialPart = irBlock { val sequentialPart = irBlock {
decoderCalls.forEach { (_, expr) -> +expr.deepCopyWithVariables() } decoderCalls.forEach { (_, expr) -> +expr.deepCopyWithVariables() }
@@ -473,7 +467,7 @@ open class SerializerIrGenerator(
val byIndexPart: IrExpression = irWhile().also { loop -> val byIndexPart: IrExpression = irWhile().also { loop ->
loop.condition = flagVar.get() loop.condition = flagVar.get()
loop.body = irBlock { loop.body = irBlock {
val readElementF = inputClass.referenceMethod(CallingConventions.decodeElementIndex) val readElementF = inputClass.referenceFunctionSymbol(CallingConventions.decodeElementIndex)
+irSet(indexVar.symbol, irInvoke(localInput.get(), readElementF, localSerialDesc.get())) +irSet(indexVar.symbol, irInvoke(localInput.get(), readElementF, localSerialDesc.get()))
+irWhen { +irWhen {
// if index == -1 (READ_DONE) break loop // if index == -1 (READ_DONE) break loop
@@ -502,7 +496,7 @@ open class SerializerIrGenerator(
+irIfThenElse(compilerContext.irBuiltIns.unitType, decodeSequentiallyCall, sequentialPart, byIndexPart) +irIfThenElse(compilerContext.irBuiltIns.unitType, decodeSequentiallyCall, sequentialPart, byIndexPart)
//input.endStructure(...) //input.endStructure(...)
val endFunc = inputClass.referenceMethod(CallingConventions.end) val endFunc = inputClass.referenceFunctionSymbol(CallingConventions.end)
+irInvoke( +irInvoke(
localInput.get(), localInput.get(),
endFunc, endFunc,
@@ -7,17 +7,31 @@ 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.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.load.kotlin.internalName
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.resolve.scopes.MemberScope
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.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.*
@@ -41,6 +55,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UN
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.internalPackageFqName import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.internalPackageFqName
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.packageFqName import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.packageFqName
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -55,6 +70,11 @@ internal val decoderType = Type.getObjectType("kotlinx/serialization/encoding/$D
internal val kInputType = Type.getObjectType("kotlinx/serialization/encoding/$STRUCTURE_DECODER_CLASS") internal val kInputType = Type.getObjectType("kotlinx/serialization/encoding/$STRUCTURE_DECODER_CLASS")
internal val pluginUtilsType = Type.getObjectType("kotlinx/serialization/internal/${PLUGIN_EXCEPTIONS_FILE}Kt") internal val pluginUtilsType = Type.getObjectType("kotlinx/serialization/internal/${PLUGIN_EXCEPTIONS_FILE}Kt")
internal val jvmLambdaType = Type.getObjectType("kotlin/jvm/internal/Lambda")
internal val kotlinLazyType = Type.getObjectType("kotlin/Lazy")
internal val function0Type = Type.getObjectType("kotlin/jvm/functions/Function0")
internal val threadSafeModeType = Type.getObjectType("kotlin/LazyThreadSafetyMode")
internal val kSerialSaverType = Type.getObjectType("kotlinx/serialization/$SERIAL_SAVER_CLASS") internal val kSerialSaverType = Type.getObjectType("kotlinx/serialization/$SERIAL_SAVER_CLASS")
internal val kSerialLoaderType = Type.getObjectType("kotlinx/serialization/$SERIAL_LOADER_CLASS") internal val kSerialLoaderType = Type.getObjectType("kotlinx/serialization/$SERIAL_LOADER_CLASS")
internal val kSerializerType = Type.getObjectType("kotlinx/serialization/$KSERIALIZER_CLASS") internal val kSerializerType = Type.getObjectType("kotlinx/serialization/$KSERIALIZER_CLASS")
@@ -65,7 +85,7 @@ internal val serializationExceptionMissingFieldName = "kotlinx/serialization/$MI
internal val serializationExceptionUnknownIndexName = "kotlinx/serialization/$UNKNOWN_FIELD_EXC" internal val serializationExceptionUnknownIndexName = "kotlinx/serialization/$UNKNOWN_FIELD_EXC"
internal val descriptorGetterName = JvmAbi.getterName(SERIAL_DESC_FIELD) internal val descriptorGetterName = JvmAbi.getterName(SERIAL_DESC_FIELD)
internal val getLazyValueName = JvmAbi.getterName("value")
val OPT_MASK_TYPE: Type = Type.INT_TYPE val OPT_MASK_TYPE: Type = Type.INT_TYPE
val OPT_MASK_BITS = 32 val OPT_MASK_BITS = 32
@@ -485,3 +505,161 @@ fun InstructionAdapter.stackValueDefault(type: Type) {
else -> aconst(null) else -> aconst(null)
} }
} }
internal fun createSingletonLambda(
lambdaName: String,
outerClassCodegen: ImplementationBodyCodegen,
resultSimpleType: SimpleType,
block: InstructionAdapter.(ImplementationBodyCodegen) -> Unit
): Type {
val lambdaType = Type.getObjectType("${outerClassCodegen.className}\$$lambdaName")
val lambdaClass = ClassDescriptorImpl(
outerClassCodegen.descriptor,
Name.identifier(lambdaName),
Modality.FINAL,
ClassKind.CLASS,
listOf(outerClassCodegen.descriptor.module.builtIns.anyType),
SourceElement.NO_SOURCE,
false,
LockBasedStorageManager.NO_LOCKS
)
lambdaClass.initialize(
MemberScope.Empty, emptySet(),
DescriptorFactory.createPrimaryConstructorForObject(lambdaClass, lambdaClass.source)
)
val lambdaClassBuilder = outerClassCodegen.state.factory.newVisitor(
JvmDeclarationOrigin(JvmDeclarationOriginKind.OTHER, null, lambdaClass),
Type.getObjectType(lambdaType.internalName),
outerClassCodegen.myClass.containingKtFile
)
val classContextForCreator = ClassContext(
outerClassCodegen.typeMapper, lambdaClass, OwnerKind.IMPLEMENTATION, outerClassCodegen.context.parentContext, null
)
val lambdaCodegen = ImplementationBodyCodegen(
outerClassCodegen.myClass,
classContextForCreator,
lambdaClassBuilder,
outerClassCodegen.state,
outerClassCodegen.parentCodegen,
false
)
lambdaCodegen.v.defineClass(
null,
outerClassCodegen.state.classFileVersion,
Opcodes.ACC_FINAL or Opcodes.ACC_SUPER or Opcodes.ACC_SYNTHETIC,
lambdaType.internalName,
"L${jvmLambdaType.internalName};L${function0Type.internalName}<L${kSerializerType.internalName}<*>;>;",
jvmLambdaType.internalName,
arrayOf(function0Type.internalName)
)
outerClassCodegen.v.visitInnerClass(
lambdaType.internalName,
null,
null,
Opcodes.ACC_FINAL or Opcodes.ACC_SUPER or Opcodes.ACC_SYNTHETIC or Opcodes.ACC_STATIC
)
lambdaCodegen.v.visitInnerClass(
lambdaType.internalName,
null,
null,
Opcodes.ACC_FINAL or Opcodes.ACC_SUPER or Opcodes.ACC_SYNTHETIC or Opcodes.ACC_STATIC
)
lambdaCodegen.v.visitOuterClass(
outerClassCodegen.className,
null,
null
)
lambdaCodegen.v.visitSource(
outerClassCodegen.myClass.containingKtFile.name,
null
)
val constr = ClassConstructorDescriptorImpl.createSynthesized(
lambdaClass,
Annotations.EMPTY,
false,
lambdaClass.source
)
constr.initialize(
emptyList(),
DescriptorVisibilities.PUBLIC
)
constr.returnType = lambdaClass.defaultType
lambdaCodegen.generateMethod(constr) { _, _ ->
load(0, lambdaType)
iconst(0)
invokespecial(jvmLambdaType.internalName, "<init>", "(I)V", false)
areturn(Type.VOID_TYPE)
}
lambdaCodegen.v.newField(
OtherOrigin(lambdaCodegen.myClass.psiOrParent),
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_STATIC or Opcodes.ACC_SYNTHETIC,
JvmAbi.INSTANCE_FIELD,
lambdaType.descriptor,
null,
null
)
val lambdaClInit = lambdaCodegen.createOrGetClInitCodegen()
with(lambdaClInit.v) {
anew(lambdaType)
dup()
invokespecial(lambdaType.internalName, "<init>", "()V", false)
putstatic(lambdaType.internalName, JvmAbi.INSTANCE_FIELD, lambdaType.descriptor)
areturn(Type.VOID_TYPE)
visitEnd()
}
val invokeFunction = SimpleFunctionDescriptorImpl.create(
lambdaCodegen.descriptor,
Annotations.EMPTY,
Name.identifier("invoke"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
lambdaCodegen.descriptor.source
)
invokeFunction.initialize(
null,
lambdaCodegen.descriptor.thisAsReceiverParameter,
emptyList(),
emptyList(),
resultSimpleType,
Modality.FINAL,
DescriptorVisibilities.PUBLIC
)
lambdaCodegen.generateMethod(invokeFunction) { _, _ ->
block(lambdaCodegen)
}
val bridgeInvokeFunction = SimpleFunctionDescriptorImpl.create(
lambdaCodegen.descriptor,
Annotations.EMPTY,
Name.identifier("invoke"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
lambdaCodegen.descriptor.source
)
bridgeInvokeFunction.initialize(
null,
lambdaCodegen.descriptor.thisAsReceiverParameter,
emptyList(),
emptyList(),
lambdaCodegen.descriptor.builtIns.anyType,
Modality.FINAL,
DescriptorVisibilities.PUBLIC
)
lambdaCodegen.generateMethod(bridgeInvokeFunction) { _, _ ->
load(0, lambdaType)
invokevirtual(lambdaType.internalName, "invoke", "()L${resultSimpleType.toClassDescriptor.classId!!.internalName};", false)
areturn(kSerializerType)
}
writeSyntheticClassMetadata(lambdaClassBuilder, lambdaCodegen.state)
lambdaClassBuilder.done()
return lambdaType
}
@@ -35,8 +35,8 @@ import org.jetbrains.kotlinx.serialization.compiler.diagnostic.VersionReader
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ARRAY_MASK_FIELD_MISSING_FUNC_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ARRAY_MASK_FIELD_MISSING_FUNC_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.INITIALIZED_DESCRIPTOR_FIELD_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SINGLE_MASK_FIELD_MISSING_FUNC_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SINGLE_MASK_FIELD_MISSING_FUNC_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.initializedDescriptorFieldName
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -347,14 +347,14 @@ class SerializableCodegenImpl(
} }
private fun InstructionAdapter.stackSerialDescriptor() { private fun InstructionAdapter.stackSerialDescriptor() {
if (serializableDescriptor.shouldHaveGeneratedSerializer && staticDescriptor) { if (serializableDescriptor.isStaticSerializable) {
val serializer = serializableDescriptor.classSerializer!! val serializer = serializableDescriptor.classSerializer!!
StackValue.singleton(serializer, classCodegen.typeMapper).put(kSerializerType, this) StackValue.singleton(serializer, classCodegen.typeMapper).put(kSerializerType, this)
invokeinterface(kSerializerType.internalName, descriptorGetterName, "()${descType.descriptor}") invokeinterface(kSerializerType.internalName, descriptorGetterName, "()${descType.descriptor}")
} else { } else {
generateStaticDescriptorField() generateStaticDescriptorField()
getstatic(thisAsmType.internalName, initializedDescriptorFieldName, descType.descriptor) getstatic(thisAsmType.internalName, INITIALIZED_DESCRIPTOR_FIELD_NAME, descType.descriptor)
} }
} }
@@ -362,7 +362,7 @@ class SerializableCodegenImpl(
val flags = Opcodes.ACC_PRIVATE or Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC or Opcodes.ACC_STATIC val flags = Opcodes.ACC_PRIVATE or Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC or Opcodes.ACC_STATIC
classCodegen.v.newField( classCodegen.v.newField(
OtherOrigin(classCodegen.myClass.psiOrParent), flags, OtherOrigin(classCodegen.myClass.psiOrParent), flags,
initializedDescriptorFieldName, descType.descriptor, null, null INITIALIZED_DESCRIPTOR_FIELD_NAME, descType.descriptor, null, null
) )
val clInit = classCodegen.createOrGetClInitCodegen() val clInit = classCodegen.createOrGetClInitCodegen()
@@ -380,7 +380,7 @@ class SerializableCodegenImpl(
invokevirtual(descImplType.internalName, CallingConventions.addElement, "(Ljava/lang/String;Z)V", false) invokevirtual(descImplType.internalName, CallingConventions.addElement, "(Ljava/lang/String;Z)V", false)
} }
putstatic(thisAsmType.internalName, initializedDescriptorFieldName, descType.descriptor) putstatic(thisAsmType.internalName, INITIALIZED_DESCRIPTOR_FIELD_NAME, descType.descriptor)
} }
} }
@@ -18,12 +18,17 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_LAZY_DELEGATE_FIELD_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.getKSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.toSimpleType import org.jetbrains.kotlinx.serialization.compiler.resolve.toSimpleType
import org.jetbrains.org.objectweb.asm.Opcodes
class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationBodyCodegen) : class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationBodyCodegen) :
SerializableCompanionCodegen(classCodegen.descriptor, classCodegen.bindingContext) { SerializableCompanionCodegen(classCodegen.descriptor, classCodegen.bindingContext) {
@@ -36,6 +41,61 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
} }
} }
override fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
// Create field for lazy delegate
classCodegen.v.newField(
OtherOrigin(classCodegen.myClass.psiOrParent),
Opcodes.ACC_PRIVATE or Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC or Opcodes.ACC_STATIC,
SERIALIZER_LAZY_DELEGATE_FIELD_NAME,
kotlinLazyType.descriptor,
"L${kotlinLazyType.internalName}<L${kSerializerType.internalName}<*>;>;",
null
)
// create singleton lambda class
val lambdaType =
createSingletonLambda("serializer\$1", classCodegen, companionDescriptor.getKSerializer().defaultType) { lambdaCodegen ->
val serializerDescriptor = requireNotNull(
findTypeSerializer(
serializableDescriptor.module,
serializableDescriptor.toSimpleType()
)
)
stackValueSerializerInstance(
lambdaCodegen,
serializableDescriptor.module,
serializableDescriptor.defaultType,
serializerDescriptor,
this,
null
)
areturn(kSerializerType)
}
// initialize lazy delegate
val clInit = classCodegen.createOrGetClInitCodegen()
with(clInit.v) {
getstatic(threadSafeModeType.internalName, "PUBLICATION", threadSafeModeType.descriptor)
getstatic(lambdaType.internalName, JvmAbi.INSTANCE_FIELD, lambdaType.descriptor)
checkcast(function0Type)
invokestatic(
"kotlin/LazyKt",
"lazy",
"(${threadSafeModeType.descriptor}${function0Type.descriptor})${kotlinLazyType.descriptor}",
false
)
putstatic(classCodegen.className, SERIALIZER_LAZY_DELEGATE_FIELD_NAME, kotlinLazyType.descriptor)
}
// create serializer getter
classCodegen.generateMethod(methodDescriptor) { _, _ ->
getstatic(classCodegen.className, SERIALIZER_LAZY_DELEGATE_FIELD_NAME, kotlinLazyType.descriptor)
invokeinterface(kotlinLazyType.internalName, getLazyValueName, "()Ljava/lang/Object;")
checkcast(kSerializerType)
areturn(kSerializerType)
}
}
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) { override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
val serial = requireNotNull( val serial = requireNotNull(
findTypeSerializer( findTypeSerializer(
@@ -44,7 +44,8 @@ object SerialEntityNames {
const val LOAD = "deserialize" const val LOAD = "deserialize"
const val SERIALIZER_CLASS = "\$serializer" const val SERIALIZER_CLASS = "\$serializer"
const val initializedDescriptorFieldName = "\$initializedDescriptor" const val INITIALIZED_DESCRIPTOR_FIELD_NAME = "\$initializedDescriptor"
const val SERIALIZER_LAZY_DELEGATE_FIELD_NAME = "\$serializer\$delegate"
// classes // classes
val KSERIALIZER_NAME = Name.identifier(KSERIALIZER_CLASS) val KSERIALIZER_NAME = Name.identifier(KSERIALIZER_CLASS)
@@ -69,6 +69,14 @@ internal fun ClassDescriptor.getKSerializerConstructorMarker(): ClassDescriptor
) )
)!! )!!
internal fun ClassDescriptor.getKSerializer(): ClassDescriptor =
module.findClassAcrossModuleDependencies(
ClassId(
SerializationPackages.packageFqName,
SerialEntityNames.KSERIALIZER_NAME
)
)!!
internal fun getInternalPackageFqn(classSimpleName: String): FqName = internal fun getInternalPackageFqn(classSimpleName: String): FqName =
SerializationPackages.internalPackageFqName.child(Name.identifier(classSimpleName)) SerializationPackages.internalPackageFqName.child(Name.identifier(classSimpleName))