IR-plugin
[IR-plugin] Synthetic property declaration in $serializer [IR-plugin] Saving most of simple cases [IP-plugin] Some refactoring and start of work on load func [IP-plugin] Loading simple case without validation [IP-plugin] Rebase to IR types and Native-enabled [IP-plugin] Generating .serializer() accessor in companion [IP-plugin] Basic synthetic deserializing constructor, fixed some todos [IR-plugin] Remove reference to SerialDescriptor.init() since K/N now has freeze-aware lazy
This commit is contained in:
+5
-5
@@ -19,14 +19,14 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
abstract class SerializableCodegen(declaration: KtPureClassOrObject, private val bindingContext: BindingContext) {
|
||||
protected val serializableDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
|
||||
abstract class SerializableCodegen(
|
||||
protected val serializableDescriptor: ClassDescriptor,
|
||||
private val bindingContext: BindingContext
|
||||
) {
|
||||
protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
|
||||
|
||||
fun generate() {
|
||||
|
||||
+7
-8
@@ -18,19 +18,18 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.SERIALIZER_PROVIDER_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
|
||||
|
||||
abstract class SerializableCompanionCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
|
||||
protected val companionDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
|
||||
abstract class SerializableCompanionCodegen(
|
||||
protected val companionDescriptor: ClassDescriptor /*declaration: KtPureClassOrObject*/
|
||||
) {
|
||||
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!!
|
||||
|
||||
fun generate() {
|
||||
val fser = KSerializerDescriptorResolver.createSerializerGetterDescriptor(companionDescriptor, serializableDescriptor)
|
||||
generateSerializerGetter(fser)
|
||||
val serializerGetterDescriptor = companionDescriptor.unsubstitutedMemberScope.findSingleFunction(SERIALIZER_PROVIDER_NAME)
|
||||
generateSerializerGetter(serializerGetterDescriptor)
|
||||
}
|
||||
|
||||
protected abstract fun generateSerializerGetter(methodDescriptor: FunctionDescriptor)
|
||||
|
||||
+7
-2
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor
|
||||
|
||||
@@ -36,11 +37,12 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
|
||||
|
||||
fun generate() {
|
||||
check(properties.isExternallySerializable) { "Class ${serializableDescriptor.name} is not externally serializable" }
|
||||
generateSerialDesc()
|
||||
val prop = generateSerializableClassPropertyIfNeeded()
|
||||
val save = generateSaveIfNeeded()
|
||||
val load = generateLoadIfNeeded()
|
||||
if (save || load || prop)
|
||||
generateSerialDesc()
|
||||
// if (save || load || prop)
|
||||
// generateSerialDesc()
|
||||
if (serializableDescriptor.declaredTypeParameters.isNotEmpty() && typedSerializerConstructorNotDeclared()) {
|
||||
generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor))
|
||||
}
|
||||
@@ -111,4 +113,7 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
|
||||
property.returnType != null &&
|
||||
isReturnTypeOk(property)
|
||||
}
|
||||
|
||||
protected fun ClassDescriptor.getFuncDesc(funcName: String): Sequence<FunctionDescriptor> =
|
||||
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }.asSequence().filterIsInstance<FunctionDescriptor>()
|
||||
}
|
||||
|
||||
+2
-1
@@ -51,7 +51,8 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
|
||||
T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
|
||||
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(
|
||||
property,
|
||||
T.nameIfStandardType.toString().capitalize()
|
||||
T.getJetTypeFqName(false).removePrefix("kotlin.") // i don't feel so good about it...
|
||||
// alternative: KotlinBuiltIns.getPrimitiveType(T)!!.typeName.identifier
|
||||
)
|
||||
KotlinBuiltIns.isString(T) -> SerialTypeInfo(property, "String")
|
||||
KotlinBuiltIns.isUnit(T) -> SerialTypeInfo(property, "Unit", unit = true)
|
||||
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
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.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
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.util.TypeTranslator
|
||||
import org.jetbrains.kotlin.ir.util.declareSimpleFunctionWithOverrides
|
||||
import org.jetbrains.kotlin.ir.util.withScope
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperty
|
||||
|
||||
interface IrBuilderExtension {
|
||||
val compilerContext: BackendContext
|
||||
val translator: TypeTranslator
|
||||
|
||||
fun IrClass.contributeFunction(descriptor: FunctionDescriptor, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) {
|
||||
val f = compilerContext.symbolTable.declareSimpleFunctionWithOverrides(
|
||||
this.startOffset,
|
||||
this.endOffset,
|
||||
SERIALIZABLE_PLUGIN_ORIGIN,
|
||||
descriptor
|
||||
)
|
||||
f.parent = this
|
||||
f.returnType = descriptor.returnType!!.toIrType()
|
||||
f.createParameterDeclarations()
|
||||
f.body = compilerContext.createIrBuilder(f.symbol).irBlockBody { bodyGen(f) }
|
||||
this.addMember(f)
|
||||
}
|
||||
|
||||
fun IrClass.contributeConstructor(
|
||||
descriptor: ClassConstructorDescriptor,
|
||||
bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit
|
||||
) {
|
||||
val c = compilerContext.symbolTable.declareConstructor(
|
||||
this.startOffset,
|
||||
this.endOffset,
|
||||
SERIALIZABLE_PLUGIN_ORIGIN,
|
||||
descriptor
|
||||
)
|
||||
c.parent = this
|
||||
c.returnType = descriptor.returnType.toIrType()
|
||||
c.createParameterDeclarations()
|
||||
c.body = compilerContext.createIrBuilder(c.symbol).irBlockBody { bodyGen(c) }
|
||||
this.addMember(c)
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.irInvoke(
|
||||
dispatchReceiver: IrExpression? = null,
|
||||
callee: IrFunctionSymbol,
|
||||
vararg args: IrExpression,
|
||||
typeHint: IrType? = null
|
||||
): IrCall {
|
||||
val call = typeHint?.let { irCall(callee, type = it) } ?: irCall(callee)
|
||||
call.dispatchReceiver = dispatchReceiver
|
||||
args.forEachIndexed(call::putValueArgument)
|
||||
return call
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression {
|
||||
val symbol = compilerContext.ir.symbols.getBinaryOperator(
|
||||
name,
|
||||
lhs.type.toKotlinType(),
|
||||
rhs.type.toKotlinType()
|
||||
)
|
||||
return irInvoke(lhs, symbol, rhs)
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.irGetObject(classDescriptor: ClassDescriptor) =
|
||||
IrGetObjectValueImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
classDescriptor.defaultType.toIrType(),
|
||||
compilerContext.symbolTable.referenceClass(classDescriptor)
|
||||
)
|
||||
|
||||
fun <T : IrDeclaration> T.buildWithScope(builder: (T) -> Unit): T =
|
||||
also { irDeclaration ->
|
||||
compilerContext.symbolTable.withScope(irDeclaration.descriptor) {
|
||||
builder(irDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.irEmptyVararg(forValueParameter: ValueParameterDescriptor) =
|
||||
IrVarargImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
forValueParameter.type.toIrType(),
|
||||
forValueParameter.varargElementType!!.toIrType()
|
||||
)
|
||||
|
||||
class BranchBuilder(
|
||||
val irWhen: IrWhen,
|
||||
context: IrGeneratorContext,
|
||||
scope: Scope,
|
||||
startOffset: Int,
|
||||
endOffset: Int
|
||||
) : IrBuilderWithScope(context, scope, startOffset, endOffset) {
|
||||
operator fun IrBranch.unaryPlus() {
|
||||
irWhen.branches.add(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.irWhen(typeHint: IrType? = null, block: BranchBuilder.() -> Unit): IrWhen {
|
||||
val whenExpr = IrWhenImpl(startOffset, endOffset, typeHint ?: compilerContext.irBuiltIns.unitType)
|
||||
val builder = BranchBuilder(whenExpr, context, scope, startOffset, endOffset)
|
||||
builder.block()
|
||||
return whenExpr
|
||||
}
|
||||
|
||||
fun BranchBuilder.elseBranch(result: IrExpression): IrElseBranch =
|
||||
IrElseBranchImpl(
|
||||
IrConstImpl.boolean(result.startOffset, result.endOffset, compilerContext.irBuiltIns.booleanType, true),
|
||||
result
|
||||
)
|
||||
|
||||
fun translateType(ktType: KotlinType): IrType =
|
||||
translator.translateType(ktType)
|
||||
|
||||
fun KotlinType.toIrType() = translateType(this)
|
||||
|
||||
|
||||
val SerializableProperty.irField: IrField
|
||||
get () = compilerContext.symbolTable.referenceField(this.descriptor).owner
|
||||
|
||||
/*
|
||||
The rest of the file is mainly copied from FunctionGenerator.
|
||||
However, I can't use it's directly because all generateSomething methods require KtProperty (psi element)
|
||||
Also, FunctionGenerator itself has DeclarationGenerator as ctor param, which is a part of psi2ir
|
||||
(it can be instantiated here, but I don't know how good is that idea)
|
||||
*/
|
||||
|
||||
fun IrBuilderWithScope.generateAnySuperConstructorCall(toBuilder: IrBlockBodyBuilder) {
|
||||
val anyConstructor = compilerContext.builtIns.any.constructors.single()
|
||||
with(toBuilder) {
|
||||
+IrDelegatingConstructorCallImpl(
|
||||
startOffset, endOffset,
|
||||
compilerContext.irBuiltIns.unitType,
|
||||
compilerContext.symbolTable.referenceConstructor(anyConstructor),
|
||||
anyConstructor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateSimplePropertyWithBackingField(
|
||||
ownerSymbol: IrValueSymbol,
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
propertyParent: IrClass
|
||||
): IrProperty {
|
||||
val irProperty = IrPropertyImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
SERIALIZABLE_PLUGIN_ORIGIN, false,
|
||||
propertyDescriptor
|
||||
)
|
||||
irProperty.parent = propertyParent
|
||||
irProperty.backingField = generatePropertyBackingField(propertyDescriptor).apply { parent = propertyParent }
|
||||
val fieldSymbol = irProperty.backingField!!.symbol
|
||||
irProperty.getter = propertyDescriptor.getter?.let { generatePropertyAccessor(it, fieldSymbol, ownerSymbol) }
|
||||
?.apply { parent = propertyParent }
|
||||
irProperty.setter = propertyDescriptor.setter?.let { generatePropertyAccessor(it, fieldSymbol, ownerSymbol) }
|
||||
?.apply { parent = propertyParent }
|
||||
return irProperty
|
||||
}
|
||||
|
||||
fun generatePropertyBackingField(propertyDescriptor: PropertyDescriptor): IrField {
|
||||
return compilerContext.symbolTable.declareField(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
SERIALIZABLE_PLUGIN_ORIGIN,
|
||||
propertyDescriptor,
|
||||
propertyDescriptor.type.toIrType()
|
||||
)
|
||||
}
|
||||
|
||||
fun generatePropertyAccessor(
|
||||
descriptor: PropertyAccessorDescriptor,
|
||||
fieldSymbol: IrFieldSymbol,
|
||||
ownerSymbol: IrValueSymbol
|
||||
): IrSimpleFunction {
|
||||
return compilerContext.symbolTable.declareSimpleFunctionWithOverrides(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
SERIALIZABLE_PLUGIN_ORIGIN, descriptor
|
||||
).buildWithScope { irAccessor ->
|
||||
irAccessor.createParameterDeclarations((ownerSymbol as IrValueParameterSymbol).owner) // todo: neat this
|
||||
irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType()
|
||||
irAccessor.body = when (descriptor) {
|
||||
is PropertyGetterDescriptor -> generateDefaultGetterBody(descriptor, irAccessor, ownerSymbol)
|
||||
is PropertySetterDescriptor -> generateDefaultSetterBody(descriptor, irAccessor, ownerSymbol)
|
||||
else -> throw AssertionError("Should be getter or setter: $descriptor")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun generateDefaultGetterBody(
|
||||
getter: PropertyGetterDescriptor,
|
||||
irAccessor: IrSimpleFunction,
|
||||
ownerSymbol: IrValueSymbol
|
||||
): IrBlockBody {
|
||||
val property = getter.correspondingProperty
|
||||
|
||||
val irBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
||||
|
||||
val receiver = generateReceiverExpressionForFieldAccess(ownerSymbol, property)
|
||||
|
||||
irBody.statements.add(
|
||||
IrReturnImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, compilerContext.irBuiltIns.nothingType,
|
||||
irAccessor.symbol,
|
||||
IrGetFieldImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
compilerContext.symbolTable.referenceField(property),
|
||||
property.type.toIrType(),
|
||||
receiver
|
||||
)
|
||||
)
|
||||
)
|
||||
return irBody
|
||||
}
|
||||
|
||||
private fun generateDefaultSetterBody(
|
||||
setter: PropertySetterDescriptor,
|
||||
irAccessor: IrSimpleFunction,
|
||||
ownerSymbol: IrValueSymbol
|
||||
): IrBlockBody {
|
||||
val property = setter.correspondingProperty
|
||||
|
||||
val startOffset = UNDEFINED_OFFSET
|
||||
val endOffset = UNDEFINED_OFFSET
|
||||
val irBody = IrBlockBodyImpl(startOffset, endOffset)
|
||||
|
||||
val receiver = generateReceiverExpressionForFieldAccess(ownerSymbol, property)
|
||||
|
||||
val irValueParameter = irAccessor.valueParameters.single()
|
||||
irBody.statements.add(
|
||||
IrSetFieldImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
compilerContext.symbolTable.referenceField(property),
|
||||
receiver,
|
||||
IrGetValueImpl(startOffset, endOffset, irValueParameter.type, irValueParameter.symbol),
|
||||
compilerContext.irBuiltIns.unitType
|
||||
)
|
||||
)
|
||||
return irBody
|
||||
}
|
||||
|
||||
fun generateReceiverExpressionForFieldAccess(
|
||||
ownerSymbol: IrValueSymbol,
|
||||
property: PropertyDescriptor
|
||||
): IrExpression {
|
||||
val containingDeclaration = property.containingDeclaration
|
||||
return when (containingDeclaration) {
|
||||
is ClassDescriptor ->
|
||||
IrGetValueImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
// symbolTable.referenceValue(containingDeclaration.thisAsReceiverParameter)
|
||||
ownerSymbol
|
||||
)
|
||||
else -> throw AssertionError("Property must be in class")
|
||||
}
|
||||
}
|
||||
|
||||
// todo: delet zis
|
||||
fun IrFunction.createParameterDeclarations(receiver: IrValueParameter? = null) {
|
||||
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
SERIALIZABLE_PLUGIN_ORIGIN,
|
||||
this,
|
||||
type.toIrType(),
|
||||
(this as? ValueParameterDescriptor)?.varargElementType?.toIrType()
|
||||
).also {
|
||||
it.parent = this@createParameterDeclarations
|
||||
}
|
||||
|
||||
dispatchReceiverParameter = receiver ?: (descriptor.dispatchReceiverParameter?.irValueParameter())
|
||||
extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter()
|
||||
|
||||
assert(valueParameters.isEmpty())
|
||||
descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() }
|
||||
|
||||
assert(typeParameters.isEmpty())
|
||||
descriptor.typeParameters.mapTo(typeParameters) {
|
||||
IrTypeParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
SERIALIZABLE_PLUGIN_ORIGIN,
|
||||
it
|
||||
).also { typeParameter ->
|
||||
typeParameter.parent = this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.util.TypeTranslator
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
|
||||
|
||||
class SerializableCompanionIrGenerator(
|
||||
val irClass: IrClass,
|
||||
override val compilerContext: BackendContext,
|
||||
bindingContext: BindingContext
|
||||
) : SerializableCompanionCodegen(irClass.descriptor), IrBuilderExtension {
|
||||
override val translator: TypeTranslator = TypeTranslator(compilerContext.symbolTable)
|
||||
|
||||
companion object {
|
||||
fun generate(irClass: IrClass,
|
||||
context: BackendContext,
|
||||
bindingContext: BindingContext) {
|
||||
val companionDescriptor = irClass.descriptor
|
||||
val serializableClass = getSerializableClassDescriptorByCompanion(companionDescriptor) ?: return
|
||||
if (serializableClass.isInternalSerializable)
|
||||
SerializableCompanionIrGenerator(irClass, context, bindingContext).generate()
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) = irClass.contributeFunction(methodDescriptor) { getter ->
|
||||
val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
|
||||
val expr = if (serializer.kind == ClassKind.OBJECT) {
|
||||
irGetObject(serializer)
|
||||
} else {
|
||||
val ctor = compilerContext.symbolTable.referenceConstructor(serializer.unsubstitutedPrimaryConstructor!!)
|
||||
val args: List<IrExpression> = emptyList() // todo
|
||||
irInvoke(null, ctor, *args.toTypedArray())
|
||||
}
|
||||
+irReturn(expr)
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.util.TypeTranslator
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getClassFromSerializationPackage
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
|
||||
|
||||
class SerializableIrGenerator(
|
||||
val irClass: IrClass,
|
||||
override val compilerContext: BackendContext,
|
||||
bindingContext: BindingContext
|
||||
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
|
||||
override val translator: TypeTranslator = TypeTranslator(compilerContext.symbolTable)
|
||||
|
||||
|
||||
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) =
|
||||
irClass.contributeConstructor(constructorDescriptor) { ctor ->
|
||||
val original = irClass.constructors.singleOrNull { it.isPrimary } ?: throw IllegalStateException("Serializable class must have single primary constructor")
|
||||
// default arguments of original constructor
|
||||
val defaultsMap: Map<ParameterDescriptor, IrExpression?> = original.valueParameters.associate { it.descriptor to it.defaultValue?.expression }
|
||||
|
||||
fun transformFieldInitializer(f: IrField): IrExpression? {
|
||||
val i = f.initializer?.expression ?: return null
|
||||
return if (i is IrGetValueImpl && i.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER) {
|
||||
// this is a primary constructor property, use corresponding default of value parameter
|
||||
defaultsMap.getValue(i.descriptor as ParameterDescriptor)
|
||||
} else {
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
// Missing field exception parts
|
||||
val exceptionCtor =
|
||||
serializableDescriptor.getClassFromSerializationPackage("MissingFieldException")
|
||||
.unsubstitutedPrimaryConstructor!!
|
||||
val exceptionCtorRef = compilerContext.symbolTable.referenceConstructor(exceptionCtor)
|
||||
val exceptionType = exceptionCtor.returnType.toIrType()
|
||||
|
||||
val thiz = irClass.thisReceiver!!
|
||||
if (KotlinBuiltIns.isAny(irClass.descriptor.getSuperClassOrAny()))
|
||||
generateAnySuperConstructorCall(toBuilder = this@contributeConstructor)
|
||||
else
|
||||
TODO("Serializable classes with inheritance")
|
||||
val seenVar = ctor.valueParameters[0]
|
||||
|
||||
for ((index, prop) in properties.serializableProperties.withIndex()) {
|
||||
val paramRef = ctor.valueParameters[index + 1]
|
||||
// assign this.a = a in else branch
|
||||
val assignParamExpr = irSetField(irGet(thiz), prop.irField, irGet(paramRef))
|
||||
|
||||
val ifNotSeenExpr: IrExpression = if (prop.optional) {
|
||||
val initializerBody =
|
||||
requireNotNull(transformFieldInitializer(prop.irField)) { "Optional value without an initializer" } // todo: filter abstract here
|
||||
irSetField(irGet(thiz), prop.irField, initializerBody)
|
||||
} else {
|
||||
irThrow(irInvoke(null, exceptionCtorRef, irString(prop.name), typeHint = exceptionType))
|
||||
}
|
||||
|
||||
val propNotSeenTest =
|
||||
irEquals(
|
||||
irInt(0),
|
||||
irBinOp(OperatorNameConventions.AND, irGet(seenVar), irInt(1 shl (index % 32)))
|
||||
)
|
||||
|
||||
+irIfThenElse(compilerContext.irBuiltIns.unitType, propNotSeenTest, ifNotSeenExpr, assignParamExpr)
|
||||
}
|
||||
|
||||
// todo: transient initializers and init blocks
|
||||
// remaining initalizers of variables
|
||||
// val serialDescs = properties.serializableProperties.map { it.descriptor }.toSet()
|
||||
// irClass.declarations.asSequence()
|
||||
// .filterIsInstance<IrProperty>()
|
||||
// .filter { it.descriptor !in serialDescs }
|
||||
// .filter { it.backingField != null }
|
||||
// .mapNotNull { prop -> prop.backingField!!.initializer?.let { prop to it.expression } }
|
||||
// .forEach { (prop, expr) -> +irSetField(irGet(thiz), prop.backingField!!, expr) }
|
||||
}
|
||||
|
||||
override fun generateWriteSelfMethod(methodDescriptor: FunctionDescriptor) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun generate(
|
||||
irClass: IrClass,
|
||||
context: BackendContext,
|
||||
bindingContext: BindingContext
|
||||
) {
|
||||
if (irClass.descriptor.isInternalSerializable)
|
||||
SerializableIrGenerator(irClass, context, bindingContext).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
+378
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
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.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.mapValueParameters
|
||||
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.TypeTranslator
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.withScope
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
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.*
|
||||
|
||||
// Is creating synthetic origin is a good idea or not?
|
||||
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER")
|
||||
|
||||
class SerializerIrGenerator(val irClass: IrClass, override val compilerContext: BackendContext, bindingContext: BindingContext) :
|
||||
SerializerCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
|
||||
|
||||
override val translator: TypeTranslator = TypeTranslator(compilerContext.symbolTable)
|
||||
|
||||
override fun generateSerialDesc() {
|
||||
val desc: PropertyDescriptor = serialDescPropertyDescriptor ?: return
|
||||
val serialDescImplClass = serializerDescriptor
|
||||
.getClassFromInternalSerializationPackage("SerialClassDescImpl")
|
||||
val serialDescImplConstructor = serialDescImplClass
|
||||
.unsubstitutedPrimaryConstructor!!
|
||||
|
||||
val addFuncS = serialDescImplClass.referenceMethod("addElement")
|
||||
|
||||
val thisAsReceiverParameter = irClass.thisReceiver!!
|
||||
lateinit var prop: IrProperty
|
||||
|
||||
// how to (auto)create backing field and getter/setter?
|
||||
compilerContext.symbolTable.withScope(irClass.descriptor) {
|
||||
|
||||
introduceValueParameter(thisAsReceiverParameter)
|
||||
prop = generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, desc, irClass)
|
||||
irClass.addMember(prop)
|
||||
}
|
||||
|
||||
compilerContext.symbolTable.declareAnonymousInitializer(
|
||||
irClass.startOffset, irClass.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irClass.descriptor
|
||||
).buildWithScope { initIrBody ->
|
||||
val ctor = irClass.declarations.filterIsInstance<IrConstructor>().singleOrNull()
|
||||
val serialClassDescImplCtor = compilerContext.symbolTable.referenceConstructor(serialDescImplConstructor)
|
||||
compilerContext.symbolTable.withScope(initIrBody.descriptor) {
|
||||
initIrBody.body = compilerContext.createIrBuilder(initIrBody.symbol).irBlockBody {
|
||||
val localDesc = irTemporary(
|
||||
irCall(
|
||||
serialClassDescImplCtor,
|
||||
type = serialDescImplConstructor.returnType.toIrType()
|
||||
).mapValueParameters { irString(serialName) },
|
||||
nameHint = "serialDesc"
|
||||
)
|
||||
|
||||
fun addFieldCall(fieldName: String) =
|
||||
irCall(addFuncS, type = compilerContext.irBuiltIns.unitType).apply {
|
||||
dispatchReceiver = irGet(localDesc)
|
||||
}.mapValueParameters { irString(fieldName) }
|
||||
|
||||
for (classProp in orderedProperties) {
|
||||
if (classProp.transient) continue
|
||||
+addFieldCall(classProp.name)
|
||||
// serialDesc.pushAnnotation(...) todo
|
||||
}
|
||||
|
||||
+irSetField(
|
||||
generateReceiverExpressionForFieldAccess(
|
||||
thisAsReceiverParameter.symbol,
|
||||
serialDescPropertyDescriptor
|
||||
),
|
||||
prop.backingField!!,
|
||||
irGet(localDesc)
|
||||
)
|
||||
}
|
||||
// workaround for KT-25353
|
||||
// irClass.addMember(initIrBody)
|
||||
(ctor?.body as? IrBlockBody)?.statements?.addAll(initIrBody.body.statements)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor) {
|
||||
// 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.
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.serializerInstance(
|
||||
serializerClass: ClassDescriptor?,
|
||||
module: ModuleDescriptor,
|
||||
kType: KotlinType,
|
||||
genericIndex: Int? = null
|
||||
): IrExpression? {
|
||||
val nullableSerClass =
|
||||
compilerContext.symbolTable.referenceClass(module.getClassFromInternalSerializationPackage("NullableSerializer"))
|
||||
if (serializerClass == null) {
|
||||
if (genericIndex == null) return null
|
||||
return 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)
|
||||
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)
|
||||
args = TODO("reference array serializer")
|
||||
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
|
||||
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
|
||||
KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
|
||||
.let { compilerContext.symbolTable.referenceConstructor(it) }
|
||||
} else {
|
||||
compilerContext.symbolTable.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!)
|
||||
}
|
||||
return irInvoke(
|
||||
null,
|
||||
ctor,
|
||||
*args.toTypedArray()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun ClassDescriptor.referenceMethod(methodName: String) =
|
||||
getFuncDesc(methodName).single().let { compilerContext.symbolTable.referenceFunction(it) }
|
||||
|
||||
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
|
||||
|
||||
fun irThis(): IrExpression =
|
||||
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
|
||||
|
||||
val kOutputClass = serializerDescriptor.getClassFromSerializationPackage("StructureEncoder")
|
||||
|
||||
val descriptorGetterSymbol = compilerContext.symbolTable.referenceFunction(serialDescPropertyDescriptor?.getter!!)
|
||||
|
||||
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
|
||||
|
||||
// fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder
|
||||
val beginFunc = kOutputClass.referenceMethod("beginStructure") // todo: retrieve from actual encoder instead
|
||||
|
||||
val call = irCall(beginFunc).mapValueParametersIndexed { i, parameterDescriptor ->
|
||||
if (i == 0) irGet(localSerialDesc) else IrVarargImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
parameterDescriptor.type.toIrType(),
|
||||
parameterDescriptor.varargElementType!!.toIrType()
|
||||
)
|
||||
}
|
||||
// can it be done in more concise way? e.g. additional builder function?
|
||||
call.dispatchReceiver = irGet(saveFunc.valueParameters[0])
|
||||
val serialObjectSymbol = saveFunc.valueParameters[1]
|
||||
val localOutput = irTemporary(call, "output")
|
||||
|
||||
// internal serialization via virtual calls?
|
||||
val labeledProperties = orderedProperties.filter { !it.transient }
|
||||
for (index in labeledProperties.indices) {
|
||||
val property = labeledProperties[index]
|
||||
if (property.transient) continue
|
||||
// output.writeXxxElementValue(classDesc, index, value)
|
||||
val sti = getSerialTypeInfo(property)
|
||||
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
|
||||
if (innerSerial == null) {
|
||||
val writeFunc =
|
||||
kOutputClass.referenceMethod("encode${sti.elementMethodPrefix}ElementValue")
|
||||
+irInvoke(
|
||||
irGet(localOutput),
|
||||
writeFunc,
|
||||
irGet(localSerialDesc),
|
||||
irInt(index),
|
||||
// todo: direct field access?
|
||||
// irInvoke(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceFunction(property.descriptor.getter!!))
|
||||
irGetField(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceField(property.descriptor).owner)
|
||||
)
|
||||
} else {
|
||||
val writeFunc = kOutputClass.referenceMethod("encode${sti.elementMethodPrefix}SerializableElementValue")
|
||||
+irInvoke(
|
||||
irGet(localOutput),
|
||||
writeFunc,
|
||||
irGet(localSerialDesc),
|
||||
irInt(index),
|
||||
innerSerial,
|
||||
// todo: direct field access?
|
||||
// irInvoke(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceFunction(property.descriptor.getter!!))
|
||||
irGetField(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceField(property.descriptor).owner)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// output.writeEnd(serialClassDesc)
|
||||
val wEndFunc = kOutputClass.referenceMethod("endStructure")
|
||||
+irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc))
|
||||
}
|
||||
|
||||
// returns null: Any? for boxed types and 0: <number type> for primitives
|
||||
fun IrBuilderWithScope.defaultValueAndType(prop: SerializableProperty): Pair<IrExpression, KotlinType> {
|
||||
val kType = prop.descriptor.returnType!!
|
||||
val T = kType.toIrType()
|
||||
val defaultPrimitive: IrExpression? = when {
|
||||
T.isInt() -> IrConstImpl.int(startOffset, endOffset, T, 0)
|
||||
T.isBoolean() -> IrConstImpl.boolean(startOffset, endOffset, T, false)
|
||||
T.isLong() -> IrConstImpl.long(startOffset, endOffset, T, 0)
|
||||
T.isDouble() -> IrConstImpl.double(startOffset, endOffset, T, 0.0)
|
||||
T.isFloat() -> IrConstImpl.float(startOffset, endOffset, T, 0.0f)
|
||||
T.isChar() -> IrConstImpl.char(startOffset, endOffset, T, 0.toChar())
|
||||
T.isByte() -> IrConstImpl.byte(startOffset, endOffset, T, 0)
|
||||
T.isShort() -> IrConstImpl.short(startOffset, endOffset, T, 0)
|
||||
else -> null
|
||||
}
|
||||
return if (defaultPrimitive == null)
|
||||
irNull() to (compilerContext.builtIns.nullableAnyType)
|
||||
else
|
||||
defaultPrimitive to kType
|
||||
}
|
||||
|
||||
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc ->
|
||||
fun irThis(): IrExpression =
|
||||
IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol)
|
||||
|
||||
fun IrVariable.get() = irGet(this)
|
||||
|
||||
val inputClass = serializerDescriptor.getClassFromSerializationPackage("StructureDecoder")
|
||||
val descriptorGetterSymbol = compilerContext.symbolTable.referenceFunction(serialDescPropertyDescriptor?.getter!!)
|
||||
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
|
||||
|
||||
// workaround due to unavailability of labels (KT-25386)
|
||||
val flagVar = irTemporaryVar(irBoolean(true), "flag", parent = loadFunc)
|
||||
|
||||
val indexVar = irTemporaryVar(irInt(0), "index", parent = loadFunc)
|
||||
// val readAll = irTemporaryVar(irBoolean(false), "readAll", parent = loadFunc)
|
||||
//
|
||||
// calculating bit mask vars
|
||||
val blocksCnt = orderedProperties.size / 32 + 1
|
||||
|
||||
// var bitMask0 = 0, bitMask1 = 0...
|
||||
val bitMasks = (0 until blocksCnt).map { irTemporaryVar(irInt(0), "bitMask$it", parent = loadFunc) }
|
||||
// var local0 = null, local1 = null ...
|
||||
val localProps = orderedProperties.mapIndexed { i, prop ->
|
||||
val (expr, type) = defaultValueAndType(prop)
|
||||
irTemporaryVar(
|
||||
expr,
|
||||
"local$i",
|
||||
typeHint = type,
|
||||
parent = loadFunc
|
||||
)
|
||||
}
|
||||
|
||||
//input = input.beginStructure(...)
|
||||
val beginFunc = inputClass.referenceMethod("beginStructure")
|
||||
val call = irInvoke(
|
||||
irGet(loadFunc.valueParameters[0]),
|
||||
beginFunc,
|
||||
irGet(localSerialDesc),
|
||||
irEmptyVararg(beginFunc.descriptor.valueParameters[1])
|
||||
)
|
||||
val localInput = irTemporary(call, "input")
|
||||
|
||||
+irWhile().also { loop ->
|
||||
loop.condition = flagVar.get()
|
||||
loop.body = irBlock {
|
||||
val readElementF = inputClass.referenceMethod("decodeElement")
|
||||
+irSetVar(indexVar.symbol, irInvoke(localInput.get(), readElementF, localSerialDesc.get()))
|
||||
+irWhen {
|
||||
// if index == -2 (READ_ALL) todo...
|
||||
+IrBranchImpl(irEquals(indexVar.get(), irInt(-2)), irThrowNpe())
|
||||
|
||||
// if index == -1 (READ_DONE) break loop
|
||||
+IrBranchImpl(irEquals(indexVar.get(), irInt(-1)), irSetVar(flagVar.symbol, irBoolean(false)))
|
||||
|
||||
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)
|
||||
// todo: update
|
||||
val decodeFuncToCall =
|
||||
(if (innerSerial != null) "decode${sti.elementMethodPrefix}SerializableElementValue"
|
||||
else "decode${sti.elementMethodPrefix}ElementValue")
|
||||
.let {
|
||||
inputClass.referenceMethod(it)
|
||||
}
|
||||
val args = mutableListOf<IrExpression>(localSerialDesc.get(), irInt(index))
|
||||
if (innerSerial != null)
|
||||
args.add(innerSerial)
|
||||
// local$i = localInput.decode...(...)
|
||||
+irSetVar(localProps[index].symbol, irInvoke(localInput.get(), decodeFuncToCall, *args.toTypedArray()))
|
||||
// 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
|
||||
}
|
||||
branchBodies.forEach { (i, e) -> +IrBranchImpl(irEquals(indexVar.get(), irInt(i)), e) }
|
||||
|
||||
// throw exception on unknown field
|
||||
val exceptionCtor =
|
||||
serializableDescriptor.getClassFromSerializationPackage("UnknownFieldException")
|
||||
.unsubstitutedPrimaryConstructor!!
|
||||
val excClassRef = compilerContext.symbolTable.referenceConstructor(exceptionCtor)
|
||||
+elseBranch(
|
||||
irThrow(
|
||||
irInvoke(
|
||||
null,
|
||||
excClassRef,
|
||||
indexVar.get(),
|
||||
typeHint = exceptionCtor.returnType.toIrType()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//input.endStructure(...)
|
||||
val endFunc = inputClass.referenceMethod("endStructure")
|
||||
+irInvoke(
|
||||
localInput.get(),
|
||||
endFunc,
|
||||
irGet(localSerialDesc)
|
||||
)
|
||||
|
||||
// todo: set properties in external deserialization
|
||||
var args: List<IrExpression> = localProps.map { it.get() }
|
||||
val ctor: IrConstructorSymbol = if (serializableDescriptor.isInternalSerializable) {
|
||||
val ctorDesc = compilerContext.symbolTable.referenceClass(serializableDescriptor)
|
||||
.owner.constructors.single { it.origin == SERIALIZABLE_PLUGIN_ORIGIN }
|
||||
args = listOf(irGet(bitMasks[0])) + args + irNull()
|
||||
ctorDesc.symbol
|
||||
} else {
|
||||
compilerContext.symbolTable.referenceConstructor(serializableDescriptor.unsubstitutedPrimaryConstructor!!)
|
||||
}
|
||||
|
||||
+irReturn(irInvoke(null, ctor, *args.toTypedArray()))
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun generate(
|
||||
irClass: IrClass,
|
||||
context: BackendContext,
|
||||
bindingContext: BindingContext
|
||||
) {
|
||||
if (getSerializableClassDescriptorBySerializer(irClass.descriptor) != null)
|
||||
SerializerIrGenerator(irClass, context, bindingContext).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -29,9 +29,11 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
class SerializableCompanionJsTranslator(declaration: KtPureClassOrObject,
|
||||
val translator: DeclarationBodyVisitor,
|
||||
val context: TranslationContext): SerializableCompanionCodegen(declaration, context.bindingContext()) {
|
||||
class SerializableCompanionJsTranslator(
|
||||
declaration: ClassDescriptor,
|
||||
val translator: DeclarationBodyVisitor,
|
||||
val context: TranslationContext): SerializableCompanionCodegen(declaration) {
|
||||
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
val f = context.buildFunction(methodDescriptor) {jsFun, context ->
|
||||
val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
|
||||
@@ -52,7 +54,7 @@ class SerializableCompanionJsTranslator(declaration: KtPureClassOrObject,
|
||||
fun translate(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) {
|
||||
val serializableClass = getSerializableClassDescriptorByCompanion(descriptor) ?: return
|
||||
if (serializableClass.isInternalSerializable)
|
||||
SerializableCompanionJsTranslator(declaration, translator, context).generate()
|
||||
SerializableCompanionJsTranslator(descriptor, translator, context).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -37,9 +37,10 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializab
|
||||
|
||||
class SerializableJsTranslator(
|
||||
val declaration: KtPureClassOrObject,
|
||||
val descriptor: ClassDescriptor,
|
||||
val translator: DeclarationBodyVisitor,
|
||||
val context: TranslationContext
|
||||
) : SerializableCodegen(declaration, context.bindingContext()) {
|
||||
) : SerializableCodegen(descriptor, context.bindingContext()) {
|
||||
|
||||
private val initMap: Map<PropertyDescriptor, KtExpression?> = declaration.run {
|
||||
(bodyPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.delegateExpressionOrInitializer } +
|
||||
@@ -109,7 +110,7 @@ class SerializableJsTranslator(
|
||||
context: TranslationContext
|
||||
) {
|
||||
if (descriptor.isInternalSerializable)
|
||||
SerializableJsTranslator(declaration, translator, context).generate()
|
||||
SerializableJsTranslator(declaration, descriptor, translator, context).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -119,13 +119,10 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
||||
context.addDeclarationStatement(f.makeStmt())
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.getFuncDesc(funcName: String) =
|
||||
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }
|
||||
|
||||
override fun generateSave(function: FunctionDescriptor) = generateFunction(function) { jsFun, ctx ->
|
||||
val kOutputClass = serializerDescriptor.getClassFromSerializationPackage("StructureEncoder")
|
||||
val wBeginFunc = ctx.getNameForDescriptor(
|
||||
kOutputClass.getFuncDesc("beginStructure").single { (it as FunctionDescriptor).valueParameters.size == 2 })
|
||||
kOutputClass.getFuncDesc("beginStructure").single { it.valueParameters.size == 2 })
|
||||
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(serialDescPropertyDescriptor!!), JsThisRef())
|
||||
|
||||
// output.writeBegin(desc, [])
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
class SerializableCodegenImpl(
|
||||
private val classCodegen: ImplementationBodyCodegen,
|
||||
serializableClass: ClassDescriptor
|
||||
) : SerializableCodegen(classCodegen.myClass, classCodegen.bindingContext) {
|
||||
) : SerializableCodegen(classCodegen.descriptor, classCodegen.bindingContext) {
|
||||
|
||||
private val thisAsmType = classCodegen.typeMapper.mapClass(serializableDescriptor)
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableC
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCodegen) :
|
||||
SerializableCompanionCodegen(codegen.myClass, codegen.bindingContext) {
|
||||
SerializableCompanionCodegen(codegen.descriptor) {
|
||||
|
||||
companion object {
|
||||
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
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.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.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
|
||||
|
||||
/**
|
||||
* Copy of [runOnFilePostfix], but this implementation first lowers declaration, then its children.
|
||||
*/
|
||||
fun ClassLoweringPass.runOnFileInOrder(irFile: IrFile) {
|
||||
irFile.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
lower(declaration)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private class SerializerClassLowering(
|
||||
val context: BackendContext,
|
||||
val bindingContext: BindingContext
|
||||
) :
|
||||
IrElementTransformerVoid(), ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
SerializableIrGenerator.generate(irClass, context, bindingContext)
|
||||
SerializerIrGenerator.generate(irClass, context, bindingContext)
|
||||
SerializableCompanionIrGenerator.generate(irClass, context, bindingContext)
|
||||
}
|
||||
}
|
||||
|
||||
class SerializationLoweringExtension : IrGenerationExtension {
|
||||
override fun generate(
|
||||
file: IrFile,
|
||||
backendContext: BackendContext,
|
||||
bindingContext: BindingContext
|
||||
) {
|
||||
SerializerClassLowering(backendContext, bindingContext).runOnFileInOrder(file)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -280,7 +280,7 @@ object KSerializerDescriptorResolver {
|
||||
fun createTypedSerializerConstructorDescriptor(
|
||||
classDescriptor: ClassDescriptor,
|
||||
serializableDescriptor: ClassDescriptor
|
||||
): ConstructorDescriptor {
|
||||
): ClassConstructorDescriptor {
|
||||
val constrDesc = ClassConstructorDescriptorImpl.createSynthesized(
|
||||
classDescriptor,
|
||||
Annotations.EMPTY,
|
||||
|
||||
Reference in New Issue
Block a user