Lazy delegate for serializer in objects, sealed and abstract classes
Fixes Kotlin/kotlinx.serialization#585
This commit is contained in:
-1
@@ -17,7 +17,6 @@ abstract class SerializableCodegen(
|
||||
bindingContext: BindingContext
|
||||
) : AbstractSerialGenerator(bindingContext, serializableDescriptor) {
|
||||
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor)
|
||||
protected val staticDescriptor = serializableDescriptor.declaredTypeParameters.isEmpty()
|
||||
|
||||
fun generate() {
|
||||
generateSyntheticInternalConstructor()
|
||||
|
||||
+12
-4
@@ -21,9 +21,8 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
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.getSerializableClassDescriptorByCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isKSerializer
|
||||
|
||||
abstract class SerializableCompanionCodegen(
|
||||
protected val companionDescriptor: ClassDescriptor,
|
||||
@@ -44,8 +43,17 @@ abstract class SerializableCompanionCodegen(
|
||||
"Can't find synthesized 'Companion.serializer()' function to generate, " +
|
||||
"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 open fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
generateSerializerGetter(methodDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -101,6 +101,8 @@ fun ClassDescriptor.serialName(): String {
|
||||
return annotations.serialNameValue ?: fqNameUnsafe.asString()
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.isStaticSerializable: Boolean get() = this.declaredTypeParameters.isEmpty()
|
||||
|
||||
/**
|
||||
* Returns class descriptor for ContextSerializer or PolymorphicSerializer
|
||||
* if [annotations] contains @Contextual or @Polymorphic annotation
|
||||
|
||||
+30
@@ -105,6 +105,26 @@ interface IrBuilderExtension {
|
||||
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(
|
||||
dispatchReceiver: IrExpression? = null,
|
||||
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(
|
||||
elementPrimitiveType: IrType,
|
||||
arrayElements: List<IrExpression>
|
||||
|
||||
+92
-7
@@ -7,20 +7,22 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irInt
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
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.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
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.module
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
@@ -34,6 +36,25 @@ class SerializableCompanionIrGenerator(
|
||||
bindingContext: BindingContext
|
||||
) : 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 {
|
||||
fun generate(
|
||||
irClass: IrClass,
|
||||
@@ -84,6 +105,70 @@ class SerializableCompanionIrGenerator(
|
||||
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) {
|
||||
irClass.contributeFunction(methodDescriptor) { getter ->
|
||||
val serializer = requireNotNull(
|
||||
@@ -138,4 +223,4 @@ class SerializableCompanionIrGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+7
-17
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
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.util.*
|
||||
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.utils.getOrPutNullable
|
||||
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.diagnostic.serializableAnnotationIsUseless
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||
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.SERIAL_DESC_FIELD
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.initializedDescriptorFieldName
|
||||
|
||||
class SerializableIrGenerator(
|
||||
val irClass: IrClass,
|
||||
@@ -41,7 +41,7 @@ class SerializableIrGenerator(
|
||||
bindingContext: BindingContext
|
||||
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
|
||||
|
||||
private val descriptorGenerationFunctionName = "createInitializedDescriptor"
|
||||
private val descriptorGenerationFunctionName = Name.identifier("createInitializedDescriptor")
|
||||
|
||||
private val serialDescClass: ClassDescriptor = serializableDescriptor.module
|
||||
.getClassFromSerializationDescriptorsPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS)
|
||||
@@ -49,7 +49,7 @@ class SerializableIrGenerator(
|
||||
private val serialDescImplClass: ClassDescriptor = serializableDescriptor
|
||||
.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 {
|
||||
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return false
|
||||
@@ -170,7 +170,7 @@ class SerializableIrGenerator(
|
||||
}
|
||||
|
||||
private fun IrBlockBodyBuilder.getSerialDescriptorExpr(): IrExpression {
|
||||
return if (serializableDescriptor.shouldHaveGeneratedSerializer && staticDescriptor) {
|
||||
return if (serializableDescriptor.isStaticSerializable) {
|
||||
val serializer = serializableDescriptor.classSerializer!!
|
||||
val serialDescriptorGetter = compilerContext.referenceClass(serializer.fqNameSafe)!!.getPropertyGetter(SERIAL_DESC_FIELD)!!
|
||||
irGet(
|
||||
@@ -187,7 +187,7 @@ class SerializableIrGenerator(
|
||||
val serialDescItType = serialDescClass.defaultType.toIrType()
|
||||
|
||||
val function = irClass.createInlinedFunction(
|
||||
Name.identifier(descriptorGenerationFunctionName),
|
||||
descriptorGenerationFunctionName,
|
||||
DescriptorVisibilities.PRIVATE,
|
||||
SERIALIZABLE_PLUGIN_ORIGIN,
|
||||
serialDescItType
|
||||
@@ -203,7 +203,7 @@ class SerializableIrGenerator(
|
||||
}
|
||||
|
||||
return irClass.addField {
|
||||
name = Name.identifier(initializedDescriptorFieldName)
|
||||
name = Name.identifier(INITIALIZED_DESCRIPTOR_FIELD_NAME)
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
origin = SERIALIZABLE_PLUGIN_ORIGIN
|
||||
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) {
|
||||
val ctorRef = superClass.declarations.filterIsInstance<IrConstructor>().singleOrNull { it.valueParameters.isEmpty() }
|
||||
?: error("Non-serializable parent of serializable $serializableDescriptor must have no arg constructor")
|
||||
|
||||
+3
-3
@@ -36,7 +36,7 @@ class SerializerForEnumsGenerator(
|
||||
|
||||
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS)
|
||||
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 serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" }
|
||||
@@ -52,7 +52,7 @@ class SerializerForEnumsGenerator(
|
||||
|
||||
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS)
|
||||
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 serializableIrClass = requireNotNull(serializableIrClass) { "Enums do not support external serialization" }
|
||||
@@ -109,7 +109,7 @@ class SerializerForEnumsGenerator(
|
||||
copySerialInfoAnnotationsToDescriptor(
|
||||
entry.annotations.mapNotNull(compilerContext.typeTranslator.constantValueGenerator::generateAnnotationConstructorCall),
|
||||
localDescriptor,
|
||||
serialDescImplClass.referenceMethod(CallingConventions.addAnnotation)
|
||||
serialDescImplClass.referenceFunctionSymbol(CallingConventions.addAnnotation)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -32,7 +32,7 @@ class SerializerForInlineClassGenerator(
|
||||
|
||||
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS)
|
||||
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 inlineEncoder = encoder.encodeInline()
|
||||
@@ -45,14 +45,14 @@ class SerializerForInlineClassGenerator(
|
||||
// inlineEncoder.encodeInt/String/SerializableValue
|
||||
val elementCall = formEncodeDecodePropertyCall(irGet(inlineEncoder), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
|
||||
val f =
|
||||
encoderClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}SerializableValue")
|
||||
encoderClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}SerializableValue")
|
||||
f to listOf(
|
||||
innerSerial,
|
||||
value
|
||||
)
|
||||
}, {
|
||||
val f =
|
||||
encoderClass.referenceMethod("${CallingConventions.encode}${it.elementMethodPrefix}")
|
||||
encoderClass.referenceFunctionSymbol("${CallingConventions.encode}${it.elementMethodPrefix}")
|
||||
val args = if (it.elementMethodPrefix != "Unit") listOf(value) else emptyList()
|
||||
f to args
|
||||
})
|
||||
@@ -67,7 +67,7 @@ class SerializerForInlineClassGenerator(
|
||||
|
||||
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS)
|
||||
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 inlineDecoder = decoder.decodeInline()
|
||||
@@ -76,9 +76,9 @@ class SerializerForInlineClassGenerator(
|
||||
val property = serializableProperties.first()
|
||||
val inlinedType = property.type.toIrType()
|
||||
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)
|
||||
val value = coerceToBox(actualCall, loadFunc.returnType)
|
||||
+irReturn(value)
|
||||
@@ -111,4 +111,4 @@ class SerializerForInlineClassGenerator(
|
||||
|
||||
private fun IrBlockBodyBuilder.getFromBox(expression: IrExpression, serializableProperty: SerializableProperty): IrExpression =
|
||||
getProperty(expression, serializableProperty.getIrPropertyFrom(serializableIrClass))
|
||||
}
|
||||
}
|
||||
|
||||
+14
-20
@@ -58,7 +58,7 @@ open class SerializerIrGenerator(
|
||||
|
||||
override fun generateSerialDesc() {
|
||||
val desc: PropertyDescriptor = generatedSerialDescPropertyDescriptor ?: return
|
||||
val addFuncS = serialDescImplClass.referenceMethod(CallingConventions.addElement)
|
||||
val addFuncS = serialDescImplClass.referenceFunctionSymbol(CallingConventions.addElement)
|
||||
|
||||
val thisAsReceiverParameter = irClass.thisReceiver!!
|
||||
lateinit var prop: IrProperty
|
||||
@@ -95,7 +95,7 @@ open class SerializerIrGenerator(
|
||||
copySerialInfoAnnotationsToDescriptor(
|
||||
serializableIrClass.annotations,
|
||||
localDesc,
|
||||
serialDescImplClass.referenceMethod(CallingConventions.addClassAnnotation)
|
||||
serialDescImplClass.referenceFunctionSymbol(CallingConventions.addClassAnnotation)
|
||||
)
|
||||
|
||||
// save local descriptor to field
|
||||
@@ -145,7 +145,7 @@ open class SerializerIrGenerator(
|
||||
copySerialInfoAnnotationsToDescriptor(
|
||||
property.annotations,
|
||||
localDescriptor,
|
||||
serialDescImplClass.referenceMethod(CallingConventions.addAnnotation)
|
||||
serialDescImplClass.referenceFunctionSymbol(CallingConventions.addAnnotation)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -233,12 +233,6 @@ open class SerializerIrGenerator(
|
||||
/* 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 ->
|
||||
|
||||
fun irThis(): IrExpression =
|
||||
@@ -252,7 +246,7 @@ open class SerializerIrGenerator(
|
||||
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
|
||||
|
||||
// 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 { _, _ ->
|
||||
irGet(localSerialDesc)
|
||||
@@ -294,7 +288,7 @@ open class SerializerIrGenerator(
|
||||
// output.writeXxxElementValue(classDesc, index, value)
|
||||
val elementCall = formEncodeDecodePropertyCall(irGet(localOutput), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
|
||||
val f =
|
||||
kOutputClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
|
||||
kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
|
||||
f to listOf(
|
||||
irGet(localSerialDesc),
|
||||
irInt(index),
|
||||
@@ -303,7 +297,7 @@ open class SerializerIrGenerator(
|
||||
)
|
||||
}, {
|
||||
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))
|
||||
if (it.elementMethodPrefix != "Unit") args.add(property.irGet())
|
||||
f to args
|
||||
@@ -318,7 +312,7 @@ open class SerializerIrGenerator(
|
||||
// if ( if (output.shouldEncodeElementDefault(this.descriptor, i)) true else {obj.prop != DEFAULT_VALUE} ) {
|
||||
// output.encodeIntElement(this.descriptor, i, obj.prop)
|
||||
// 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 partB = irNotEquals(property.irGet(), initializerAdapter(property.irField.initializer!!))
|
||||
// Ir infrastructure does not have dedicated symbol for ||, so
|
||||
@@ -329,7 +323,7 @@ open class SerializerIrGenerator(
|
||||
}
|
||||
|
||||
// output.writeEnd(serialClassDesc)
|
||||
val wEndFunc = kOutputClass.referenceMethod(CallingConventions.end)
|
||||
val wEndFunc = kOutputClass.referenceFunctionSymbol(CallingConventions.end)
|
||||
+irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc))
|
||||
}
|
||||
|
||||
@@ -424,7 +418,7 @@ open class SerializerIrGenerator(
|
||||
}
|
||||
|
||||
//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(
|
||||
irGet(loadFunc.valueParameters[0]),
|
||||
beginFunc,
|
||||
@@ -438,13 +432,13 @@ open class SerializerIrGenerator(
|
||||
serializableProperties.mapIndexed { index, property ->
|
||||
val body = irBlock {
|
||||
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}
|
||||
) to listOf(
|
||||
localSerialDesc.get(), irInt(index), innerSerial, serialPropertiesMap.getValue(property.descriptor).get()
|
||||
)
|
||||
}, {
|
||||
inputClass.referenceMethod(
|
||||
inputClass.referenceFunctionSymbol(
|
||||
"${CallingConventions.decode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}", {it.valueParameters.size == 2}
|
||||
) to listOf(
|
||||
localSerialDesc.get(), irInt(index)
|
||||
@@ -464,7 +458,7 @@ open class SerializerIrGenerator(
|
||||
}
|
||||
|
||||
// if (decoder.decodeSequentially())
|
||||
val decodeSequentiallyCall = irInvoke(localInput.get(), inputClass.referenceMethod(CallingConventions.decodeSequentially))
|
||||
val decodeSequentiallyCall = irInvoke(localInput.get(), inputClass.referenceFunctionSymbol(CallingConventions.decodeSequentially))
|
||||
|
||||
val sequentialPart = irBlock {
|
||||
decoderCalls.forEach { (_, expr) -> +expr.deepCopyWithVariables() }
|
||||
@@ -473,7 +467,7 @@ open class SerializerIrGenerator(
|
||||
val byIndexPart: IrExpression = irWhile().also { loop ->
|
||||
loop.condition = flagVar.get()
|
||||
loop.body = irBlock {
|
||||
val readElementF = inputClass.referenceMethod(CallingConventions.decodeElementIndex)
|
||||
val readElementF = inputClass.referenceFunctionSymbol(CallingConventions.decodeElementIndex)
|
||||
+irSet(indexVar.symbol, irInvoke(localInput.get(), readElementF, localSerialDesc.get()))
|
||||
+irWhen {
|
||||
// if index == -1 (READ_DONE) break loop
|
||||
@@ -502,7 +496,7 @@ open class SerializerIrGenerator(
|
||||
+irIfThenElse(compilerContext.irBuiltIns.unitType, decodeSequentiallyCall, sequentialPart, byIndexPart)
|
||||
|
||||
//input.endStructure(...)
|
||||
val endFunc = inputClass.referenceMethod(CallingConventions.end)
|
||||
val endFunc = inputClass.referenceFunctionSymbol(CallingConventions.end)
|
||||
+irInvoke(
|
||||
localInput.get(),
|
||||
endFunc,
|
||||
|
||||
+1
-1
@@ -67,4 +67,4 @@ class SerializableCompanionJsTranslator(
|
||||
SerializableCompanionJsTranslator(descriptor, translator, context).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+179
-1
@@ -7,17 +7,31 @@ 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.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.load.java.JvmAbi
|
||||
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.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.module
|
||||
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.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.SimpleType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
|
||||
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.SerializationPackages.internalPackageFqName
|
||||
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.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 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 kSerialLoaderType = Type.getObjectType("kotlinx/serialization/$SERIAL_LOADER_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 descriptorGetterName = JvmAbi.getterName(SERIAL_DESC_FIELD)
|
||||
|
||||
internal val getLazyValueName = JvmAbi.getterName("value")
|
||||
|
||||
val OPT_MASK_TYPE: Type = Type.INT_TYPE
|
||||
val OPT_MASK_BITS = 32
|
||||
@@ -485,3 +505,161 @@ fun InstructionAdapter.stackValueDefault(type: Type) {
|
||||
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
|
||||
}
|
||||
|
||||
+5
-5
@@ -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.resolve.*
|
||||
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.initializedDescriptorFieldName
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -347,14 +347,14 @@ class SerializableCodegenImpl(
|
||||
}
|
||||
|
||||
private fun InstructionAdapter.stackSerialDescriptor() {
|
||||
if (serializableDescriptor.shouldHaveGeneratedSerializer && staticDescriptor) {
|
||||
if (serializableDescriptor.isStaticSerializable) {
|
||||
val serializer = serializableDescriptor.classSerializer!!
|
||||
StackValue.singleton(serializer, classCodegen.typeMapper).put(kSerializerType, this)
|
||||
invokeinterface(kSerializerType.internalName, descriptorGetterName, "()${descType.descriptor}")
|
||||
} else {
|
||||
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
|
||||
classCodegen.v.newField(
|
||||
OtherOrigin(classCodegen.myClass.psiOrParent), flags,
|
||||
initializedDescriptorFieldName, descType.descriptor, null, null
|
||||
INITIALIZED_DESCRIPTOR_FIELD_NAME, descType.descriptor, null, null
|
||||
)
|
||||
|
||||
val clInit = classCodegen.createOrGetClInitCodegen()
|
||||
@@ -380,7 +380,7 @@ class SerializableCodegenImpl(
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+61
-1
@@ -18,12 +18,17 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
||||
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.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
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.shouldHaveGeneratedMethodsInCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.toSimpleType
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
|
||||
class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationBodyCodegen) :
|
||||
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) {
|
||||
val serial = requireNotNull(
|
||||
findTypeSerializer(
|
||||
@@ -57,4 +117,4 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
|
||||
areturn(kSerializerType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -44,7 +44,8 @@ object SerialEntityNames {
|
||||
const val LOAD = "deserialize"
|
||||
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
|
||||
val KSERIALIZER_NAME = Name.identifier(KSERIALIZER_CLASS)
|
||||
|
||||
+8
@@ -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 =
|
||||
SerializationPackages.internalPackageFqName.child(Name.identifier(classSimpleName))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user