Descriptors for IR
This commit is contained in:
committed by
Leonid Startsev
parent
3010814327
commit
01d3c7bdc8
+88
-1
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-53
@@ -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}"
|
||||
|
||||
Reference in New Issue
Block a user