Optimize check for missing fields in deserialization (#3862)
Fixes Kotlin/kotlinx.serialization#662 Kotlin/kotlinx.serialization#657
This commit is contained in:
+41
@@ -16,11 +16,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.ApiVersion
|
||||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors
|
import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.VersionReader
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
|
|
||||||
abstract class SerializableCodegen(
|
abstract class SerializableCodegen(
|
||||||
@@ -28,6 +31,10 @@ abstract class SerializableCodegen(
|
|||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
) : AbstractSerialGenerator(bindingContext, serializableDescriptor) {
|
) : AbstractSerialGenerator(bindingContext, serializableDescriptor) {
|
||||||
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor)
|
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor)
|
||||||
|
protected val staticDescriptor = serializableDescriptor.declaredTypeParameters.isEmpty()
|
||||||
|
|
||||||
|
private val fieldMissingOptimizationVersion = ApiVersion.parse("1.1")!!
|
||||||
|
protected val useFieldMissingOptimization = canUseFieldMissingOptimization()
|
||||||
|
|
||||||
fun generate() {
|
fun generate() {
|
||||||
generateSyntheticInternalConstructor()
|
generateSyntheticInternalConstructor()
|
||||||
@@ -50,6 +57,40 @@ abstract class SerializableCodegen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun getGoldenMask(): Int {
|
||||||
|
var goldenMask = 0
|
||||||
|
var requiredBit = 1
|
||||||
|
for (property in properties.serializableProperties) {
|
||||||
|
if (!property.optional) {
|
||||||
|
goldenMask = goldenMask or requiredBit
|
||||||
|
}
|
||||||
|
requiredBit = requiredBit shl 1
|
||||||
|
}
|
||||||
|
return goldenMask
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun getGoldenMaskList(): List<Int> {
|
||||||
|
val maskSlotCount = properties.serializableProperties.bitMaskSlotCount()
|
||||||
|
val goldenMaskList = MutableList(maskSlotCount) { 0 }
|
||||||
|
|
||||||
|
for (i in properties.serializableProperties.indices) {
|
||||||
|
if (!properties.serializableProperties[i].optional) {
|
||||||
|
val slotNumber = i / 32
|
||||||
|
val bitInSlot = i % 32
|
||||||
|
goldenMaskList[slotNumber] = goldenMaskList[slotNumber] or (1 shl bitInSlot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return goldenMaskList
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun canUseFieldMissingOptimization(): Boolean {
|
||||||
|
val implementationVersion = VersionReader.getVersionsForCurrentModuleFromContext(
|
||||||
|
serializableDescriptor.module,
|
||||||
|
bindingContext
|
||||||
|
)?.implementationVersion
|
||||||
|
return if (implementationVersion != null) implementationVersion >= fieldMissingOptimizationVersion else false
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor)
|
protected abstract fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor)
|
||||||
|
|
||||||
protected open fun generateWriteSelfMethod(methodDescriptor: FunctionDescriptor) {
|
protected open fun generateWriteSelfMethod(methodDescriptor: FunctionDescriptor) {
|
||||||
|
|||||||
+39
-1
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
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.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
@@ -67,6 +68,30 @@ interface IrBuilderExtension {
|
|||||||
) { bodyGen(c) }
|
) { bodyGen(c) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// function will not be created in the real class
|
||||||
|
fun IrClass.createInlinedFunction(
|
||||||
|
name: Name,
|
||||||
|
visibility: DescriptorVisibility,
|
||||||
|
origin: IrDeclarationOrigin,
|
||||||
|
returnType: IrType,
|
||||||
|
bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit
|
||||||
|
): IrSimpleFunction {
|
||||||
|
val function = factory.buildFun {
|
||||||
|
this.name = name
|
||||||
|
this.visibility = visibility
|
||||||
|
this.origin = origin
|
||||||
|
this.isInline = true
|
||||||
|
this.returnType = returnType
|
||||||
|
}
|
||||||
|
val functionSymbol = function.symbol
|
||||||
|
function.parent = this
|
||||||
|
function.body = DeclarationIrBuilder(compilerContext, functionSymbol, startOffset, endOffset).irBlockBody(
|
||||||
|
startOffset,
|
||||||
|
endOffset
|
||||||
|
) { bodyGen(function) }
|
||||||
|
return function
|
||||||
|
}
|
||||||
|
|
||||||
fun IrBuilderWithScope.irInvoke(
|
fun IrBuilderWithScope.irInvoke(
|
||||||
dispatchReceiver: IrExpression? = null,
|
dispatchReceiver: IrExpression? = null,
|
||||||
callee: IrFunctionSymbol,
|
callee: IrFunctionSymbol,
|
||||||
@@ -109,6 +134,19 @@ interface IrBuilderExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.createPrimitiveArrayOfExpression(
|
||||||
|
elementPrimitiveType: IrType,
|
||||||
|
arrayElements: List<IrExpression>
|
||||||
|
): IrExpression {
|
||||||
|
val arrayType = compilerContext.irBuiltIns.primitiveArrayForType.getValue(elementPrimitiveType).defaultType
|
||||||
|
val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, elementPrimitiveType, arrayElements)
|
||||||
|
val typeArguments = listOf(elementPrimitiveType)
|
||||||
|
|
||||||
|
return irCall(compilerContext.symbols.arrayOf, arrayType, typeArguments = typeArguments).apply {
|
||||||
|
putValueArgument(0, arg0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression {
|
fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression {
|
||||||
val classFqName = (lhs.type as IrSimpleType).classOrNull!!.owner.fqNameWhenAvailable!!
|
val classFqName = (lhs.type as IrSimpleType).classOrNull!!.owner.fqNameWhenAvailable!!
|
||||||
val symbol = compilerContext.referenceFunctions(classFqName.child(name)).single()
|
val symbol = compilerContext.referenceFunctions(classFqName.child(name)).single()
|
||||||
@@ -766,4 +804,4 @@ interface IrBuilderExtension {
|
|||||||
return superClasses.singleOrNull { it.kind == ClassKind.CLASS }
|
return superClasses.singleOrNull { it.kind == ClassKind.CLASS }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -68,7 +68,7 @@ class SerialInfoImplJvmIrGenerator(
|
|||||||
generateSimplePropertyWithBackingField(property.descriptor, irClass, Name.identifier("_" + property.name.asString()))
|
generateSimplePropertyWithBackingField(property.descriptor, irClass, Name.identifier("_" + property.name.asString()))
|
||||||
|
|
||||||
val getter = property.getter!!
|
val getter = property.getter!!
|
||||||
getter.origin = SERIALIZABLE_SYNTHETIC_ORIGIN
|
getter.origin = SERIALIZABLE_PLUGIN_ORIGIN
|
||||||
// Add JvmName annotation to property getters to force the resulting JVM method name for 'x' be 'x', instead of 'getX',
|
// Add JvmName annotation to property getters to force the resulting JVM method name for 'x' be 'x', instead of 'getX',
|
||||||
// and to avoid having useless bridges for it generated in BridgeLowering.
|
// and to avoid having useless bridges for it generated in BridgeLowering.
|
||||||
// Unfortunately, this results in an extra `@JvmName` annotation in the bytecode, but it shouldn't matter very much.
|
// Unfortunately, this results in an extra `@JvmName` annotation in the bytecode, but it shouldn't matter very much.
|
||||||
@@ -76,7 +76,7 @@ class SerialInfoImplJvmIrGenerator(
|
|||||||
|
|
||||||
val field = property.backingField!!
|
val field = property.backingField!!
|
||||||
field.visibility = DescriptorVisibilities.PRIVATE
|
field.visibility = DescriptorVisibilities.PRIVATE
|
||||||
field.origin = SERIALIZABLE_SYNTHETIC_ORIGIN
|
field.origin = SERIALIZABLE_PLUGIN_ORIGIN
|
||||||
|
|
||||||
val parameter = ctor.addValueParameter(property.name.asString(), getter.returnType)
|
val parameter = ctor.addValueParameter(property.name.asString(), getter.returnType)
|
||||||
ctorBody.statements += IrSetFieldImpl(
|
ctorBody.statements += IrSetFieldImpl(
|
||||||
|
|||||||
+185
-7
@@ -8,24 +8,31 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
|||||||
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
|
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
|
||||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||||
import org.jetbrains.kotlin.codegen.CompilationException
|
import org.jetbrains.kotlin.codegen.CompilationException
|
||||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addField
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.getAnnotation
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ARRAY_MASK_FIELD_MISSING_FUNC_FQ
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESC_FIELD
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SINGLE_MASK_FIELD_MISSING_FUNC_FQ
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.initializedDescriptorFieldName
|
||||||
|
|
||||||
class SerializableIrGenerator(
|
class SerializableIrGenerator(
|
||||||
val irClass: IrClass,
|
val irClass: IrClass,
|
||||||
@@ -33,7 +40,20 @@ class SerializableIrGenerator(
|
|||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
|
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
|
||||||
|
|
||||||
|
private val descriptorGenerationFunctionName = "createInitializedDescriptor"
|
||||||
|
|
||||||
|
private val serialDescClass: ClassDescriptor = serializableDescriptor.module
|
||||||
|
.getClassFromSerializationDescriptorsPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS)
|
||||||
|
|
||||||
|
private val serialDescImplClass: ClassDescriptor = serializableDescriptor
|
||||||
|
.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL)
|
||||||
|
|
||||||
|
private val addElementFun = serialDescImplClass.findFunctionSymbol(CallingConventions.addElement)
|
||||||
|
|
||||||
|
val throwMissedFieldExceptionFunc =
|
||||||
|
if (useFieldMissingOptimization) compilerContext.referenceFunctions(SINGLE_MASK_FIELD_MISSING_FUNC_FQ).single() else null
|
||||||
|
val throwMissedFieldExceptionArrayFunc =
|
||||||
|
if (useFieldMissingOptimization) compilerContext.referenceFunctions(ARRAY_MASK_FIELD_MISSING_FUNC_FQ).single() else null
|
||||||
|
|
||||||
private fun IrClass.hasSerializableAnnotationWithoutArgs(): Boolean {
|
private fun IrClass.hasSerializableAnnotationWithoutArgs(): Boolean {
|
||||||
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return false
|
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return false
|
||||||
@@ -64,6 +84,10 @@ class SerializableIrGenerator(
|
|||||||
val thiz = irClass.thisReceiver!!
|
val thiz = irClass.thisReceiver!!
|
||||||
val superClass = irClass.getSuperClassOrAny()
|
val superClass = irClass.getSuperClassOrAny()
|
||||||
var startPropOffset: Int = 0
|
var startPropOffset: Int = 0
|
||||||
|
|
||||||
|
if (useFieldMissingOptimization) {
|
||||||
|
generateOptimizedGoldenMaskCheck(seenVars)
|
||||||
|
}
|
||||||
when {
|
when {
|
||||||
superClass.symbol == compilerContext.irBuiltIns.anyClass -> generateAnySuperConstructorCall(toBuilder = this@contributeConstructor)
|
superClass.symbol == compilerContext.irBuiltIns.anyClass -> generateAnySuperConstructorCall(toBuilder = this@contributeConstructor)
|
||||||
superClass.isInternalSerializable -> {
|
superClass.isInternalSerializable -> {
|
||||||
@@ -83,7 +107,14 @@ class SerializableIrGenerator(
|
|||||||
requireNotNull(transformFieldInitializer(prop.irField)) { "Optional value without an initializer" } // todo: filter abstract here
|
requireNotNull(transformFieldInitializer(prop.irField)) { "Optional value without an initializer" } // todo: filter abstract here
|
||||||
setProperty(irGet(thiz), prop.irProp, initializerBody)
|
setProperty(irGet(thiz), prop.irProp, initializerBody)
|
||||||
} else {
|
} else {
|
||||||
irThrow(irInvoke(null, exceptionCtorRef, irString(prop.name), typeHint = exceptionType))
|
// property required
|
||||||
|
if (useFieldMissingOptimization) {
|
||||||
|
// field definitely not empty as it's checked before - no need another IF, only assign property from param
|
||||||
|
+assignParamExpr
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
irThrow(irInvoke(null, exceptionCtorRef, irString(prop.name), typeHint = exceptionType))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val propNotSeenTest =
|
val propNotSeenTest =
|
||||||
@@ -116,6 +147,153 @@ class SerializableIrGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrBlockBodyBuilder.generateOptimizedGoldenMaskCheck(seenVars: List<IrValueParameter>) {
|
||||||
|
if (serializableDescriptor.isAbstractSerializableClass() || serializableDescriptor.isSealedSerializableClass()) {
|
||||||
|
// for abstract classes fields MUST BE checked in child classes
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val fieldsMissedTest: IrExpression
|
||||||
|
val throwErrorExpr: IrExpression
|
||||||
|
|
||||||
|
val maskSlotCount = seenVars.size
|
||||||
|
if (maskSlotCount == 1) {
|
||||||
|
val goldenMask = getGoldenMask()
|
||||||
|
|
||||||
|
throwErrorExpr = irInvoke(
|
||||||
|
null,
|
||||||
|
throwMissedFieldExceptionFunc!!,
|
||||||
|
irGet(seenVars[0]),
|
||||||
|
irInt(goldenMask),
|
||||||
|
getSerialDescriptorExpr(),
|
||||||
|
typeHint = compilerContext.irBuiltIns.unitType
|
||||||
|
)
|
||||||
|
|
||||||
|
fieldsMissedTest = irNotEquals(
|
||||||
|
irInt(goldenMask),
|
||||||
|
irBinOp(
|
||||||
|
OperatorNameConventions.AND,
|
||||||
|
irInt(goldenMask),
|
||||||
|
irGet(seenVars[0])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val goldenMaskList = getGoldenMaskList()
|
||||||
|
|
||||||
|
var compositeExpression: IrExpression? = null
|
||||||
|
for (i in goldenMaskList.indices) {
|
||||||
|
val singleCheckExpr = irNotEquals(
|
||||||
|
irInt(goldenMaskList[i]),
|
||||||
|
irBinOp(
|
||||||
|
OperatorNameConventions.AND,
|
||||||
|
irInt(goldenMaskList[i]),
|
||||||
|
irGet(seenVars[i])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
compositeExpression = if (compositeExpression == null) {
|
||||||
|
singleCheckExpr
|
||||||
|
} else {
|
||||||
|
irBinOp(
|
||||||
|
OperatorNameConventions.OR,
|
||||||
|
compositeExpression,
|
||||||
|
singleCheckExpr
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsMissedTest = compositeExpression!!
|
||||||
|
|
||||||
|
throwErrorExpr = irBlock {
|
||||||
|
+irInvoke(
|
||||||
|
null,
|
||||||
|
throwMissedFieldExceptionArrayFunc!!,
|
||||||
|
createPrimitiveArrayOfExpression(compilerContext.irBuiltIns.intType, goldenMaskList.indices.map { irGet(seenVars[it]) }),
|
||||||
|
createPrimitiveArrayOfExpression(compilerContext.irBuiltIns.intType, goldenMaskList.map { irInt(it) }),
|
||||||
|
getSerialDescriptorExpr(),
|
||||||
|
typeHint = compilerContext.irBuiltIns.unitType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+irIfThen(compilerContext.irBuiltIns.unitType, fieldsMissedTest, throwErrorExpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrBlockBodyBuilder.getSerialDescriptorExpr(): IrExpression {
|
||||||
|
return if (serializableDescriptor.shouldHaveGeneratedSerializer && staticDescriptor) {
|
||||||
|
val serializer = serializableDescriptor.classSerializer!!
|
||||||
|
val serialDescriptorGetter = compilerContext.referenceClass(serializer.fqNameSafe)!!.getPropertyGetter(SERIAL_DESC_FIELD)!!
|
||||||
|
irGet(
|
||||||
|
serialDescriptorGetter.owner.returnType,
|
||||||
|
irGetObject(serializer),
|
||||||
|
serialDescriptorGetter.owner.symbol
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
irGetField(null, generateStaticDescriptorField())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrBlockBodyBuilder.generateStaticDescriptorField(): IrField {
|
||||||
|
val serialDescItType = serialDescClass.defaultType.toIrType()
|
||||||
|
|
||||||
|
val function = irClass.createInlinedFunction(
|
||||||
|
Name.identifier(descriptorGenerationFunctionName),
|
||||||
|
DescriptorVisibilities.PRIVATE,
|
||||||
|
SERIALIZABLE_PLUGIN_ORIGIN,
|
||||||
|
serialDescItType
|
||||||
|
) {
|
||||||
|
val serialDescVar = irTemporary(
|
||||||
|
getInstantiateDescriptorExpr(),
|
||||||
|
nameHint = "serialDesc"
|
||||||
|
)
|
||||||
|
for (property in properties.serializableProperties) {
|
||||||
|
+getAddElementToDescriptorExpr(property, serialDescVar)
|
||||||
|
}
|
||||||
|
+irReturn(irGet(serialDescVar))
|
||||||
|
}
|
||||||
|
|
||||||
|
return irClass.addField {
|
||||||
|
name = Name.identifier(initializedDescriptorFieldName)
|
||||||
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
|
origin = SERIALIZABLE_PLUGIN_ORIGIN
|
||||||
|
isFinal = true
|
||||||
|
isStatic = true
|
||||||
|
type = serialDescItType
|
||||||
|
}.apply { initializer = irClass.factory.createExpressionBody(irCall(function)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrBlockBodyBuilder.getInstantiateDescriptorExpr(): IrExpression {
|
||||||
|
val classConstructors = compilerContext.referenceConstructors(serialDescImplClass.fqNameSafe)
|
||||||
|
val serialClassDescImplCtor = classConstructors.single { it.owner.isPrimary }
|
||||||
|
return irInvoke(
|
||||||
|
null, serialClassDescImplCtor,
|
||||||
|
irString(serializableDescriptor.serialName()), irNull(), irInt(properties.serializableProperties.size)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrBlockBodyBuilder.getAddElementToDescriptorExpr(
|
||||||
|
property: SerializableProperty,
|
||||||
|
serialDescVar: IrVariable
|
||||||
|
): IrExpression {
|
||||||
|
return irInvoke(
|
||||||
|
irGet(serialDescVar),
|
||||||
|
addElementFun,
|
||||||
|
irString(property.name),
|
||||||
|
irBoolean(property.optional),
|
||||||
|
typeHint = compilerContext.irBuiltIns.unitType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun ClassDescriptor.findFunctionSymbol(
|
||||||
|
functionName: String,
|
||||||
|
predicate: (IrSimpleFunction) -> Boolean = { true }
|
||||||
|
): IrFunctionSymbol {
|
||||||
|
val irClass = compilerContext.referenceClass(fqNameSafe)?.owner ?: error("Couldn't load class $this")
|
||||||
|
val simpleFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>()
|
||||||
|
|
||||||
|
return simpleFunctions.filter { it.name.asString() == functionName }.single { predicate(it) }.symbol
|
||||||
|
}
|
||||||
|
|
||||||
private fun IrBlockBodyBuilder.generateSuperNonSerializableCall(superClass: IrClass) {
|
private fun IrBlockBodyBuilder.generateSuperNonSerializableCall(superClass: IrClass) {
|
||||||
val ctorRef = superClass.declarations.filterIsInstance<IrConstructor>().singleOrNull { it.valueParameters.isEmpty() }
|
val ctorRef = superClass.declarations.filterIsInstance<IrConstructor>().singleOrNull { it.valueParameters.isEmpty() }
|
||||||
?: error("Non-serializable parent of serializable $serializableDescriptor must have no arg constructor")
|
?: error("Non-serializable parent of serializable $serializableDescriptor must have no arg constructor")
|
||||||
@@ -189,4 +367,4 @@ class SerializableIrGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-4
@@ -37,10 +37,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ST
|
|||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_ENCODER_CLASS
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_ENCODER_CLASS
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UNKNOWN_FIELD_EXC
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UNKNOWN_FIELD_EXC
|
||||||
|
|
||||||
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER")
|
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER", true)
|
||||||
|
|
||||||
// TODO: use in places where elements need to have ACC_SYNTHETIC on JVM
|
|
||||||
object SERIALIZABLE_SYNTHETIC_ORIGIN : IrDeclarationOriginImpl("SERIALIZER")
|
|
||||||
|
|
||||||
open class SerializerIrGenerator(
|
open class SerializerIrGenerator(
|
||||||
val irClass: IrClass,
|
val irClass: IrClass,
|
||||||
|
|||||||
+7
-1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -25,10 +26,12 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DE
|
|||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.KSERIALIZER_CLASS
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.KSERIALIZER_CLASS
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.PLUGIN_EXCEPTIONS_FILE
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_CTOR_MARKER_NAME
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_CTOR_MARKER_NAME
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_FOR_ENUM
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_FOR_ENUM
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESC_FIELD
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_EXC
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_EXC
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_LOADER_CLASS
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_LOADER_CLASS
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_SAVER_CLASS
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_SAVER_CLASS
|
||||||
@@ -50,7 +53,7 @@ internal val kOutputType = Type.getObjectType("kotlinx/serialization/encoding/$S
|
|||||||
internal val encoderType = Type.getObjectType("kotlinx/serialization/encoding/$ENCODER_CLASS")
|
internal val encoderType = Type.getObjectType("kotlinx/serialization/encoding/$ENCODER_CLASS")
|
||||||
internal val decoderType = Type.getObjectType("kotlinx/serialization/encoding/$DECODER_CLASS")
|
internal val decoderType = Type.getObjectType("kotlinx/serialization/encoding/$DECODER_CLASS")
|
||||||
internal val kInputType = Type.getObjectType("kotlinx/serialization/encoding/$STRUCTURE_DECODER_CLASS")
|
internal val kInputType = Type.getObjectType("kotlinx/serialization/encoding/$STRUCTURE_DECODER_CLASS")
|
||||||
|
internal val pluginUtilsType = Type.getObjectType("kotlinx/serialization/internal/${PLUGIN_EXCEPTIONS_FILE}Kt")
|
||||||
|
|
||||||
internal val kSerialSaverType = Type.getObjectType("kotlinx/serialization/$SERIAL_SAVER_CLASS")
|
internal val kSerialSaverType = Type.getObjectType("kotlinx/serialization/$SERIAL_SAVER_CLASS")
|
||||||
internal val kSerialLoaderType = Type.getObjectType("kotlinx/serialization/$SERIAL_LOADER_CLASS")
|
internal val kSerialLoaderType = Type.getObjectType("kotlinx/serialization/$SERIAL_LOADER_CLASS")
|
||||||
@@ -61,6 +64,9 @@ internal val serializationExceptionName = "kotlinx/serialization/$SERIAL_EXC"
|
|||||||
internal val serializationExceptionMissingFieldName = "kotlinx/serialization/$MISSING_FIELD_EXC"
|
internal val serializationExceptionMissingFieldName = "kotlinx/serialization/$MISSING_FIELD_EXC"
|
||||||
internal val serializationExceptionUnknownIndexName = "kotlinx/serialization/$UNKNOWN_FIELD_EXC"
|
internal val serializationExceptionUnknownIndexName = "kotlinx/serialization/$UNKNOWN_FIELD_EXC"
|
||||||
|
|
||||||
|
internal val descriptorGetterName = JvmAbi.getterName(SERIAL_DESC_FIELD)
|
||||||
|
|
||||||
|
|
||||||
val OPT_MASK_TYPE: Type = Type.INT_TYPE
|
val OPT_MASK_TYPE: Type = Type.INT_TYPE
|
||||||
val OPT_MASK_BITS = 32
|
val OPT_MASK_BITS = 32
|
||||||
|
|
||||||
|
|||||||
+125
-12
@@ -28,10 +28,15 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ARRAY_MASK_FIELD_MISSING_FUNC_NAME
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SINGLE_MASK_FIELD_MISSING_FUNC_NAME
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.initializedDescriptorFieldName
|
||||||
import org.jetbrains.org.objectweb.asm.Label
|
import org.jetbrains.org.objectweb.asm.Label
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
@@ -179,20 +184,28 @@ class SerializableCodegenImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) {
|
private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) {
|
||||||
val seenMask = 1
|
val seenMaskVar = 1
|
||||||
val bitMaskOff = fun(it: Int): Int { return seenMask + bitMaskSlotAt(it) }
|
val bitMaskOff = fun(it: Int): Int { return seenMaskVar + bitMaskSlotAt(it) }
|
||||||
val bitMaskEnd = seenMask + properties.serializableProperties.bitMaskSlotCount()
|
val bitMaskEnd = seenMaskVar + properties.serializableProperties.bitMaskSlotCount()
|
||||||
var (propIndex, propOffset) = generateSuperSerializableCall(bitMaskEnd)
|
|
||||||
|
if (useFieldMissingOptimization) {
|
||||||
|
generateOptimizedGoldenMaskCheck(seenMaskVar)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (propIndex, propOffset) = generateSuperSerializableCall(seenMaskVar, bitMaskEnd)
|
||||||
for (i in propIndex until properties.serializableProperties.size) {
|
for (i in propIndex until properties.serializableProperties.size) {
|
||||||
val prop = properties[i]
|
val prop = properties[i]
|
||||||
val propType = prop.asmType
|
val propType = prop.asmType
|
||||||
if (!prop.optional) {
|
if (!prop.optional) {
|
||||||
// primary were validated before constructor call
|
if (!useFieldMissingOptimization) {
|
||||||
genValidateProperty(i, bitMaskOff(i))
|
// primary were validated before constructor call
|
||||||
val nonThrowLabel = Label()
|
genValidateProperty(i, bitMaskOff(i))
|
||||||
ificmpne(nonThrowLabel)
|
val nonThrowLabel = Label()
|
||||||
genMissingFieldExceptionThrow(prop.name)
|
ificmpne(nonThrowLabel)
|
||||||
visitLabel(nonThrowLabel)
|
genMissingFieldExceptionThrow(prop.name)
|
||||||
|
visitLabel(nonThrowLabel)
|
||||||
|
}
|
||||||
|
|
||||||
// setting field
|
// setting field
|
||||||
load(0, thisAsmType)
|
load(0, thisAsmType)
|
||||||
load(propOffset, propType)
|
load(propOffset, propType)
|
||||||
@@ -237,7 +250,7 @@ class SerializableCodegenImpl(
|
|||||||
areturn(Type.VOID_TYPE)
|
areturn(Type.VOID_TYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun InstructionAdapter.generateSuperSerializableCall(propStartVar: Int): Pair<Int, Int> {
|
private fun InstructionAdapter.generateSuperSerializableCall(maskVar: Int, propStartVar: Int): Pair<Int, Int> {
|
||||||
val superClass = serializableDescriptor.getSuperClassOrAny()
|
val superClass = serializableDescriptor.getSuperClassOrAny()
|
||||||
val superType = classCodegen.typeMapper.mapType(superClass).internalName
|
val superType = classCodegen.typeMapper.mapType(superClass).internalName
|
||||||
|
|
||||||
@@ -261,12 +274,112 @@ class SerializableCodegenImpl(
|
|||||||
return 0 to propStartVar
|
return 0 to propStartVar
|
||||||
} else {
|
} else {
|
||||||
val superProps = bindingContext.serializablePropertiesFor(superClass).serializableProperties
|
val superProps = bindingContext.serializablePropertiesFor(superClass).serializableProperties
|
||||||
val creator = buildInternalConstructorDesc(propStartVar, 1, classCodegen, superProps)
|
val creator = buildInternalConstructorDesc(propStartVar, maskVar, classCodegen, superProps)
|
||||||
invokespecial(superType, "<init>", creator, false)
|
invokespecial(superType, "<init>", creator, false)
|
||||||
return superProps.size to propStartVar + superProps.sumBy { it.asmType.size }
|
return superProps.size to propStartVar + superProps.sumBy { it.asmType.size }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun InstructionAdapter.generateOptimizedGoldenMaskCheck(maskVar: Int) {
|
||||||
|
if (serializableDescriptor.isAbstractSerializableClass() || serializableDescriptor.isSealedSerializableClass()) {
|
||||||
|
// for abstract classes fields MUST BE checked in child classes
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val allPresentsLabel = Label()
|
||||||
|
val maskSlotCount = properties.serializableProperties.bitMaskSlotCount()
|
||||||
|
if (maskSlotCount == 1) {
|
||||||
|
val goldenMask = getGoldenMask()
|
||||||
|
|
||||||
|
iconst(goldenMask)
|
||||||
|
dup()
|
||||||
|
load(maskVar, OPT_MASK_TYPE)
|
||||||
|
and(OPT_MASK_TYPE)
|
||||||
|
ificmpeq(allPresentsLabel)
|
||||||
|
|
||||||
|
load(maskVar, OPT_MASK_TYPE)
|
||||||
|
iconst(goldenMask)
|
||||||
|
|
||||||
|
stackSerialDescriptor()
|
||||||
|
invokestatic(
|
||||||
|
pluginUtilsType.internalName,
|
||||||
|
SINGLE_MASK_FIELD_MISSING_FUNC_NAME.asString(),
|
||||||
|
"(II${descType.descriptor})V",
|
||||||
|
false
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val fieldsMissingLabel = Label()
|
||||||
|
|
||||||
|
val goldenMaskList = getGoldenMaskList()
|
||||||
|
goldenMaskList.forEachIndexed { i, goldenMask ->
|
||||||
|
val maskIndex = maskVar + i
|
||||||
|
// if( (goldenMask & seen) != goldenMask )
|
||||||
|
iconst(goldenMask)
|
||||||
|
dup()
|
||||||
|
load(maskIndex, OPT_MASK_TYPE)
|
||||||
|
and(OPT_MASK_TYPE)
|
||||||
|
ificmpne(fieldsMissingLabel)
|
||||||
|
}
|
||||||
|
goTo(allPresentsLabel)
|
||||||
|
|
||||||
|
visitLabel(fieldsMissingLabel)
|
||||||
|
// prepare seen array
|
||||||
|
fillArray(OPT_MASK_TYPE, goldenMaskList) { i, _ ->
|
||||||
|
load(maskVar + i, OPT_MASK_TYPE)
|
||||||
|
}
|
||||||
|
// prepare golden mask array
|
||||||
|
fillArray(OPT_MASK_TYPE, goldenMaskList) { _, goldenMask ->
|
||||||
|
iconst(goldenMask)
|
||||||
|
}
|
||||||
|
stackSerialDescriptor()
|
||||||
|
invokestatic(
|
||||||
|
pluginUtilsType.internalName,
|
||||||
|
ARRAY_MASK_FIELD_MISSING_FUNC_NAME.asString(),
|
||||||
|
"([I[I${descType.descriptor})V",
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
visitLabel(allPresentsLabel)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun InstructionAdapter.stackSerialDescriptor() {
|
||||||
|
if (serializableDescriptor.shouldHaveGeneratedSerializer && staticDescriptor) {
|
||||||
|
val serializer = serializableDescriptor.classSerializer!!
|
||||||
|
StackValue.singleton(serializer, classCodegen.typeMapper).put(kSerializerType, this)
|
||||||
|
invokeinterface(kSerializerType.internalName, descriptorGetterName, "()${descType.descriptor}")
|
||||||
|
} else {
|
||||||
|
generateStaticDescriptorField()
|
||||||
|
|
||||||
|
getstatic(thisAsmType.internalName, initializedDescriptorFieldName, descType.descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateStaticDescriptorField() {
|
||||||
|
val flags = Opcodes.ACC_PRIVATE or Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC or Opcodes.ACC_STATIC
|
||||||
|
classCodegen.v.newField(
|
||||||
|
OtherOrigin(classCodegen.myClass.psiOrParent), flags,
|
||||||
|
initializedDescriptorFieldName, descType.descriptor, null, null
|
||||||
|
)
|
||||||
|
|
||||||
|
val clInit = classCodegen.createOrGetClInitCodegen()
|
||||||
|
with(clInit.v) {
|
||||||
|
anew(descImplType)
|
||||||
|
dup()
|
||||||
|
aconst(serializableDescriptor.serialName())
|
||||||
|
aconst(null)
|
||||||
|
aconst(properties.serializableProperties.size)
|
||||||
|
invokespecial(descImplType.internalName, "<init>", "(Ljava/lang/String;${generatedSerializerType.descriptor}I)V", false)
|
||||||
|
for (property in properties.serializableProperties) {
|
||||||
|
dup()
|
||||||
|
aconst(property.name)
|
||||||
|
iconst(if (property.optional) 1 else 0)
|
||||||
|
invokevirtual(descImplType.internalName, CallingConventions.addElement, "(Ljava/lang/String;Z)V", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
putstatic(thisAsmType.internalName, initializedDescriptorFieldName, descType.descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun ExpressionCodegen.genInitProperty(prop: SerializableProperty) = getProp(prop)?.let {
|
private fun ExpressionCodegen.genInitProperty(prop: SerializableProperty) = getProp(prop)?.let {
|
||||||
classCodegen.initializeProperty(this, it)
|
classCodegen.initializeProperty(this, it)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.config.ApiVersion
|
|||||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
import org.jetbrains.kotlin.util.slicedMap.Slices
|
import org.jetbrains.kotlin.util.slicedMap.Slices
|
||||||
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
|
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
|
||||||
@@ -50,6 +51,11 @@ object VersionReader {
|
|||||||
return versions
|
return versions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getVersionsForCurrentModuleFromContext(module: ModuleDescriptor, context: BindingContext): RuntimeVersions? {
|
||||||
|
context.get(VERSIONS_SLICE, module)?.let { return it }
|
||||||
|
return getVersionsForCurrentModule(module)
|
||||||
|
}
|
||||||
|
|
||||||
fun getVersionsForCurrentModule(module: ModuleDescriptor): RuntimeVersions? {
|
fun getVersionsForCurrentModule(module: ModuleDescriptor): RuntimeVersions? {
|
||||||
val markerClass = module.getClassFromSerializationPackage(SerialEntityNames.KSERIALIZER_CLASS)
|
val markerClass = module.getClassFromSerializationPackage(SerialEntityNames.KSERIALIZER_CLASS)
|
||||||
val location = (markerClass.source as? KotlinJvmBinarySourceElement)?.binaryClass?.location ?: return null
|
val location = (markerClass.source as? KotlinJvmBinarySourceElement)?.binaryClass?.location ?: return null
|
||||||
@@ -59,4 +65,4 @@ object VersionReader {
|
|||||||
if (!file.exists()) return null
|
if (!file.exists()) return null
|
||||||
return getVersionsFromManifest(file)
|
return getVersionsFromManifest(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -44,6 +44,8 @@ object SerialEntityNames {
|
|||||||
const val LOAD = "deserialize"
|
const val LOAD = "deserialize"
|
||||||
const val SERIALIZER_CLASS = "\$serializer"
|
const val SERIALIZER_CLASS = "\$serializer"
|
||||||
|
|
||||||
|
const val initializedDescriptorFieldName = "\$initializedDescriptor"
|
||||||
|
|
||||||
// classes
|
// classes
|
||||||
val KSERIALIZER_NAME = Name.identifier(KSERIALIZER_CLASS)
|
val KSERIALIZER_NAME = Name.identifier(KSERIALIZER_CLASS)
|
||||||
val SERIAL_CTOR_MARKER_NAME = Name.identifier("SerializationConstructorMarker")
|
val SERIAL_CTOR_MARKER_NAME = Name.identifier("SerializationConstructorMarker")
|
||||||
@@ -68,6 +70,8 @@ object SerialEntityNames {
|
|||||||
const val SERIAL_DESCRIPTOR_CLASS_IMPL = "PluginGeneratedSerialDescriptor"
|
const val SERIAL_DESCRIPTOR_CLASS_IMPL = "PluginGeneratedSerialDescriptor"
|
||||||
const val SERIAL_DESCRIPTOR_FOR_ENUM = "EnumDescriptor"
|
const val SERIAL_DESCRIPTOR_FOR_ENUM = "EnumDescriptor"
|
||||||
|
|
||||||
|
const val PLUGIN_EXCEPTIONS_FILE = "PluginExceptions"
|
||||||
|
|
||||||
//exceptions
|
//exceptions
|
||||||
const val SERIAL_EXC = "SerializationException"
|
const val SERIAL_EXC = "SerializationException"
|
||||||
const val MISSING_FIELD_EXC = "MissingFieldException"
|
const val MISSING_FIELD_EXC = "MissingFieldException"
|
||||||
@@ -81,6 +85,10 @@ object SerialEntityNames {
|
|||||||
val TYPE_PARAMS_SERIALIZERS_GETTER = Name.identifier("typeParametersSerializers")
|
val TYPE_PARAMS_SERIALIZERS_GETTER = Name.identifier("typeParametersSerializers")
|
||||||
val WRITE_SELF_NAME = Name.identifier("write\$Self")
|
val WRITE_SELF_NAME = Name.identifier("write\$Self")
|
||||||
val SERIALIZER_PROVIDER_NAME = Name.identifier("serializer")
|
val SERIALIZER_PROVIDER_NAME = Name.identifier("serializer")
|
||||||
|
val SINGLE_MASK_FIELD_MISSING_FUNC_NAME = Name.identifier("throwMissingFieldException")
|
||||||
|
val ARRAY_MASK_FIELD_MISSING_FUNC_NAME = Name.identifier("throwArrayMissingFieldException")
|
||||||
|
val SINGLE_MASK_FIELD_MISSING_FUNC_FQ = SerializationPackages.internalPackageFqName.child(SINGLE_MASK_FIELD_MISSING_FUNC_NAME)
|
||||||
|
val ARRAY_MASK_FIELD_MISSING_FUNC_FQ = SerializationPackages.internalPackageFqName.child(ARRAY_MASK_FIELD_MISSING_FUNC_NAME)
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
val dummyParamName = Name.identifier("serializationConstructorMarker")
|
val dummyParamName = Name.identifier("serializationConstructorMarker")
|
||||||
|
|||||||
+10
@@ -82,6 +82,16 @@ internal fun ModuleDescriptor.getClassFromInternalSerializationPackage(classSimp
|
|||||||
)
|
)
|
||||||
) { "Can't locate class $classSimpleName from package ${SerializationPackages.internalPackageFqName}" }
|
) { "Can't locate class $classSimpleName from package ${SerializationPackages.internalPackageFqName}" }
|
||||||
|
|
||||||
|
internal fun ModuleDescriptor.getClassFromSerializationDescriptorsPackage(classSimpleName: String) =
|
||||||
|
requireNotNull(
|
||||||
|
findClassAcrossModuleDependencies(
|
||||||
|
ClassId(
|
||||||
|
SerializationPackages.descriptorsPackageFqName,
|
||||||
|
Name.identifier(classSimpleName)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) { "Can't locate class $classSimpleName from package ${SerializationPackages.descriptorsPackageFqName}" }
|
||||||
|
|
||||||
internal fun getSerializationPackageFqn(classSimpleName: String): FqName =
|
internal fun getSerializationPackageFqn(classSimpleName: String): FqName =
|
||||||
SerializationPackages.packageFqName.child(Name.identifier(classSimpleName))
|
SerializationPackages.packageFqName.child(Name.identifier(classSimpleName))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user