Rewrite IR plugin infrastructure (and serialization plugin) so it won't emit LazyIR.

LazyIR was emitted because plugin was not able to declare symbols, only to reference them.
Moreover, declarations added by frontend plugin were also unbound symbols produced by psi2ir,
and declaration stub generator was stubbing them with LazyIR – therefore access to global symbol table is not enough for plugins. IrProvider won't help here, because some functions produced by plugin have circular dependencies.

By moving compiler plugins step between psi2ir and declaration stub generator, both problems are resolved
– unbound symbols produced by psi2ir and compiler plugins are declared where they would be declared if this was a user code,
and only unbound symbols left are external dependencies, which is a correct input for lazy ir.
This commit is contained in:
Leonid Startsev
2019-11-15 18:33:46 +03:00
parent e4d0d450ab
commit 3e18350a1f
13 changed files with 187 additions and 145 deletions
@@ -5,18 +5,31 @@
package org.jetbrains.kotlin.backend.common.extensions
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.builders.IrGeneratorContext
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.resolve.BindingContext
class IrPluginContext(
val moduleDescriptor: ModuleDescriptor,
val bindingContext: BindingContext,
val languageVersionSettings: LanguageVersionSettings,
val symbolTable: SymbolTable,
val typeTranslator: TypeTranslator,
override val irBuiltIns: IrBuiltIns
): IrGeneratorContext()
interface IrGenerationExtension {
companion object :
ProjectExtensionDescriptor<IrGenerationExtension>("org.jetbrains.kotlin.irGenerationExtension", IrGenerationExtension::class.java)
fun generate(
file: IrFile,
backendContext: BackendContext,
bindingContext: BindingContext
moduleFragment: IrModuleFragment,
pluginContext: IrPluginContext
)
}
@@ -39,11 +39,11 @@ import org.jetbrains.kotlin.name.Name
class IrLoweringContext(backendContext: BackendContext) : IrGeneratorContextBase(backendContext.irBuiltIns)
class DeclarationIrBuilder(
backendContext: BackendContext,
generatorContext: IrGeneratorContext,
symbol: IrSymbol,
startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET
) : IrBuilderWithScope(
IrLoweringContext(backendContext),
generatorContext,
Scope(symbol),
startOffset,
endOffset
@@ -73,7 +73,7 @@ fun BackendContext.createIrBuilder(
startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET
) =
DeclarationIrBuilder(this, symbol, startOffset, endOffset)
DeclarationIrBuilder(IrLoweringContext(this), symbol, startOffset, endOffset)
fun <T : IrBuilder> T.at(element: IrElement) = this.at(element.startOffset, element.endOffset)
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.jvm.codegen.ClassCodegen
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
@@ -31,6 +33,23 @@ object JvmBackendFacade {
val psi2ir = Psi2IrTranslator(state.languageVersionSettings)
val psi2irContext = psi2ir.createGeneratorContext(state.module, state.bindingContext, extensions = JvmGeneratorExtensions)
val extensions = JvmStubGeneratorExtensions()
for (extension in IrGenerationExtension.getInstances(state.project)) {
psi2ir.addPostprocessingStep { module ->
extension.generate(
module,
IrPluginContext(
psi2irContext.moduleDescriptor,
psi2irContext.bindingContext,
psi2irContext.languageVersionSettings,
psi2irContext.symbolTable,
psi2irContext.typeTranslator,
psi2irContext.irBuiltIns
)
)
}
}
val irModuleFragment = psi2ir.generateModuleFragment(psi2irContext, files, stubGeneratorExtensions = extensions)
doGenerateFilesInternal(
state, errorHandler, irModuleFragment, psi2irContext.symbolTable, psi2irContext.sourceManager, phaseConfig, extensions
@@ -65,12 +84,6 @@ object JvmBackendFacade {
context.classNameOverride = extensions.classNameOverride
for (irFile in irModuleFragment.files) {
for (extension in IrGenerationExtension.getInstances(context.state.project)) {
extension.generate(irFile, context, context.state.bindingContext)
}
}
try {
JvmLower(context).lower(irModuleFragment)
} catch (e: Throwable) {
@@ -31,17 +31,15 @@ import org.jetbrains.kotlin.psi2ir.transformations.insertImplicitCasts
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.utils.SmartList
typealias Psi2IrPostprocessingStep = (IrModuleFragment) -> Unit
class Psi2IrTranslator(
val languageVersionSettings: LanguageVersionSettings,
val configuration: Psi2IrConfiguration = Psi2IrConfiguration()
) {
interface PostprocessingStep {
fun postprocess(context: GeneratorContext, irElement: IrElement)
}
private val postprocessingSteps = SmartList<Psi2IrPostprocessingStep>()
private val postprocessingSteps = SmartList<PostprocessingStep>()
fun add(step: PostprocessingStep) {
fun addPostprocessingStep(step: Psi2IrPostprocessingStep) {
postprocessingSteps.add(step)
}
@@ -74,20 +72,17 @@ class Psi2IrTranslator(
val moduleGenerator = ModuleGenerator(context)
val irModule = moduleGenerator.generateModuleFragment(ktFiles)
// This is required for implicit casts insertion on IrTypes (work-in-progress).
moduleGenerator.generateUnboundSymbolsAsDependencies(irModule, deserializer, irProviders, stubGeneratorExtensions)
irModule.patchDeclarationParents()
postprocess(context, irModule)
moduleGenerator.generateUnboundSymbolsAsDependencies(irModule, deserializer, irProviders, stubGeneratorExtensions)
return irModule
}
private fun postprocess(context: GeneratorContext, irElement: IrElement) {
private fun postprocess(context: GeneratorContext, irElement: IrModuleFragment) {
insertImplicitCasts(irElement, context)
generateAnnotationsForDeclarations(context, irElement)
postprocessingSteps.forEach { it.postprocess(context, irElement) }
postprocessingSteps.forEach { it(irElement) }
irElement.patchDeclarationParents()
}
@@ -177,6 +177,7 @@ fun loadIr(
}
val moduleFragment = psi2IrContext.generateModuleFragment(files, deserializer)
// todo: add postprocessing step
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, deserializer)
}
@@ -5,12 +5,11 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
@@ -27,7 +26,9 @@ 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.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
@@ -37,21 +38,15 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.allSealedSeri
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
val BackendContext.externalSymbols: ReferenceSymbolTable get() = ir.symbols.externalSymbolTable
internal fun BackendContext.createTypeTranslator(moduleDescriptor: ModuleDescriptor): TypeTranslator =
TypeTranslator(externalSymbols, irBuiltIns.languageVersionSettings, moduleDescriptor.builtIns).apply {
constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable = externalSymbols)
constantValueGenerator.typeTranslator = this
}
val SerializationPluginContext.externalSymbols: SymbolTable get() = symbolTable // Todo: deprecate and remove
val SerializationPluginContext.localSymbolTable: SymbolTable get() = symbolTable // Todo: deprecate and remove
interface IrBuilderExtension {
val compilerContext: BackendContext
val translator: TypeTranslator
val BackendContext.localSymbolTable: SymbolTable
val compilerContext: SerializationPluginContext
val translator: TypeTranslator get() = compilerContext.typeTranslator // Todo: deprecate and remove
private fun IrClass.declareSimpleFunctionWithExternalOverrides(descriptor: FunctionDescriptor): IrSimpleFunction {
return compilerContext.localSymbolTable.declareSimpleFunction(startOffset, endOffset, SERIALIZABLE_PLUGIN_ORIGIN, descriptor)
@@ -64,26 +59,26 @@ interface IrBuilderExtension {
fun IrClass.contributeFunction(
descriptor: FunctionDescriptor,
fromStubs: Boolean = false,
declareNew: Boolean = true,
bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit
) {
val f: IrSimpleFunction = if (!fromStubs) declareSimpleFunctionWithExternalOverrides(
val f: IrSimpleFunction = if (declareNew) declareSimpleFunctionWithExternalOverrides(
descriptor
) else compilerContext.externalSymbols.referenceSimpleFunction(descriptor).owner
f.parent = this
f.returnType = descriptor.returnType!!.toIrType()
if (!fromStubs) f.createParameterDeclarations(this.thisReceiver!!)
f.body = compilerContext.createIrBuilder(f.symbol).at(this).irBlockBody(this.startOffset, this.endOffset) { bodyGen(f) }
if (declareNew) f.createParameterDeclarations(this.thisReceiver!!)
f.body = DeclarationIrBuilder(compilerContext, f.symbol, this.startOffset, this.endOffset).irBlockBody(this.startOffset, this.endOffset) { bodyGen(f) }
this.addMember(f)
}
fun IrClass.contributeConstructor(
descriptor: ClassConstructorDescriptor,
fromStubs: Boolean = false,
declareNew: Boolean = true,
overwriteValueParameters: Boolean = false,
bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit
) {
val c = if (!fromStubs) compilerContext.localSymbolTable.declareConstructor(
val c = if (declareNew) compilerContext.localSymbolTable.declareConstructor(
this.startOffset,
this.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN,
@@ -91,12 +86,12 @@ interface IrBuilderExtension {
) else compilerContext.externalSymbols.referenceConstructor(descriptor).owner
c.parent = this
c.returnType = descriptor.returnType.toIrType()
if (!fromStubs || overwriteValueParameters) c.createParameterDeclarations(
if (declareNew || overwriteValueParameters) c.createParameterDeclarations(
receiver = null,
overwriteValueParameters = overwriteValueParameters,
copyTypeParameters = false
)
c.body = compilerContext.createIrBuilder(c.symbol).at(this).irBlockBody(this.startOffset, this.endOffset) { bodyGen(c) }
c.body = DeclarationIrBuilder(compilerContext, c.symbol, this.startOffset, this.endOffset).irBlockBody(this.startOffset, this.endOffset) { bodyGen(c) }
this.addMember(c)
}
@@ -106,7 +101,8 @@ interface IrBuilderExtension {
vararg args: IrExpression,
typeHint: IrType? = null
): IrMemberAccessExpression {
val call = typeHint?.let { irCall(callee, type = it) } ?: irCall(callee)
val returnType = typeHint ?: callee.descriptor.returnType!!.toIrType()
val call = irCall(callee, type = returnType)
call.dispatchReceiver = dispatchReceiver
args.forEachIndexed(call::putValueArgument)
return call
@@ -126,25 +122,44 @@ interface IrBuilderExtension {
typeHint = returnTypeHint
).also { call -> typeArguments.forEachIndexed(call::putTypeArgument) }
// todo: remove copypasta
private fun SerializationPluginContext.builtInsPackage(vararg packageNameSegments: String) =
builtIns.builtInsModule.getPackage(FqName.fromSegments(listOf(*packageNameSegments))).memberScope
private fun SerializationPluginContext.getSimpleFunction(
name: Name,
vararg packageNameSegments: String = arrayOf("kotlin"),
condition: (SimpleFunctionDescriptor) -> Boolean
): IrSimpleFunctionSymbol =
symbolTable.referenceSimpleFunction(
builtInsPackage(*packageNameSegments).getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
.first(condition)
)
fun IrBuilderWithScope.createArrayOfExpression(
arrayElementType: IrType,
arrayElements: List<IrExpression>
): IrExpression {
val arrayType = compilerContext.ir.symbols.array.typeWith(arrayElementType)
val arrayType = context.irBuiltIns.arrayClass.typeWith(arrayElementType)
val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, arrayElementType, arrayElements)
val typeArguments = listOf(arrayElementType)
return irCall(compilerContext.ir.symbols.arrayOf, arrayType, typeArguments = typeArguments).apply {
val arrayOf = compilerContext.getSimpleFunction(Name.identifier("arrayOf")) {
it.extensionReceiverParameter == null && it.dispatchReceiverParameter == null && it.valueParameters.size == 1 &&
it.valueParameters[0].isVararg
}
return irCall(arrayOf, arrayType, typeArguments = typeArguments).apply {
putValueArgument(0, arg0)
}
}
fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression {
val symbol = compilerContext.ir.symbols.getBinaryOperator(
name,
lhs.type.toKotlinType(),
rhs.type.toKotlinType()
val symbol = compilerContext.symbolTable.referenceSimpleFunction(
lhs.type.toKotlinType().memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
.first { it.valueParameters.size == 1 && it.valueParameters[0].type == rhs.type.toKotlinType() }
)
return irInvoke(lhs, symbol, rhs)
}
@@ -271,9 +286,9 @@ interface IrBuilderExtension {
descriptor: PropertyAccessorDescriptor,
fieldSymbol: IrFieldSymbol
): IrSimpleFunction {
// Declaration can also be called from user code. Since we lookup descriptor getter in externalSymbols
// (see generateSave/generateLoad), seems it is correct approach to declare getter lazily there.
val declaration = compilerContext.externalSymbols.referenceSimpleFunction(descriptor).owner
val declaration = compilerContext.externalSymbols.declareSimpleFunctionWithOverrides(fieldSymbol.owner.startOffset,
fieldSymbol.owner.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN,descriptor)
return declaration.buildWithScope { irAccessor ->
irAccessor.createParameterDeclarations(receiver = null)
irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType()
@@ -481,7 +496,7 @@ interface IrBuilderExtension {
): IrExpression {
return if (type.isMarkedNullable)
irInvoke(
null, nullableSerializerClass.constructors.toList()[0],
null, compilerContext.symbolTable.referenceConstructor(nullableSerializerClass.descriptor.constructors.toList().first()),
typeArguments = listOf(type.makeNotNullable().toIrType()),
valueArguments = listOf(expression),
returnTypeHint = wrapIrTypeIntoKSerializerIrType(module, type.toIrType())
@@ -21,22 +21,19 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class SerializableCompanionIrGenerator(
val irClass: IrClass,
override val compilerContext: BackendContext,
override val compilerContext: SerializationPluginContext,
bindingContext: BindingContext
) : SerializableCompanionCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module)
private val _table = SymbolTable()
override val BackendContext.localSymbolTable: SymbolTable
get() = _table
companion object {
fun generate(
irClass: IrClass,
context: BackendContext,
context: SerializationPluginContext,
bindingContext: BindingContext
) {
val companionDescriptor = irClass.descriptor
@@ -63,9 +60,9 @@ class SerializableCompanionIrGenerator(
compilerContext.externalSymbols.referenceConstructor(it)
})
val annotationType = compilerContext.externalSymbols.referenceClass(annotationMarkerClass).owner.defaultType
val annotationType = annotationMarkerClass.defaultType.toIrType()
val irSerializableClass = compilerContext.externalSymbols.referenceClass(serializableDescriptor).owner
val annotationCtorCall = IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, annotationType, annotationCtor, annotationMarkerClass.declaredTypeParameters.size).apply {
val annotationCtorCall = IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, annotationType, annotationCtor).apply {
val serializerType = serializer.toSimpleType(false)
putValueArgument(
0,
@@ -81,7 +78,7 @@ class SerializableCompanionIrGenerator(
}
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) =
irClass.contributeFunction(methodDescriptor, fromStubs = true) { getter ->
irClass.contributeFunction(methodDescriptor) { getter ->
val serializer = requireNotNull(
findTypeSerializer(
serializableDescriptor.module,
@@ -28,21 +28,18 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
class SerializableIrGenerator(
val irClass: IrClass,
override val compilerContext: BackendContext,
override val compilerContext: SerializationPluginContext,
bindingContext: BindingContext
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module)
private val _table = SymbolTable()
override val BackendContext.localSymbolTable: SymbolTable
get() = _table
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) =
irClass.contributeConstructor(constructorDescriptor, fromStubs = true, overwriteValueParameters = true) { ctor ->
irClass.contributeConstructor(constructorDescriptor, overwriteValueParameters = true) { ctor ->
val transformFieldInitializer = buildInitializersRemapping(irClass)
// Missing field exception parts
@@ -50,7 +47,7 @@ class SerializableIrGenerator(
serializableDescriptor.getClassFromSerializationPackage(MISSING_FIELD_EXC)
.unsubstitutedPrimaryConstructor!!
val exceptionCtorRef = compilerContext.externalSymbols.referenceConstructor(exceptionCtor)
val exceptionType = exceptionCtorRef.owner.returnType
val exceptionType = exceptionCtor.returnType.toIrType()
val serializableProperties = properties.serializableProperties
val seenVarsOffset = serializableProperties.bitMaskSlotCount()
@@ -166,7 +163,7 @@ class SerializableIrGenerator(
companion object {
fun generate(
irClass: IrClass,
context: BackendContext,
context: SerializationPluginContext,
bindingContext: BindingContext
) {
val serializableClass = irClass.descriptor
@@ -5,9 +5,9 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrVariable
@@ -20,9 +20,14 @@ import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class SerializerForEnumsGenerator(irClass: IrClass, compilerContext: BackendContext, bindingContext: BindingContext) :
class SerializerForEnumsGenerator(
irClass: IrClass,
compilerContext: SerializationPluginContext,
bindingContext: BindingContext
) :
SerializerIrGenerator(irClass, compilerContext, bindingContext) {
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
@@ -53,9 +58,13 @@ class SerializerForEnumsGenerator(irClass: IrClass, compilerContext: BackendCont
val getValues = irInvoke(dispatchReceiver = null, callee = valuesF.symbol)
val arrayGet =
compilerContext.ir.symbols.array.owner.functions.single { it.name == Name.identifier("get") }.symbol
compilerContext.builtIns.array.unsubstitutedMemberScope.getContributedFunctions(
Name.identifier("get"),
NoLookupLocation.FROM_BACKEND
).single()
val arrayGetSymbol = compilerContext.externalSymbols.referenceFunction(arrayGet)
val getValueByOrdinal =
irInvoke(getValues, arrayGet, irInvoke(irGet(loadFunc.valueParameters[0]), decode, serialDescGetter))
irInvoke(getValues, arrayGetSymbol, irInvoke(irGet(loadFunc.valueParameters[0]), decode, serialDescGetter))
+irReturn(getValueByOrdinal)
}
@@ -70,7 +79,7 @@ class SerializerForEnumsGenerator(irClass: IrClass, compilerContext: BackendCont
return irInvoke(
null, ctor,
irString(serialName),
typeHint = ctor.owner.returnType
typeHint = ctor.descriptor.returnType.toIrType()
)
}
@@ -93,7 +102,7 @@ class SerializerForEnumsGenerator(irClass: IrClass, compilerContext: BackendCont
+call
// serialDesc.pushAnnotation(...)
copySerialInfoAnnotationsToDescriptor(
compilerContext.externalSymbols.referenceClass(entry).owner.annotations,
entry.annotations.mapNotNull(compilerContext.typeTranslator.constantValueGenerator::generateAnnotationConstructorCall),
localDescriptor,
serialDescImplClass.referenceMethod(CallingConventions.addAnnotation)
)
@@ -5,9 +5,8 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.descriptors.*
@@ -25,6 +24,7 @@ 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.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
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
@@ -36,14 +36,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UN
// Is creating synthetic origin is a good idea or not?
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER")
open class SerializerIrGenerator(val irClass: IrClass, final override val compilerContext: BackendContext, bindingContext: BindingContext) :
open class SerializerIrGenerator(val irClass: IrClass, final override val compilerContext: SerializationPluginContext, bindingContext: BindingContext) :
SerializerCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
final override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module)
private val _table = SymbolTable()
final override val BackendContext.localSymbolTable: SymbolTable
get() = _table
protected val serializableIrClass = compilerContext.externalSymbols.referenceClass(serializableDescriptor).owner
override fun generateSerialDesc() {
@@ -75,30 +69,31 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
val ctor = irClass.declarations.filterIsInstance<IrConstructor>().find { it.isPrimary }
?: throw AssertionError("Serializer must have primary constructor")
compilerContext.localSymbolTable.withScope(initIrBody.descriptor) {
initIrBody.body = compilerContext.createIrBuilder(initIrBody.symbol).irBlockBody {
val localDesc = irTemporary(
instantiateNewDescriptor(serialDescImplClass, irGet(thisAsReceiverParameter)),
nameHint = "serialDesc"
)
initIrBody.body =
DeclarationIrBuilder(compilerContext, initIrBody.symbol, initIrBody.startOffset, initIrBody.endOffset).irBlockBody {
val localDesc = irTemporary(
instantiateNewDescriptor(serialDescImplClass, irGet(thisAsReceiverParameter)),
nameHint = "serialDesc"
)
addElementsContentToDescriptor(serialDescImplClass, localDesc, addFuncS)
// add class annotations
copySerialInfoAnnotationsToDescriptor(
serializableIrClass.annotations,
localDesc,
serialDescImplClass.referenceMethod(CallingConventions.addClassAnnotation)
)
addElementsContentToDescriptor(serialDescImplClass, localDesc, addFuncS)
// add class annotations
copySerialInfoAnnotationsToDescriptor(
serializableIrClass.annotations,
localDesc,
serialDescImplClass.referenceMethod(CallingConventions.addClassAnnotation)
)
// save local descriptor to field
+irSetField(
generateReceiverExpressionForFieldAccess(
thisAsReceiverParameter.symbol,
generatedSerialDescPropertyDescriptor
),
prop.backingField!!,
irGet(localDesc)
)
}
// save local descriptor to field
+irSetField(
generateReceiverExpressionForFieldAccess(
thisAsReceiverParameter.symbol,
generatedSerialDescPropertyDescriptor
),
prop.backingField!!,
irGet(localDesc)
)
}
(ctor.body as? IrBlockBody)?.statements?.addAll(initIrBody.body.statements)
}
}
@@ -113,8 +108,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
val serialClassDescImplCtor = compilerContext.externalSymbols.referenceConstructor(serialDescImplConstructor)
return irInvoke(
null, serialClassDescImplCtor,
irString(serialName), if (isGeneratedSerializer) correctThis else irNull(),
typeHint = serialClassDescImplCtor.owner.returnType
irString(serialName), if (isGeneratedSerializer) correctThis else irNull()
)
}
@@ -155,7 +149,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
}
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ClassConstructorDescriptor) =
irClass.contributeConstructor(typedConstructorDescriptor, fromStubs = true) { ctor ->
irClass.contributeConstructor(typedConstructorDescriptor) { ctor ->
// generate call to primary ctor to init serialClassDesc and super()
val primaryCtor = irClass.constructors.find { it.isPrimary }
?: throw AssertionError("Serializer class must have primary constructor")
@@ -183,9 +177,11 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
}
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function, fromStubs = true) { irFun ->
val allSerializers = serializableProperties.map { requireNotNull(
serializerTower(this@SerializerIrGenerator, irFun.dispatchReceiverParameter!!, it)) { "Property ${it.name} must have a serializer" }
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun ->
val allSerializers = serializableProperties.map {
requireNotNull(
serializerTower(this@SerializerIrGenerator, irFun.dispatchReceiverParameter!!, it)
) { "Property ${it.name} must have a serializer" }
}
val kSerType = ((irFun.returnType as IrSimpleType).arguments.first() as IrTypeProjection).type
@@ -200,7 +196,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
protected fun ClassDescriptor.referenceMethod(methodName: String) =
getFuncDesc(methodName).single().let { compilerContext.externalSymbols.referenceFunction(it) }
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function, fromStubs = true) { saveFunc ->
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
val fieldInitializer: (SerializableProperty) -> IrExpression? =
buildInitializersRemapping(serializableIrClass).run { { invoke(it.irField) } }
@@ -218,7 +214,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
// fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder
val beginFunc = kOutputSmallClass.referenceMethod(CallingConventions.begin) // todo: retrieve from actual encoder instead
val call = irCall(beginFunc).mapValueParametersIndexed { i, parameterDescriptor ->
val call = irCall(beginFunc, type = beginFunc.descriptor.returnType!!.toIrType()).mapValueParametersIndexed { i, parameterDescriptor ->
if (i == 0) irGet(localSerialDesc) else IrVarargImpl(
startOffset,
endOffset,
@@ -269,7 +265,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
property.irGet()
)
}
val typeArgs = if (writeFunc.owner.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
val typeArgs = if (writeFunc.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
val elementCall = irInvoke(irGet(localOutput), writeFunc, typeArguments = typeArgs, valueArguments = args)
// check for call to .shouldEncodeElementDefault
@@ -316,7 +312,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
defaultPrimitive to kType
}
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function, fromStubs = true) { loadFunc ->
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc ->
if (serializableDescriptor.modality == Modality.ABSTRACT || serializableDescriptor.modality == Modality.SEALED) {
return@contributeFunction
}
@@ -393,7 +389,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
inputClass.referenceMethod(it)
}
val typeArgs =
if (decodeFuncToCall.owner.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
if (decodeFuncToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
val args = mutableListOf<IrExpression>(localSerialDesc.get(), irInt(index))
if (innerSerial != null)
args.add(innerSerial)
@@ -421,8 +417,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
irInvoke(
null,
excClassRef,
indexVar.get(),
typeHint = excClassRef.owner.returnType
indexVar.get()
)
)
)
@@ -454,7 +449,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
companion object {
fun generate(
irClass: IrClass,
context: BackendContext,
context: SerializationPluginContext,
bindingContext: BindingContext
) {
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
@@ -5,18 +5,18 @@
package org.jetbrains.kotlinx.serialization.compiler.extensions
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializableCompanionIrGenerator
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializableIrGenerator
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator
@@ -37,24 +37,26 @@ fun ClassLoweringPass.runOnFileInOrder(irFile: IrFile) {
})
}
typealias SerializationPluginContext = IrPluginContext
private class SerializerClassLowering(
val context: BackendContext,
val bindingContext: BindingContext
val context: SerializationPluginContext
) :
IrElementTransformerVoid(), ClassLoweringPass {
override fun lower(irClass: IrClass) {
SerializableIrGenerator.generate(irClass, context, bindingContext)
SerializerIrGenerator.generate(irClass, context, bindingContext)
SerializableCompanionIrGenerator.generate(irClass, context, bindingContext)
SerializableIrGenerator.generate(irClass, context, context.bindingContext)
SerializerIrGenerator.generate(irClass, context, context.bindingContext)
SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext)
}
}
open class SerializationLoweringExtension : IrGenerationExtension {
override fun generate(
file: IrFile,
backendContext: BackendContext,
bindingContext: BindingContext
moduleFragment: IrModuleFragment,
pluginContext: IrPluginContext
) {
SerializerClassLowering(backendContext, bindingContext).runOnFileInOrder(file)
val serializerClassLowering = SerializerClassLowering(pluginContext)
for (file in moduleFragment.files)
serializerClassLowering.runOnFileInOrder(file)
}
}
@@ -186,8 +186,10 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa
ALOAD (4)
ALOAD (3)
INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V)
RETURN
LABEL (L2)
LINENUMBER (13)
RETURN
LABEL (L3)
}
public void serialize(kotlinx.serialization.Encoder p0, java.lang.Object p1) {
@@ -487,8 +489,10 @@ public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serializ
ALOAD (4)
ALOAD (3)
INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V)
RETURN
LABEL (L7)
LINENUMBER (10)
RETURN
LABEL (L8)
}
public void serialize(kotlinx.serialization.Encoder p0, java.lang.Object p1) {
@@ -829,8 +833,10 @@ public final class User$$serializer : java/lang/Object, kotlinx/serialization/in
ALOAD (4)
ALOAD (3)
INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V)
RETURN
LABEL (L2)
LINENUMBER (7)
RETURN
LABEL (L3)
}
public void serialize(kotlinx.serialization.Encoder p0, java.lang.Object p1) {
@@ -957,4 +963,4 @@ public final class User : java/lang/Object {
public final java.lang.String getFirstName()
public final java.lang.String getLastName()
}
}
@@ -5,14 +5,13 @@
package org.jetbrains.kotlinx.serialization.compiler.extensions
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.idea.runIfEnabledOn
class SerializationIDECodegenExtension : SerializationCodegenExtension() {
@@ -32,7 +31,7 @@ class SerializationIDEJsExtension : SerializationJsExtension() {
}
class SerializationIDEIrExtension : SerializationLoweringExtension() {
override fun generate(file: IrFile, backendContext: BackendContext, bindingContext: BindingContext) {
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
/* No-op don't enable IR extensions in IDE */
}
}