Supported synthetic fields in serialization

This commit is contained in:
Igor Chevdar
2018-08-01 17:13:53 +03:00
parent bde9b3e5ed
commit b8428903ed
6 changed files with 40 additions and 18 deletions
@@ -58,6 +58,7 @@ import kotlin.properties.Delegates
internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir<Context>(context, irModule) { internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir<Context>(context, irModule) {
val propertiesWithBackingFields = mutableSetOf<PropertyDescriptor>() val propertiesWithBackingFields = mutableSetOf<PropertyDescriptor>()
val classesDelegatedBackingFields = mutableMapOf<ClassDescriptor, MutableList<PropertyDescriptor>>()
val originalModuleIndex = ModuleIndex(irModule) val originalModuleIndex = ModuleIndex(irModule)
@@ -102,7 +102,7 @@ val IrProperty.konanBackingField: IrField?
this.endOffset, this.endOffset,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD, IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
backingFieldDescriptor, backingFieldDescriptor,
this.getter!!.returnType // TODO: this copies the behaviour found in backing field descriptor creation, but both are incorrect for property delegation. this.getter!!.returnType
).also { ).also {
it.parent = this.parent it.parent = this.parent
} }
@@ -139,10 +139,7 @@ private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<Ir
} }
private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>): LLVMTypeRef { private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>): LLVMTypeRef {
val fieldTypes = fields.map { val fieldTypes = fields.map { getLLVMType(it.type) }
@Suppress("DEPRECATION")
getLLVMType(if (it.isDelegate) context.irBuiltIns.anyNType else it.type)
}
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!! val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
@@ -17,8 +17,13 @@
package org.jetbrains.kotlin.backend.konan.serialization package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -29,12 +34,24 @@ internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid
} }
override fun visitProperty(declaration: IrProperty) { override fun visitProperty(declaration: IrProperty) {
if (declaration.backingField == null) return if (declaration.isDelegated) {
assert(declaration.backingField!!.descriptor val irClass = declaration.parent as? IrClass
== declaration.descriptor || declaration.isDelegated) val list = irClass?.let { context.ir.classesDelegatedBackingFields.getOrPut(irClass.descriptor) { mutableListOf() } }
list?.add(declaration.backingField!!.descriptor)
}
if (declaration.backingField == null || declaration.isDelegated) return
assert(declaration.backingField!!.descriptor == declaration.descriptor)
context.ir.propertiesWithBackingFields.add(declaration.descriptor) context.ir.propertiesWithBackingFields.add(declaration.descriptor)
} }
override fun visitClass(declaration: IrClass) {
declaration.declarations.filterIsInstance<IrField>().forEach {
val list = context.ir.classesDelegatedBackingFields.getOrPut(declaration.descriptor) { mutableListOf() }
list.add(it.descriptor)
}
super.visitClass(declaration)
}
} }
internal fun markBackingFields(context: Context) { internal fun markBackingFields(context: Context) {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.serialization package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.backend.common.onlyIf import org.jetbrains.kotlin.backend.common.onlyIf
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.needsSerializedIr import org.jetbrains.kotlin.backend.konan.descriptors.needsSerializedIr
import org.jetbrains.kotlin.backend.konan.serialization.IrAwareExtension import org.jetbrains.kotlin.backend.konan.serialization.IrAwareExtension
import org.jetbrains.kotlin.backend.konan.serialization.KonanStringTable import org.jetbrains.kotlin.backend.konan.serialization.KonanStringTable
@@ -54,6 +55,7 @@ import java.io.ByteArrayOutputStream
import java.util.* import java.util.*
class KonanDescriptorSerializer private constructor( class KonanDescriptorSerializer private constructor(
private val context: Context,
private val containingDeclaration: DeclarationDescriptor?, private val containingDeclaration: DeclarationDescriptor?,
private val typeParameters: Interner<TypeParameterDescriptor>, private val typeParameters: Interner<TypeParameterDescriptor>,
private val extension: SerializerExtension, private val extension: SerializerExtension,
@@ -64,7 +66,7 @@ class KonanDescriptorSerializer private constructor(
private val contractSerializer = ContractSerializer() private val contractSerializer = ContractSerializer()
fun createChildSerializer(descriptor: DeclarationDescriptor): KonanDescriptorSerializer = fun createChildSerializer(descriptor: DeclarationDescriptor): KonanDescriptorSerializer =
KonanDescriptorSerializer(descriptor, Interner(typeParameters), extension, typeTable, versionRequirementTable, KonanDescriptorSerializer(context, descriptor, Interner(typeParameters), extension, typeTable, versionRequirementTable,
serializeTypeTableToFunction = false) serializeTypeTableToFunction = false)
val stringTable: DescriptorAwareStringTable val stringTable: DescriptorAwareStringTable
@@ -124,6 +126,10 @@ class KonanDescriptorSerializer private constructor(
} }
} }
context.ir.classesDelegatedBackingFields[classDescriptor]?.forEach {
builder.addProperty(propertyProto(it))
}
val nestedClassifiers = sort(DescriptorUtils.getAllDescriptors(classDescriptor.unsubstitutedInnerClassesScope)) val nestedClassifiers = sort(DescriptorUtils.getAllDescriptors(classDescriptor.unsubstitutedInnerClassesScope))
for (descriptor in nestedClassifiers) { for (descriptor in nestedClassifiers) {
if (descriptor is TypeAliasDescriptor) { if (descriptor is TypeAliasDescriptor) {
@@ -735,29 +741,30 @@ class KonanDescriptorSerializer private constructor(
companion object { companion object {
@JvmStatic @JvmStatic
fun createTopLevel(extension: SerializerExtension): KonanDescriptorSerializer { internal fun createTopLevel(context: Context, extension: SerializerExtension): KonanDescriptorSerializer {
return KonanDescriptorSerializer(null, Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(), return KonanDescriptorSerializer(context, null, Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(),
serializeTypeTableToFunction = false) serializeTypeTableToFunction = false)
} }
@JvmStatic @JvmStatic
fun createForLambda(extension: SerializerExtension): KonanDescriptorSerializer { internal fun createForLambda(context: Context, extension: SerializerExtension): KonanDescriptorSerializer {
return KonanDescriptorSerializer(null, Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(), return KonanDescriptorSerializer(context, null, Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(),
serializeTypeTableToFunction = true) serializeTypeTableToFunction = true)
} }
@JvmStatic @JvmStatic
fun create(descriptor: ClassDescriptor, extension: SerializerExtension): KonanDescriptorSerializer { internal fun create(context: Context, descriptor: ClassDescriptor, extension: SerializerExtension): KonanDescriptorSerializer {
val container = descriptor.containingDeclaration val container = descriptor.containingDeclaration
val parentSerializer = if (container is ClassDescriptor) val parentSerializer = if (container is ClassDescriptor)
create(container, extension) create(context, container, extension)
else else
createTopLevel(extension) createTopLevel(context, extension)
// Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always // Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
// serializing outer classes before nested classes. // serializing outer classes before nested classes.
// Otherwise our interner can get wrong ids because we may serialize classes in any order. // Otherwise our interner can get wrong ids because we may serialize classes in any order.
val serializer = KonanDescriptorSerializer( val serializer = KonanDescriptorSerializer(
context,
descriptor, descriptor,
Interner(parentSerializer.typeParameters), Interner(parentSerializer.typeParameters),
parentSerializer.extension, parentSerializer.extension,
@@ -144,7 +144,7 @@ internal fun deserializeModule(languageVersionSettings: LanguageVersionSettings,
internal class KonanSerializationUtil(val context: Context, metadataVersion: BinaryVersion) { internal class KonanSerializationUtil(val context: Context, metadataVersion: BinaryVersion) {
val serializerExtension = KonanSerializerExtension(context, metadataVersion) val serializerExtension = KonanSerializerExtension(context, metadataVersion)
val topSerializer = KonanDescriptorSerializer.createTopLevel(serializerExtension) val topSerializer = KonanDescriptorSerializer.createTopLevel(context, serializerExtension)
var classSerializer: KonanDescriptorSerializer = topSerializer var classSerializer: KonanDescriptorSerializer = topSerializer
fun serializeClass(packageName: FqName, fun serializeClass(packageName: FqName,
@@ -155,7 +155,7 @@ internal class KonanSerializationUtil(val context: Context, metadataVersion: Bin
// TODO: this is to filter out object{}. Change me. // TODO: this is to filter out object{}. Change me.
if (classDescriptor.isExported()) if (classDescriptor.isExported())
classSerializer = KonanDescriptorSerializer.create(classDescriptor, serializerExtension) classSerializer = KonanDescriptorSerializer.create(context, classDescriptor, serializerExtension)
val classProto = classSerializer.classProto(classDescriptor).build() val classProto = classSerializer.classProto(classDescriptor).build()
?: error("Class not serialized: $classDescriptor") ?: error("Class not serialized: $classDescriptor")