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) {
val propertiesWithBackingFields = mutableSetOf<PropertyDescriptor>()
val classesDelegatedBackingFields = mutableMapOf<ClassDescriptor, MutableList<PropertyDescriptor>>()
val originalModuleIndex = ModuleIndex(irModule)
@@ -102,7 +102,7 @@ val IrProperty.konanBackingField: IrField?
this.endOffset,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
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 {
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 {
val fieldTypes = fields.map {
@Suppress("DEPRECATION")
getLLVMType(if (it.isDelegate) context.irBuiltIns.anyNType else it.type)
}
val fieldTypes = fields.map { getLLVMType(it.type) }
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
@@ -17,8 +17,13 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
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.util.parentAsClass
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -29,12 +34,24 @@ internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid
}
override fun visitProperty(declaration: IrProperty) {
if (declaration.backingField == null) return
assert(declaration.backingField!!.descriptor
== declaration.descriptor || declaration.isDelegated)
if (declaration.isDelegated) {
val irClass = declaration.parent as? IrClass
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)
}
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) {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.serialization
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.serialization.IrAwareExtension
import org.jetbrains.kotlin.backend.konan.serialization.KonanStringTable
@@ -54,6 +55,7 @@ import java.io.ByteArrayOutputStream
import java.util.*
class KonanDescriptorSerializer private constructor(
private val context: Context,
private val containingDeclaration: DeclarationDescriptor?,
private val typeParameters: Interner<TypeParameterDescriptor>,
private val extension: SerializerExtension,
@@ -64,7 +66,7 @@ class KonanDescriptorSerializer private constructor(
private val contractSerializer = ContractSerializer()
fun createChildSerializer(descriptor: DeclarationDescriptor): KonanDescriptorSerializer =
KonanDescriptorSerializer(descriptor, Interner(typeParameters), extension, typeTable, versionRequirementTable,
KonanDescriptorSerializer(context, descriptor, Interner(typeParameters), extension, typeTable, versionRequirementTable,
serializeTypeTableToFunction = false)
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))
for (descriptor in nestedClassifiers) {
if (descriptor is TypeAliasDescriptor) {
@@ -735,29 +741,30 @@ class KonanDescriptorSerializer private constructor(
companion object {
@JvmStatic
fun createTopLevel(extension: SerializerExtension): KonanDescriptorSerializer {
return KonanDescriptorSerializer(null, Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(),
internal fun createTopLevel(context: Context, extension: SerializerExtension): KonanDescriptorSerializer {
return KonanDescriptorSerializer(context, null, Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(),
serializeTypeTableToFunction = false)
}
@JvmStatic
fun createForLambda(extension: SerializerExtension): KonanDescriptorSerializer {
return KonanDescriptorSerializer(null, Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(),
internal fun createForLambda(context: Context, extension: SerializerExtension): KonanDescriptorSerializer {
return KonanDescriptorSerializer(context, null, Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(),
serializeTypeTableToFunction = true)
}
@JvmStatic
fun create(descriptor: ClassDescriptor, extension: SerializerExtension): KonanDescriptorSerializer {
internal fun create(context: Context, descriptor: ClassDescriptor, extension: SerializerExtension): KonanDescriptorSerializer {
val container = descriptor.containingDeclaration
val parentSerializer = if (container is ClassDescriptor)
create(container, extension)
create(context, container, extension)
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
// serializing outer classes before nested classes.
// Otherwise our interner can get wrong ids because we may serialize classes in any order.
val serializer = KonanDescriptorSerializer(
context,
descriptor,
Interner(parentSerializer.typeParameters),
parentSerializer.extension,
@@ -144,7 +144,7 @@ internal fun deserializeModule(languageVersionSettings: LanguageVersionSettings,
internal class KonanSerializationUtil(val context: Context, metadataVersion: BinaryVersion) {
val serializerExtension = KonanSerializerExtension(context, metadataVersion)
val topSerializer = KonanDescriptorSerializer.createTopLevel(serializerExtension)
val topSerializer = KonanDescriptorSerializer.createTopLevel(context, serializerExtension)
var classSerializer: KonanDescriptorSerializer = topSerializer
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.
if (classDescriptor.isExported())
classSerializer = KonanDescriptorSerializer.create(classDescriptor, serializerExtension)
classSerializer = KonanDescriptorSerializer.create(context, classDescriptor, serializerExtension)
val classProto = classSerializer.classProto(classDescriptor).build()
?: error("Class not serialized: $classDescriptor")