Descriptors for IR

This commit is contained in:
Leonid Startsev
2018-09-25 23:24:09 +03:00
committed by Leonid Startsev
parent 3010814327
commit 01d3c7bdc8
2 changed files with 112 additions and 54 deletions
@@ -6,6 +6,7 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -22,10 +23,24 @@ import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsNew
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperty
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractSerialGenerator
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializerJsTranslator
import org.jetbrains.kotlinx.serialization.compiler.backend.js.serializerInstance
import org.jetbrains.kotlinx.serialization.compiler.backend.js.translateQualifiedReference
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
val BackendContext.externalSymbols: ReferenceSymbolTable get() = ir.symbols.externalSymbolTable
@@ -83,6 +98,21 @@ interface IrBuilderExtension {
return call
}
fun IrBuilderWithScope.createArrayOfExpression(
resultingType: IrType,
arrayElementType: IrType,
arrayElements: List<IrExpression>
): IrExpression {
val arrayType = compilerContext.ir.symbols.array.typeWith(arrayElementType)
val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, arrayElementType, arrayElements)
val typeArguments = listOf(arrayElementType)
return irCall(compilerContext.ir.symbols.arrayOf, resultingType, typeArguments = typeArguments).apply {
putValueArgument(0, arg0)
}
}
fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression {
val symbol = compilerContext.ir.symbols.getBinaryOperator(
name,
@@ -327,4 +357,61 @@ interface IrBuilderExtension {
}
}
}
// Does not use sti and therefore does not perform encoder calls optimization
fun IrBuilderWithScope.serializerTower(generator: SerializerIrGenerator, property: SerializableProperty): IrExpression? {
val nullableSerClass =
compilerContext.externalSymbols.referenceClass(property.module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
val serializer =
property.serializableWith?.toClassDescriptor
?: if (!property.type.isTypeParameter()) generator.findTypeSerializerOrContext(
property.module,
property.type,
property.descriptor.annotations,
property.descriptor.findPsi()
) else null
return serializerInstance(generator, generator.serializableDescriptor, serializer, property.module, property.type, property.genericIndex)
?.let { expr -> if (property.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr }
}
fun IrBuilderWithScope.serializerInstance(
enclosingGenerator: AbstractSerialGenerator,
serializableDescriptor: ClassDescriptor,
serializerClass: ClassDescriptor?,
module: ModuleDescriptor,
kType: KotlinType,
genericIndex: Int? = null
): IrExpression? {
val nullableSerClass =
compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
if (serializerClass == null) {
if (genericIndex == null) return null
TODO("Saved serializer for generic argument")
}
if (serializerClass.kind == ClassKind.OBJECT) {
return irGetObject(serializerClass)
} else {
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
TODO("enum and context serializer")
else kType.arguments.map {
val argSer = enclosingGenerator.findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
val expr = serializerInstance(enclosingGenerator, serializableDescriptor, argSer, module, it.type, it.type.genericIndex) ?: return null
// todo: smth better than constructors[0] ??
if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr
}
if (serializerClass.classId == referenceArraySerializerId) TODO("reference array serializer")
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
.let { compilerContext.externalSymbols.referenceConstructor(it) }
} else {
compilerContext.externalSymbols.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!)
}
return irInvoke(
null,
ctor,
*args.toTypedArray()
)
}
}
}
@@ -8,7 +8,10 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
@@ -22,21 +25,16 @@ import org.jetbrains.kotlin.ir.expressions.mapValueParametersIndexed
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.KSERIALIZER_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_DECODER_CLASS
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_ENCODER_CLASS
@@ -81,11 +79,11 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
compilerContext.localSymbolTable.withScope(initIrBody.descriptor) {
initIrBody.body = compilerContext.createIrBuilder(initIrBody.symbol).irBlockBody {
val localDesc = irTemporary(
irCall(
serialClassDescImplCtor,
type = serialClassDescImplCtor.owner.returnType
).mapValueParameters { irString(serialName) },
nameHint = "serialDesc"
irInvoke(null, serialClassDescImplCtor,
irString(serialName), irGet(thisAsReceiverParameter),
typeHint = serialClassDescImplCtor.owner.returnType
),
nameHint = "serialDesc"
)
fun addFieldCall(fieldName: String) =
@@ -119,47 +117,20 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun generateSerializableClassProperty(property: PropertyDescriptor) {
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun ->
val allSerializers = orderedProperties.map { requireNotNull(
serializerTower(this@SerializerIrGenerator, it)) { "Property ${it.name} must have a serializer" }
}
val arrayOfKSerType = irFun.returnType
val kSer = serializableDescriptor.module.getClassFromSerializationPackage(KSERIALIZER_NAME.identifier)
val kSerType = compilerContext.externalSymbols.referenceClass(kSer).owner.defaultType
val array = createArrayOfExpression(arrayOfKSerType, kSerType, allSerializers)
+irReturn(array)
}
private fun IrBuilderWithScope.serializerInstance(
serializerClass: ClassDescriptor?,
module: ModuleDescriptor,
kType: KotlinType,
genericIndex: Int? = null
): IrExpression? {
val nullableSerClass =
compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
if (serializerClass == null) {
if (genericIndex == null) return null
TODO("Saved serializer for generic argument")
}
if (serializerClass.kind == ClassKind.OBJECT) {
return irGetObject(serializerClass)
} else {
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
TODO("enum and context serializer")
else kType.arguments.map {
val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
val expr = serializerInstance(argSer, module, it.type, it.type.genericIndex) ?: return null
// todo: smth better than constructors[0] ??
if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr
}
if (serializerClass.classId == referenceArraySerializerId) TODO("reference array serializer")
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
.let { compilerContext.externalSymbols.referenceConstructor(it) }
} else {
compilerContext.externalSymbols.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!)
}
return irInvoke(
null,
ctor,
*args.toTypedArray()
)
}
override fun generateSerializableClassProperty(property: PropertyDescriptor) {
/* Already implemented in .generateSerialClassDesc ? */
}
fun ClassDescriptor.referenceMethod(methodName: String) =
@@ -200,7 +171,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
if (property.transient) continue
// output.writeXxxElementValue(classDesc, index, value)
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
val innerSerial = serializerInstance(this@SerializerIrGenerator, serializableDescriptor, sti.serializer, property.module, property.type, property.genericIndex)
if (innerSerial == null) {
val writeFunc =
kOutputClass.referenceMethod("${CallingConventions.encode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
@@ -308,7 +279,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
val branchBodies: List<Pair<Int, IrExpression>> = orderedProperties.mapIndexed { index, property ->
val body = irBlock {
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
val innerSerial = serializerInstance(this@SerializerIrGenerator, serializableDescriptor, sti.serializer, property.module, property.type, property.genericIndex)
// todo: update
val decodeFuncToCall =
(if (innerSerial != null) "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}"