Insert correct offsets in a lot of places in IR

Use correct type arguments when invoking a generic functions
Fix missing parent in initializer
This commit is contained in:
Leonid Startsev
2019-02-14 14:22:13 +03:00
parent 66272bfa74
commit 8b16801f0d
2 changed files with 93 additions and 62 deletions
@@ -6,10 +6,10 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId 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.enumSerializerId
@@ -68,32 +69,25 @@ interface IrBuilderExtension {
f.parent = this f.parent = this
f.returnType = descriptor.returnType!!.toIrType() f.returnType = descriptor.returnType!!.toIrType()
if (!fromStubs) f.createParameterDeclarations(this.thisReceiver) if (!fromStubs) f.createParameterDeclarations(this.thisReceiver)
f.body = compilerContext.createIrBuilder(f.symbol).irBlockBody { bodyGen(f) } f.body = compilerContext.createIrBuilder(f.symbol).at(this).irBlockBody(this.startOffset, this.endOffset) { bodyGen(f) }
this.addMember(f) this.addMember(f)
} }
fun IrClass.contributeCtor(descriptor: ClassConstructorDescriptor, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) {
val c = compilerContext.externalSymbols.referenceConstructor(descriptor).owner
c.parent = this
c.returnType = descriptor.returnType.toIrType()
c.body = compilerContext.createIrBuilder(c.symbol).irBlockBody { bodyGen(c) }
this.addMember(c)
}
fun IrClass.contributeConstructor( fun IrClass.contributeConstructor(
descriptor: ClassConstructorDescriptor, descriptor: ClassConstructorDescriptor,
fromStubs: Boolean = false,
bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit
) { ) {
val c = compilerContext.localSymbolTable.declareConstructor( val c = if (!fromStubs) compilerContext.localSymbolTable.declareConstructor(
this.startOffset, this.startOffset,
this.endOffset, this.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN, SERIALIZABLE_PLUGIN_ORIGIN,
descriptor descriptor
) ) else compilerContext.externalSymbols.referenceConstructor(descriptor).owner
c.parent = this c.parent = this
c.returnType = descriptor.returnType.toIrType() c.returnType = descriptor.returnType.toIrType()
c.createParameterDeclarations() if (!fromStubs) c.createParameterDeclarations()
c.body = compilerContext.createIrBuilder(c.symbol).irBlockBody { bodyGen(c) } c.body = compilerContext.createIrBuilder(c.symbol).at(this).irBlockBody(this.startOffset, this.endOffset) { bodyGen(c) }
this.addMember(c) this.addMember(c)
} }
@@ -109,6 +103,19 @@ interface IrBuilderExtension {
return call return call
} }
fun IrBuilderWithScope.irInvoke(
dispatchReceiver: IrExpression? = null,
callee: IrFunctionSymbol,
typeArguments: List<IrType?>,
valueArguments: List<IrExpression>,
returnTypeHint: IrType? = null
): IrCall = irInvoke(
dispatchReceiver,
callee,
args = *valueArguments.toTypedArray(),
typeHint = returnTypeHint
).also { call -> typeArguments.forEachIndexed(call::putTypeArgument) }
fun IrBuilderWithScope.createArrayOfExpression( fun IrBuilderWithScope.createArrayOfExpression(
arrayElementType: IrType, arrayElementType: IrType,
arrayElements: List<IrExpression> arrayElements: List<IrExpression>
@@ -221,12 +228,13 @@ interface IrBuilderExtension {
propertyParent: IrClass propertyParent: IrClass
): IrProperty { ): IrProperty {
val irProperty = IrPropertyImpl( val irProperty = IrPropertyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, propertyParent.startOffset, propertyParent.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN, false, SERIALIZABLE_PLUGIN_ORIGIN, false,
propertyDescriptor propertyDescriptor
) )
irProperty.parent = propertyParent irProperty.parent = propertyParent
irProperty.backingField = generatePropertyBackingField(propertyDescriptor).apply { parent = propertyParent } irProperty.backingField =
generatePropertyBackingField(propertyDescriptor, irProperty).apply { parent = propertyParent }
val fieldSymbol = irProperty.backingField!!.symbol val fieldSymbol = irProperty.backingField!!.symbol
irProperty.getter = propertyDescriptor.getter?.let { generatePropertyAccessor(it, fieldSymbol, ownerSymbol) } irProperty.getter = propertyDescriptor.getter?.let { generatePropertyAccessor(it, fieldSymbol, ownerSymbol) }
?.apply { parent = propertyParent } ?.apply { parent = propertyParent }
@@ -235,10 +243,13 @@ interface IrBuilderExtension {
return irProperty return irProperty
} }
fun generatePropertyBackingField(propertyDescriptor: PropertyDescriptor): IrField { private fun generatePropertyBackingField(
propertyDescriptor: PropertyDescriptor,
originProperty: IrProperty
): IrField {
return compilerContext.localSymbolTable.declareField( return compilerContext.localSymbolTable.declareField(
UNDEFINED_OFFSET, originProperty.startOffset,
UNDEFINED_OFFSET, originProperty.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN, SERIALIZABLE_PLUGIN_ORIGIN,
propertyDescriptor, propertyDescriptor,
propertyDescriptor.type.toIrType() propertyDescriptor.type.toIrType()
@@ -271,16 +282,18 @@ interface IrBuilderExtension {
): IrBlockBody { ): IrBlockBody {
val property = getter.correspondingProperty val property = getter.correspondingProperty
val irBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) val startOffset = irAccessor.startOffset
val endOffset = irAccessor.endOffset
val irBody = IrBlockBodyImpl(startOffset, endOffset)
val receiver = generateReceiverExpressionForFieldAccess(ownerSymbol, property) val receiver = generateReceiverExpressionForFieldAccess(ownerSymbol, property)
irBody.statements.add( irBody.statements.add(
IrReturnImpl( IrReturnImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, compilerContext.irBuiltIns.nothingType, startOffset, endOffset, compilerContext.irBuiltIns.nothingType,
irAccessor.symbol, irAccessor.symbol,
IrGetFieldImpl( IrGetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, startOffset, endOffset,
compilerContext.localSymbolTable.referenceField(property), compilerContext.localSymbolTable.referenceField(property),
property.type.toIrType(), property.type.toIrType(),
receiver receiver
@@ -297,8 +310,8 @@ interface IrBuilderExtension {
): IrBlockBody { ): IrBlockBody {
val property = setter.correspondingProperty val property = setter.correspondingProperty
val startOffset = UNDEFINED_OFFSET val startOffset = irAccessor.startOffset
val endOffset = UNDEFINED_OFFSET val endOffset = irAccessor.endOffset
val irBody = IrBlockBodyImpl(startOffset, endOffset) val irBody = IrBlockBodyImpl(startOffset, endOffset)
val receiver = generateReceiverExpressionForFieldAccess(ownerSymbol, property) val receiver = generateReceiverExpressionForFieldAccess(ownerSymbol, property)
@@ -306,7 +319,7 @@ interface IrBuilderExtension {
val irValueParameter = irAccessor.valueParameters.single() val irValueParameter = irAccessor.valueParameters.single()
irBody.statements.add( irBody.statements.add(
IrSetFieldImpl( IrSetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, startOffset, endOffset,
compilerContext.localSymbolTable.referenceField(property), compilerContext.localSymbolTable.referenceField(property),
receiver, receiver,
IrGetValueImpl(startOffset, endOffset, irValueParameter.type, irValueParameter.symbol), IrGetValueImpl(startOffset, endOffset, irValueParameter.type, irValueParameter.symbol),
@@ -324,7 +337,7 @@ interface IrBuilderExtension {
return when (containingDeclaration) { return when (containingDeclaration) {
is ClassDescriptor -> is ClassDescriptor ->
IrGetValueImpl( IrGetValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, ownerSymbol.owner.startOffset, ownerSymbol.owner.endOffset,
// symbolTable.referenceValue(containingDeclaration.thisAsReceiverParameter) // symbolTable.referenceValue(containingDeclaration.thisAsReceiverParameter)
ownerSymbol ownerSymbol
) )
@@ -335,7 +348,7 @@ interface IrBuilderExtension {
// todo: delet zis // todo: delet zis
fun IrFunction.createParameterDeclarations(receiver: IrValueParameter? = null) { fun IrFunction.createParameterDeclarations(receiver: IrValueParameter? = null) {
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl( fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, this@createParameterDeclarations.startOffset, this@createParameterDeclarations.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN, SERIALIZABLE_PLUGIN_ORIGIN,
this, this,
type.toIrType(), type.toIrType(),
@@ -353,7 +366,7 @@ interface IrBuilderExtension {
assert(typeParameters.isEmpty()) assert(typeParameters.isEmpty())
descriptor.typeParameters.mapTo(typeParameters) { descriptor.typeParameters.mapTo(typeParameters) {
IrTypeParameterImpl( IrTypeParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, startOffset, endOffset,
SERIALIZABLE_PLUGIN_ORIGIN, SERIALIZABLE_PLUGIN_ORIGIN,
it it
).also { typeParameter -> ).also { typeParameter ->
@@ -422,7 +435,14 @@ interface IrBuilderExtension {
property.descriptor.findPsi() property.descriptor.findPsi()
) else null ) else null
return serializerInstance(generator, generator.serializableDescriptor, serializer, property.module, property.type, property.genericIndex) 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 } ?.let { expr -> wrapWithNullableSerializerIfNeeded(property.type, expr, nullableSerClass) }
}
private fun IrBuilderWithScope.wrapWithNullableSerializerIfNeeded(type: KotlinType, expression: IrExpression, nullableSerializerClass: IrClassSymbol): IrExpression {
return if (type.isMarkedNullable)
irInvoke(null, nullableSerializerClass.constructors.toList()[0], listOf(type.makeNotNullable().toIrType()), listOf(expression))
else
expression
} }
fun IrBuilderWithScope.serializerInstance( fun IrBuilderWithScope.serializerInstance(
@@ -464,12 +484,13 @@ interface IrBuilderExtension {
val argSer = enclosingGenerator.findTypeSerializerOrContext(module, it.type, sourceElement = serializerClassOriginal.findPsi()) val argSer = enclosingGenerator.findTypeSerializerOrContext(module, it.type, sourceElement = serializerClassOriginal.findPsi())
val expr = serializerInstance(enclosingGenerator, serializableDescriptor, argSer, module, it.type, it.type.genericIndex) val expr = serializerInstance(enclosingGenerator, serializableDescriptor, argSer, module, it.type, it.type.genericIndex)
?: return null ?: return null
if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr wrapWithNullableSerializerIfNeeded(it.type, expr, nullableSerClass)
} }
} }
if (serializerClassOriginal.classId == referenceArraySerializerId) if (serializerClassOriginal.classId == referenceArraySerializerId)
args = listOf(classReference(kType.arguments[0].type)) + args args = listOf(classReference(kType.arguments[0].type)) + args
val typeArgs = kType.arguments.map { it.type.toIrType() }
val serializable = getSerializableClassDescriptorBySerializer(serializerClass) val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) { val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
requireNotNull( requireNotNull(
@@ -479,11 +500,7 @@ interface IrBuilderExtension {
} else { } else {
compilerContext.externalSymbols.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!) compilerContext.externalSymbols.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!)
} }
return irInvoke( return irInvoke(null, ctor, typeArgs, args)
null,
ctor,
*args.toTypedArray()
)
} }
} }
@@ -76,6 +76,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
compilerContext.localSymbolTable.declareAnonymousInitializer( compilerContext.localSymbolTable.declareAnonymousInitializer(
irClass.startOffset, irClass.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irClass.descriptor irClass.startOffset, irClass.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irClass.descriptor
).buildWithScope { initIrBody -> ).buildWithScope { initIrBody ->
initIrBody.parent = irClass
val ctor = irClass.declarations.filterIsInstance<IrConstructor>().find { it.isPrimary } val ctor = irClass.declarations.filterIsInstance<IrConstructor>().find { it.isPrimary }
?: throw AssertionError("Serializer must have primary constructor") ?: throw AssertionError("Serializer must have primary constructor")
val serialClassDescImplCtor = compilerContext.externalSymbols.referenceConstructor(serialDescImplConstructor) val serialClassDescImplCtor = compilerContext.externalSymbols.referenceConstructor(serialDescImplConstructor)
@@ -139,16 +140,15 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
} }
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ClassConstructorDescriptor) = override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ClassConstructorDescriptor) =
irClass.contributeCtor(typedConstructorDescriptor) { ctor -> irClass.contributeConstructor(typedConstructorDescriptor, fromStubs = true) { ctor ->
// generate call to primary ctor to init serialClassDesc and super() // generate call to primary ctor to init serialClassDesc and super()
val primaryCtor = irClass.descriptor.unsubstitutedPrimaryConstructor val primaryCtor = irClass.constructors.find { it.isPrimary }
?: throw AssertionError("Serializer class must have primary constructor") ?: throw AssertionError("Serializer class must have primary constructor")
+IrDelegatingConstructorCallImpl( +IrDelegatingConstructorCallImpl(
startOffset, startOffset,
endOffset, endOffset,
compilerContext.irBuiltIns.unitType, compilerContext.irBuiltIns.unitType,
compilerContext.localSymbolTable.referenceConstructor(primaryCtor), primaryCtor.symbol
primaryCtor
) )
// store type arguments serializers in fields // store type arguments serializers in fields
@@ -241,7 +241,8 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
property.irGet() property.irGet()
) )
} }
val elementCall = irInvoke(irGet(localOutput), writeFunc, *args.toTypedArray()) val typeArgs = if (writeFunc.owner.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
val elementCall = irInvoke(irGet(localOutput), writeFunc, typeArguments = typeArgs, valueArguments = args)
// check for call to .shouldEncodeElementDefault // check for call to .shouldEncodeElementDefault
if (!property.optional) { if (!property.optional) {
@@ -341,29 +342,42 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
// if index == -1 (READ_DONE) break loop // if index == -1 (READ_DONE) break loop
+IrBranchImpl(irEquals(indexVar.get(), irInt(-1)), irSetVar(flagVar.symbol, irBoolean(false))) +IrBranchImpl(irEquals(indexVar.get(), irInt(-1)), irSetVar(flagVar.symbol, irBoolean(false)))
val branchBodies: List<Pair<Int, IrExpression>> = serializableProperties.mapIndexed { index, property -> val branchBodies: List<Pair<Int, IrExpression>> =
val body = irBlock { serializableProperties.mapIndexed { index, property ->
val sti = getSerialTypeInfo(property) val body = irBlock {
val innerSerial = serializerInstance(this@SerializerIrGenerator, serializableDescriptor, sti.serializer, property.module, property.type, property.genericIndex) val sti = getSerialTypeInfo(property)
// todo: update val innerSerial = serializerInstance(
val decodeFuncToCall = this@SerializerIrGenerator,
(if (innerSerial != null) "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}" serializableDescriptor,
else "${CallingConventions.decode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}") sti.serializer,
.let { property.module,
inputClass.referenceMethod(it) property.type,
} property.genericIndex
val args = mutableListOf<IrExpression>(localSerialDesc.get(), irInt(index)) )
if (innerSerial != null) // todo: update
args.add(innerSerial) val decodeFuncToCall =
// local$i = localInput.decode...(...) (if (innerSerial != null) "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}"
+irSetVar(localProps[index].symbol, irInvoke(localInput.get(), decodeFuncToCall, *args.toTypedArray())) else "${CallingConventions.decode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
// bitMask[i] |= 1 << x .let {
val bitPos = 1 shl (index % 32) inputClass.referenceMethod(it)
val or = irBinOp(OperatorNameConventions.OR, bitMasks[index / 32].get(), irInt(bitPos)) }
+irSetVar(bitMasks[index / 32].symbol, or) val typeArgs =
if (decodeFuncToCall.owner.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
val args = mutableListOf(localSerialDesc.get(), irInt(index))
if (innerSerial != null)
args.add(innerSerial)
// local$i = localInput.decode...(...)
+irSetVar(
localProps[index].symbol,
irInvoke(localInput.get(), decodeFuncToCall, typeArgs, args)
)
// bitMask[i] |= 1 << x
val bitPos = 1 shl (index % 32)
val or = irBinOp(OperatorNameConventions.OR, bitMasks[index / 32].get(), irInt(bitPos))
+irSetVar(bitMasks[index / 32].symbol, or)
}
index to body
} }
index to body
}
branchBodies.forEach { (i, e) -> +IrBranchImpl(irEquals(indexVar.get(), irInt(i)), e) } branchBodies.forEach { (i, e) -> +IrBranchImpl(irEquals(indexVar.get(), irInt(i)), e) }
// throw exception on unknown field // throw exception on unknown field