Fix IR compilation of kotlix.serialization runtime in native

This commit is contained in:
Sergey Shanshin
2021-04-12 17:08:08 +03:00
committed by GitHub
parent 39731fd493
commit 5f9fe8e5de
7 changed files with 216 additions and 157 deletions
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
@@ -28,10 +29,7 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
@@ -42,6 +40,12 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.FUNCTION0_FQ
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.KPROPERTY1_FQ
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_FQ
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_FUNC_FQ
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_MODE_FQ
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_PUBLICATION_MODE_NAME
interface IrBuilderExtension {
val compilerContext: SerializationPluginContext
@@ -82,48 +86,125 @@ interface IrBuilderExtension {
) { bodyGen(c) }
}
// function will not be created in the real class
fun IrClass.createInlinedFunction(
name: Name,
visibility: DescriptorVisibility,
origin: IrDeclarationOrigin,
returnType: IrType,
bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit
): IrSimpleFunction {
val function = factory.buildFun {
this.name = name
this.visibility = visibility
this.origin = origin
this.isInline = true
this.returnType = returnType
}
val functionSymbol = function.symbol
function.parent = this
function.body = DeclarationIrBuilder(compilerContext, functionSymbol, startOffset, endOffset).irBlockBody(
startOffset,
endOffset
) { bodyGen(function) }
return function
}
fun IrClass.createSingletonLambda(
returnType: IrType,
startOffset: Int,
endOffset: Int,
fun IrClass.createLambdaExpression(
type: IrType,
bodyGen: IrBlockBodyBuilder.() -> Unit
): IrSimpleFunction {
): IrFunctionExpression {
val function = compilerContext.irFactory.buildFun {
this.startOffset = startOffset
this.endOffset = endOffset
this.returnType = returnType
this.startOffset = this@createLambdaExpression.startOffset
this.endOffset = this@createLambdaExpression.endOffset
this.returnType = type
name = Name.identifier("<anonymous>")
visibility = DescriptorVisibilities.LOCAL
origin = SERIALIZABLE_PLUGIN_ORIGIN
}
function.body =
DeclarationIrBuilder(compilerContext, function.symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset, bodyGen)
function.parent = this
return function
val f0Type = module.findClassAcrossModuleDependencies(ClassId.topLevel(FUNCTION0_FQ))!!.defaultType
val f0ParamSymbol = compilerContext.symbolTable.referenceTypeParameter(f0Type.constructor.parameters[0])
val f0IrType = f0Type.toIrType().substitute(mapOf(f0ParamSymbol to type))
return IrFunctionExpressionImpl(
startOffset,
endOffset,
f0IrType,
function,
IrStatementOrigin.LAMBDA
)
}
fun createLazyProperty(
containingClass: IrClass,
targetIrType: IrType,
name: Name,
initializerBuilder: IrBlockBodyBuilder.() -> Unit
): IrProperty {
val lazySafeModeClassDescriptor = compilerContext.referenceClass(LAZY_MODE_FQ)!!.descriptor
val lazyFunctionSymbol = compilerContext.referenceFunctions(LAZY_FUNC_FQ).single {
it.descriptor.valueParameters.size == 2 && it.descriptor.valueParameters[0].type == lazySafeModeClassDescriptor.defaultType
}
val publicationEntryDescriptor = lazySafeModeClassDescriptor.enumEntries().single { it.name == LAZY_PUBLICATION_MODE_NAME }
val lazyIrClass = compilerContext.referenceClass(LAZY_FQ)!!.owner
val lazyKotlinType = lazyIrClass.defaultType.substitute(mapOf(lazyIrClass.typeParameters[0].symbol to targetIrType)).toKotlinType()
val kPropertyIrClass = compilerContext.referenceClass(KPROPERTY1_FQ)!!.owner
val kPropertyKotlinType = kPropertyIrClass.defaultType.substitute(
mapOf(
kPropertyIrClass.typeParameters[0].symbol to targetIrType,
kPropertyIrClass.typeParameters[1].symbol to containingClass.defaultType,
)
).toKotlinType()
val targetKotlinType = targetIrType.toKotlinType()
val propertyDescriptor =
KSerializerDescriptorResolver.createValPropertyDescriptor(name, containingClass.descriptor, targetKotlinType)
val delegate = IrPropertyDelegateDescriptorImpl(propertyDescriptor, lazyKotlinType, kPropertyKotlinType)
return generateSimplePropertyWithBackingField(delegate, containingClass, delegate.name).apply {
val builder = DeclarationIrBuilder(compilerContext, containingClass.symbol, startOffset, endOffset)
val initializerBody = builder.run {
val enumElement = IrGetEnumValueImpl(
startOffset,
endOffset,
publicationEntryDescriptor.classValueType!!.toIrType(),
compilerContext.symbolTable.referenceEnumEntry(publicationEntryDescriptor)
)
val lambdaExpression = containingClass.createLambdaExpression(targetIrType, initializerBuilder)
irExprBody(
irInvoke(null, lazyFunctionSymbol, listOf(targetIrType), listOf(enumElement, lambdaExpression), targetIrType)
)
}
backingField!!.initializer = initializerBody
}
}
fun createCompanionValProperty(
companionClass: IrClass,
type: IrType,
name: Name,
initializerBuilder: IrBlockBodyBuilder.() -> Unit
): IrProperty {
val targetKotlinType = type.toKotlinType()
val propertyDescriptor =
KSerializerDescriptorResolver.createValPropertyDescriptor(name, companionClass.descriptor, targetKotlinType)
return generateSimplePropertyWithBackingField(propertyDescriptor, companionClass, name).apply {
companionClass.contributeAnonymousInitializer {
val irBlockBody = irBlockBody(startOffset, endOffset, initializerBuilder)
irBlockBody.statements.dropLast(1).forEach { +it }
val expression = irBlockBody.statements.last() as? IrExpression
?: throw AssertionError("Last statement in property initializer builder is not an a expression")
+irSetField(irGetObject(companionClass), backingField!!, expression)
}
}
}
fun IrClass.contributeAnonymousInitializer(bodyGen: IrBlockBodyBuilder.() -> Unit) {
val symbol = IrAnonymousInitializerSymbolImpl(descriptor)
factory.createAnonymousInitializer(startOffset, endOffset, SERIALIZABLE_PLUGIN_ORIGIN, symbol).also {
it.parent = this
declarations.add(it)
it.body = DeclarationIrBuilder(compilerContext, symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset, bodyGen)
}
}
fun IrBlockBodyBuilder.getLazyValueExpression(companionClass: IrClass, property: IrProperty): IrExpression {
val lazyIrClass = compilerContext.referenceClass(LAZY_FQ)!!.owner
val valueGetter = lazyIrClass.getPropertyGetter("value")!!
val backingField = property.backingField!!
return irGet(
backingField.type,
irGetField(irGetObject(companionClass), backingField),
valueGetter
)
}
fun IrBuilderWithScope.irInvoke(
@@ -12,17 +12,12 @@ 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.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.ir.util.*
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
@@ -36,25 +31,6 @@ 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,
@@ -113,58 +89,22 @@ class SerializableCompanionIrGenerator(
)
)
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 kSerializerIrClass = compilerContext.referenceClass(SerialEntityNames.KSERIALIZER_NAME_FQ)!!.owner
val targetIrType =
kSerializerIrClass.defaultType.substitute(mapOf(kSerializerIrClass.typeParameters[0].symbol to compilerContext.builtIns.anyType.toIrType()))
val call = IrCallImpl(startOffset, endOffset, type, lazyFunctionSymbol, 0, 2)
call.putValueArgument(
0,
IrGetEnumValueImpl(
startOffset,
endOffset,
publicationEntryDescriptor.classValueType!!.toIrType(),
compilerContext.symbolTable.referenceEnumEntry(publicationEntryDescriptor)
),
val property = createLazyProperty(irClass, targetIrType, SerialEntityNames.CACHED_SERIALIZER_PROPERTY_NAME) {
val expr = serializerInstance(
this@SerializableCompanionIrGenerator,
serializerDescriptor, serializableDescriptor.module,
serializableDescriptor.defaultType
)
call.putValueArgument(
1,
IrFunctionExpressionImpl(
startOffset,
endOffset,
function0Descriptor.defaultType.toIrType(),
lambda,
IrStatementOrigin.LAMBDA
),
)
initializer = irClass.factory.createExpressionBody(startOffset, endOffset, call)
patchSerializableClassWithMarkerAnnotation(serializerDescriptor)
+irReturn(requireNotNull(expr))
}
val valueGetter = compilerContext.referenceClass(lazyDescriptor.fqNameSafe)!!.getPropertyGetter("value")!!
irClass.contributeFunction(methodDescriptor) {
+irReturn(
irGet(
serializerDescriptor.defaultType.toIrType(),
irGetField(null, field), valueGetter
)
)
+irReturn(getLazyValueExpression(irClass, property))
}
generateSerializerFactoryIfNeeded(methodDescriptor)
}
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.codegen.CompilationException
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addField
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
@@ -19,7 +18,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
@@ -29,7 +27,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
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.CACHED_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
@@ -39,8 +37,6 @@ class SerializableIrGenerator(
bindingContext: BindingContext
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
private val descriptorGenerationFunctionName = Name.identifier("createInitializedDescriptor")
private val serialDescClass: ClassDescriptor = serializableDescriptor.module
.getClassFromSerializationDescriptorsPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS)
@@ -116,7 +112,14 @@ class SerializableIrGenerator(
// for abstract classes fields MUST BE checked in child classes
!serializableDescriptor.isAbstractSerializableClass() && !serializableDescriptor.isSealedSerializableClass()
) {
generateGoldenMaskCheck(seenVars, properties, getSerialDescriptorExpr())
val getDescriptorExpr = if (serializableDescriptor.isStaticSerializable) {
getStaticSerialDescriptorExpr()
} else {
// synthetic constructor is created only for internally serializable classes - so companion definitely exists
val companionObject = irClass.companionObject()!!
getParametrizedSerialDescriptorExpr(companionObject, createCachedDescriptorProperty(companionObject))
}
generateGoldenMaskCheck(seenVars, properties, getDescriptorExpr)
}
when {
superClass.symbol == compilerContext.irBuiltIns.anyClass -> generateAnySuperConstructorCall(toBuilder = this@contributeConstructor)
@@ -167,29 +170,25 @@ class SerializableIrGenerator(
}
}
private fun IrBlockBodyBuilder.getSerialDescriptorExpr(): IrExpression {
return if (serializableDescriptor.isStaticSerializable) {
val serializer = serializableDescriptor.classSerializer!!
val serialDescriptorGetter = compilerContext.referenceClass(serializer.fqNameSafe)!!.getPropertyGetter(SERIAL_DESC_FIELD)!!
irGet(
serialDescriptorGetter.owner.returnType,
irGetObject(serializer),
serialDescriptorGetter.owner.symbol
)
} else {
irGetField(null, generateStaticDescriptorField())
}
private fun IrBlockBodyBuilder.getStaticSerialDescriptorExpr(): IrExpression {
val serializer = serializableDescriptor.classSerializer!!
val serialDescriptorGetter = compilerContext.referenceClass(serializer.fqNameSafe)?.getPropertyGetter(SERIAL_DESC_FIELD)
?: throw Exception("No class with name ${serializer.fqNameSafe}")
return irGet(
serialDescriptorGetter.owner.returnType,
irGetObject(serializer),
serialDescriptorGetter.owner.symbol
)
}
private fun IrBlockBodyBuilder.generateStaticDescriptorField(): IrField {
val serialDescItType = serialDescClass.defaultType.toIrType()
private fun IrBlockBodyBuilder.getParametrizedSerialDescriptorExpr(companionObject: IrClass, property: IrProperty): IrExpression {
return irGetField(irGetObject(companionObject), property.backingField!!)
}
val function = irClass.createInlinedFunction(
descriptorGenerationFunctionName,
DescriptorVisibilities.PRIVATE,
SERIALIZABLE_PLUGIN_ORIGIN,
serialDescItType
) {
private fun IrBlockBodyBuilder.createCachedDescriptorProperty(companionObject: IrClass): IrProperty {
val serialDescIrType = serialDescClass.defaultType.toIrType()
return createCompanionValProperty(companionObject, serialDescIrType, CACHED_DESCRIPTOR_FIELD_NAME) {
val serialDescVar = irTemporary(
getInstantiateDescriptorExpr(),
nameHint = "serialDesc"
@@ -197,17 +196,8 @@ class SerializableIrGenerator(
for (property in properties.serializableProperties) {
+getAddElementToDescriptorExpr(property, serialDescVar)
}
+irReturn(irGet(serialDescVar))
+irGet(serialDescVar)
}
return irClass.addField {
name = Name.identifier(INITIALIZED_DESCRIPTOR_FIELD_NAME)
visibility = DescriptorVisibilities.PRIVATE
origin = SERIALIZABLE_PLUGIN_ORIGIN
isFinal = true
isStatic = true
type = serialDescItType
}.apply { initializer = irClass.factory.createExpressionBody(irCall(function)) }
}
private fun IrBlockBodyBuilder.getInstantiateDescriptorExpr(): IrExpression {
@@ -35,7 +35,7 @@ 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.CACHED_DESCRIPTOR_FIELD
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SINGLE_MASK_FIELD_MISSING_FUNC_NAME
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -354,7 +354,7 @@ class SerializableCodegenImpl(
} else {
generateStaticDescriptorField()
getstatic(thisAsmType.internalName, INITIALIZED_DESCRIPTOR_FIELD_NAME, descType.descriptor)
getstatic(thisAsmType.internalName, CACHED_DESCRIPTOR_FIELD, 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,
INITIALIZED_DESCRIPTOR_FIELD_NAME, descType.descriptor, null, null
CACHED_DESCRIPTOR_FIELD, 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, INITIALIZED_DESCRIPTOR_FIELD_NAME, descType.descriptor)
putstatic(thisAsmType.internalName, CACHED_DESCRIPTOR_FIELD, descType.descriptor)
}
}
@@ -23,11 +23,12 @@ 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.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.CACHED_SERIALIZER_PROPERTY
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_PUBLICATION_MODE_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) :
@@ -42,11 +43,13 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
}
override fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
val fieldName = "$CACHED_SERIALIZER_PROPERTY\$delegate"
// 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,
fieldName,
kotlinLazyType.descriptor,
"L${kotlinLazyType.internalName}<L${kSerializerType.internalName}<*>;>;",
null
@@ -75,7 +78,7 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
// initialize lazy delegate
val clInit = classCodegen.createOrGetClInitCodegen()
with(clInit.v) {
getstatic(threadSafeModeType.internalName, "PUBLICATION", threadSafeModeType.descriptor)
getstatic(threadSafeModeType.internalName, LAZY_PUBLICATION_MODE_NAME.identifier, threadSafeModeType.descriptor)
getstatic(lambdaType.internalName, JvmAbi.INSTANCE_FIELD, lambdaType.descriptor)
checkcast(function0Type)
invokestatic(
@@ -84,12 +87,12 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
"(${threadSafeModeType.descriptor}${function0Type.descriptor})${kotlinLazyType.descriptor}",
false
)
putstatic(classCodegen.className, SERIALIZER_LAZY_DELEGATE_FIELD_NAME, kotlinLazyType.descriptor)
putstatic(classCodegen.className, fieldName, kotlinLazyType.descriptor)
}
// create serializer getter
classCodegen.generateMethod(methodDescriptor) { _, _ ->
getstatic(classCodegen.className, SERIALIZER_LAZY_DELEGATE_FIELD_NAME, kotlinLazyType.descriptor)
getstatic(classCodegen.className, fieldName, kotlinLazyType.descriptor)
invokeinterface(kotlinLazyType.internalName, getLazyValueName, "()Ljava/lang/Object;")
checkcast(kSerializerType)
areturn(kSerializerType)
@@ -290,6 +290,40 @@ object KSerializerDescriptorResolver {
return functionDescriptor
}
fun createValPropertyDescriptor(
name: Name,
containingClassDescriptor: ClassDescriptor,
type: KotlinType,
visibility: DescriptorVisibility = DescriptorVisibilities.PRIVATE,
createGetter: Boolean = false
): PropertyDescriptor {
val propertyDescriptor = PropertyDescriptorImpl.create(
containingClassDescriptor,
Annotations.EMPTY, Modality.FINAL, visibility, false, name,
CallableMemberDescriptor.Kind.SYNTHESIZED, containingClassDescriptor.source, false, false, false, false, false, false
)
val extensionReceiverParameter: ReceiverParameterDescriptor? = null // kludge to disambiguate call
propertyDescriptor.setType(
type,
emptyList(), // no need type parameters?
containingClassDescriptor.thisAsReceiverParameter,
extensionReceiverParameter
)
val propertyGetter: PropertyGetterDescriptorImpl? = if (createGetter) {
PropertyGetterDescriptorImpl(
propertyDescriptor, Annotations.EMPTY, Modality.FINAL, visibility, false, false, false,
CallableMemberDescriptor.Kind.SYNTHESIZED, null, containingClassDescriptor.source
).apply { initialize(type) }
} else {
null
}
propertyDescriptor.initialize(propertyGetter, null)
return propertyDescriptor
}
fun createLoadConstructorDescriptor(
classDescriptor: ClassDescriptor,
bindingContext: BindingContext,
@@ -44,8 +44,8 @@ object SerialEntityNames {
const val LOAD = "deserialize"
const val SERIALIZER_CLASS = "\$serializer"
const val INITIALIZED_DESCRIPTOR_FIELD_NAME = "\$initializedDescriptor"
const val SERIALIZER_LAZY_DELEGATE_FIELD_NAME = "\$serializer\$delegate"
const val CACHED_DESCRIPTOR_FIELD = "\$cachedDescriptor"
const val CACHED_SERIALIZER_PROPERTY = "\$cachedSerializer"
// classes
val KSERIALIZER_NAME = Name.identifier(KSERIALIZER_CLASS)
@@ -91,6 +91,8 @@ object SerialEntityNames {
val ARRAY_MASK_FIELD_MISSING_FUNC_NAME = Name.identifier("throwArrayMissingFieldException")
val SINGLE_MASK_FIELD_MISSING_FUNC_FQ = SerializationPackages.internalPackageFqName.child(SINGLE_MASK_FIELD_MISSING_FUNC_NAME)
val ARRAY_MASK_FIELD_MISSING_FUNC_FQ = SerializationPackages.internalPackageFqName.child(ARRAY_MASK_FIELD_MISSING_FUNC_NAME)
val CACHED_SERIALIZER_PROPERTY_NAME = Name.identifier(CACHED_SERIALIZER_PROPERTY)
val CACHED_DESCRIPTOR_FIELD_NAME = Name.identifier(CACHED_DESCRIPTOR_FIELD)
// parameters
val dummyParamName = Name.identifier("serializationConstructorMarker")
@@ -129,3 +131,12 @@ object CallingConventions {
const val addAnnotation = "pushAnnotation"
const val addClassAnnotation = "pushClassAnnotation"
}
internal object SerializationDependencies {
val LAZY_FQ = FqName("kotlin.Lazy")
val LAZY_FUNC_FQ = FqName("kotlin.lazy")
val LAZY_MODE_FQ = FqName("kotlin.LazyThreadSafetyMode")
val KPROPERTY1_FQ = FqName("kotlin.reflect.KProperty1")
val FUNCTION0_FQ = FqName("kotlin.Function0")
val LAZY_PUBLICATION_MODE_NAME = Name.identifier("PUBLICATION")
}