Support classes with more than 32 serializable properties
Via increasing count of int bit masks in synthetic constructor
This commit is contained in:
+1
-1
@@ -33,7 +33,7 @@ abstract class SerializerCodegen(
|
|||||||
val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
|
val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
|
||||||
protected val serialName: String = serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString()
|
protected val serialName: String = serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString()
|
||||||
protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
|
protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
|
||||||
protected val orderedProperties = properties.serializableProperties
|
protected val serializableProperties = properties.serializableProperties
|
||||||
|
|
||||||
private fun checkSerializability() {
|
private fun checkSerializability() {
|
||||||
check(properties.isExternallySerializable) {
|
check(properties.isExternallySerializable) {
|
||||||
|
|||||||
+9
-7
@@ -19,11 +19,8 @@ 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.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.resolve.*
|
||||||
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.getClassFromSerializationPackage
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.hasCompanionObjectAsSerializer
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.hasSerializableAnnotationWithoutArgs
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
|
|
||||||
|
|
||||||
class SerializableIrGenerator(
|
class SerializableIrGenerator(
|
||||||
val irClass: IrClass,
|
val irClass: IrClass,
|
||||||
@@ -51,10 +48,11 @@ class SerializableIrGenerator(
|
|||||||
generateAnySuperConstructorCall(toBuilder = this@contributeConstructor)
|
generateAnySuperConstructorCall(toBuilder = this@contributeConstructor)
|
||||||
else
|
else
|
||||||
TODO("Serializable classes with inheritance")
|
TODO("Serializable classes with inheritance")
|
||||||
val seenVar = ctor.valueParameters[0]
|
val seenVarsOffset = properties.serializableProperties.bitMaskSlotCount()
|
||||||
|
val seenVars = (0 until seenVarsOffset).map { ctor.valueParameters[it] }
|
||||||
|
|
||||||
for ((index, prop) in properties.serializableProperties.withIndex()) {
|
for ((index, prop) in properties.serializableProperties.withIndex()) {
|
||||||
val paramRef = ctor.valueParameters[index + 1]
|
val paramRef = ctor.valueParameters[index + seenVarsOffset]
|
||||||
// assign this.a = a in else branch
|
// assign this.a = a in else branch
|
||||||
val assignParamExpr = irSetField(irGet(thiz), prop.irField, irGet(paramRef))
|
val assignParamExpr = irSetField(irGet(thiz), prop.irField, irGet(paramRef))
|
||||||
|
|
||||||
@@ -69,7 +67,11 @@ class SerializableIrGenerator(
|
|||||||
val propNotSeenTest =
|
val propNotSeenTest =
|
||||||
irEquals(
|
irEquals(
|
||||||
irInt(0),
|
irInt(0),
|
||||||
irBinOp(OperatorNameConventions.AND, irGet(seenVar), irInt(1 shl (index % 32)))
|
irBinOp(
|
||||||
|
OperatorNameConventions.AND,
|
||||||
|
irGet(seenVars[bitMaskSlotAt(index)]),
|
||||||
|
irInt(1 shl (index % 32))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
+irIfThenElse(compilerContext.irBuiltIns.unitType, propNotSeenTest, ifNotSeenExpr, assignParamExpr)
|
+irIfThenElse(compilerContext.irBuiltIns.unitType, propNotSeenTest, ifNotSeenExpr, assignParamExpr)
|
||||||
|
|||||||
+8
-8
@@ -95,7 +95,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
|||||||
dispatchReceiver = irGet(localDesc)
|
dispatchReceiver = irGet(localDesc)
|
||||||
}.mapValueParameters { irString(fieldName) }
|
}.mapValueParameters { irString(fieldName) }
|
||||||
|
|
||||||
for (classProp in orderedProperties) {
|
for (classProp in serializableProperties) {
|
||||||
if (classProp.transient) continue
|
if (classProp.transient) continue
|
||||||
+addFieldCall(classProp.name)
|
+addFieldCall(classProp.name)
|
||||||
// add property annotations
|
// add property annotations
|
||||||
@@ -163,7 +163,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun ->
|
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun ->
|
||||||
val allSerializers = orderedProperties.map { requireNotNull(
|
val allSerializers = serializableProperties.map { requireNotNull(
|
||||||
serializerTower(this@SerializerIrGenerator, it)) { "Property ${it.name} must have a serializer" }
|
serializerTower(this@SerializerIrGenerator, it)) { "Property ${it.name} must have a serializer" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
|||||||
fun SerializableProperty.irGet(): IrGetField = irGetField(irGet(serialObjectSymbol), irField)
|
fun SerializableProperty.irGet(): IrGetField = irGetField(irGet(serialObjectSymbol), irField)
|
||||||
|
|
||||||
// internal serialization via virtual calls?
|
// internal serialization via virtual calls?
|
||||||
for ((index, property) in orderedProperties.filter { !it.transient }.withIndex()) {
|
for ((index, property) in serializableProperties.filter { !it.transient }.withIndex()) {
|
||||||
// output.writeXxxElementValue(classDesc, index, value)
|
// output.writeXxxElementValue(classDesc, index, value)
|
||||||
val sti = getSerialTypeInfo(property)
|
val sti = getSerialTypeInfo(property)
|
||||||
val innerSerial = serializerInstance(
|
val innerSerial = serializerInstance(
|
||||||
@@ -252,7 +252,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
|||||||
// if (obj.prop != DEFAULT_VALUE || output.shouldEncodeElementDefault(this.descriptor, i))
|
// if (obj.prop != DEFAULT_VALUE || output.shouldEncodeElementDefault(this.descriptor, i))
|
||||||
// output.encodeIntElement(this.descriptor, i, obj.prop)
|
// output.encodeIntElement(this.descriptor, i, obj.prop)
|
||||||
val shouldEncodeFunc = kOutputClass.referenceMethod(CallingConventions.shouldEncodeDefault)
|
val shouldEncodeFunc = kOutputClass.referenceMethod(CallingConventions.shouldEncodeDefault)
|
||||||
val partA = irNotEquals(property.irGet(), fieldInitializer(property)!!) // todo: props w/o backing fields
|
val partA = irNotEquals(property.irGet(), fieldInitializer(property)!!)
|
||||||
val partB = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index))
|
val partB = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index))
|
||||||
// Ir infrastructure does not have dedicated symbol for ||, so
|
// Ir infrastructure does not have dedicated symbol for ||, so
|
||||||
// `a || b == if (a) true else b`, see org.jetbrains.kotlin.ir.builders.PrimitivesKt.oror
|
// `a || b == if (a) true else b`, see org.jetbrains.kotlin.ir.builders.PrimitivesKt.oror
|
||||||
@@ -305,12 +305,12 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
|||||||
// val readAll = irTemporaryVar(irBoolean(false), "readAll", parent = loadFunc)
|
// val readAll = irTemporaryVar(irBoolean(false), "readAll", parent = loadFunc)
|
||||||
//
|
//
|
||||||
// calculating bit mask vars
|
// calculating bit mask vars
|
||||||
val blocksCnt = orderedProperties.size / 32 + 1
|
val blocksCnt = serializableProperties.bitMaskSlotCount()
|
||||||
|
|
||||||
// var bitMask0 = 0, bitMask1 = 0...
|
// var bitMask0 = 0, bitMask1 = 0...
|
||||||
val bitMasks = (0 until blocksCnt).map { irTemporaryVar(irInt(0), "bitMask$it") }
|
val bitMasks = (0 until blocksCnt).map { irTemporaryVar(irInt(0), "bitMask$it") }
|
||||||
// var local0 = null, local1 = null ...
|
// var local0 = null, local1 = null ...
|
||||||
val localProps = orderedProperties.mapIndexed { i, prop ->
|
val localProps = serializableProperties.mapIndexed { i, prop ->
|
||||||
val (expr, type) = defaultValueAndType(prop)
|
val (expr, type) = defaultValueAndType(prop)
|
||||||
irTemporaryVar(
|
irTemporaryVar(
|
||||||
expr,
|
expr,
|
||||||
@@ -341,7 +341,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
|||||||
// if index == -1 (READ_DONE) break loop
|
// if index == -1 (READ_DONE) break loop
|
||||||
+IrBranchImpl(irEquals(indexVar.get(), irInt(-1)), irSetVar(flagVar.symbol, irBoolean(false)))
|
+IrBranchImpl(irEquals(indexVar.get(), irInt(-1)), irSetVar(flagVar.symbol, irBoolean(false)))
|
||||||
|
|
||||||
val branchBodies: List<Pair<Int, IrExpression>> = orderedProperties.mapIndexed { index, property ->
|
val branchBodies: List<Pair<Int, IrExpression>> = serializableProperties.mapIndexed { index, property ->
|
||||||
val body = irBlock {
|
val body = irBlock {
|
||||||
val sti = getSerialTypeInfo(property)
|
val sti = getSerialTypeInfo(property)
|
||||||
val innerSerial = serializerInstance(this@SerializerIrGenerator, serializableDescriptor, sti.serializer, property.module, property.type, property.genericIndex)
|
val innerSerial = serializerInstance(this@SerializerIrGenerator, serializableDescriptor, sti.serializer, property.module, property.type, property.genericIndex)
|
||||||
@@ -398,7 +398,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
|||||||
val ctor: IrConstructorSymbol = if (serializableDescriptor.isInternalSerializable) {
|
val ctor: IrConstructorSymbol = if (serializableDescriptor.isInternalSerializable) {
|
||||||
val ctorDesc = serializableIrClass
|
val ctorDesc = serializableIrClass
|
||||||
.constructors.single { it.origin == SERIALIZABLE_PLUGIN_ORIGIN }
|
.constructors.single { it.origin == SERIALIZABLE_PLUGIN_ORIGIN }
|
||||||
args = listOf(irGet(bitMasks[0])) + args + irNull()
|
args = bitMasks.map { irGet(it) } + args + irNull()
|
||||||
ctorDesc.symbol
|
ctorDesc.symbol
|
||||||
} else {
|
} else {
|
||||||
compilerContext.externalSymbols.referenceConstructor(serializableDescriptor.unsubstitutedPrimaryConstructor!!)
|
compilerContext.externalSymbols.referenceConstructor(serializableDescriptor.unsubstitutedPrimaryConstructor!!)
|
||||||
|
|||||||
+6
-9
@@ -32,16 +32,12 @@ import org.jetbrains.kotlin.psi.KtExpression
|
|||||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||||
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.anonymousInitializers
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.anonymousInitializers
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
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.getClassFromSerializationPackage
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.hasCompanionObjectAsSerializer
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.hasSerializableAnnotationWithoutArgs
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
|
|
||||||
|
|
||||||
class SerializableJsTranslator(
|
class SerializableJsTranslator(
|
||||||
val declaration: KtPureClassOrObject,
|
val declaration: KtPureClassOrObject,
|
||||||
val descriptor: ClassDescriptor,
|
val descriptor: ClassDescriptor,
|
||||||
val translator: DeclarationBodyVisitor,
|
|
||||||
val context: TranslationContext
|
val context: TranslationContext
|
||||||
) : SerializableCodegen(descriptor, context.bindingContext()) {
|
) : SerializableCodegen(descriptor, context.bindingContext()) {
|
||||||
|
|
||||||
@@ -63,9 +59,10 @@ class SerializableJsTranslator(
|
|||||||
Namer.createObjectWithPrototypeFrom(context.getInnerNameForDescriptor(serializableDescriptor).makeRef())
|
Namer.createObjectWithPrototypeFrom(context.getInnerNameForDescriptor(serializableDescriptor).makeRef())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val seenVar = jsFun.parameters[0].name.makeRef()
|
val seenVarsOffset = properties.serializableProperties.bitMaskSlotCount()
|
||||||
|
val seenVars = (0 until seenVarsOffset).map { jsFun.parameters[it].name.makeRef() }
|
||||||
for ((index, prop) in properties.serializableProperties.withIndex()) {
|
for ((index, prop) in properties.serializableProperties.withIndex()) {
|
||||||
val paramRef = jsFun.parameters[index + 1].name.makeRef()
|
val paramRef = jsFun.parameters[index + seenVarsOffset].name.makeRef()
|
||||||
// assign this.a = a in else branch
|
// assign this.a = a in else branch
|
||||||
val assignParamStmt = TranslationUtils.assignmentToBackingField(context, prop.descriptor, paramRef).makeStmt()
|
val assignParamStmt = TranslationUtils.assignmentToBackingField(context, prop.descriptor, paramRef).makeStmt()
|
||||||
|
|
||||||
@@ -77,7 +74,7 @@ class SerializableJsTranslator(
|
|||||||
JsThrow(JsNew(missingExceptionClassRef, listOf(JsStringLiteral(prop.name))))
|
JsThrow(JsNew(missingExceptionClassRef, listOf(JsStringLiteral(prop.name))))
|
||||||
}
|
}
|
||||||
// (seen & 1 << i == 0) -- not seen
|
// (seen & 1 << i == 0) -- not seen
|
||||||
val notSeenTest = propNotSeenTest(seenVar, index)
|
val notSeenTest = propNotSeenTest(seenVars[bitMaskSlotAt(index)], index)
|
||||||
+JsIf(notSeenTest, ifNotSeenStmt, assignParamStmt)
|
+JsIf(notSeenTest, ifNotSeenStmt, assignParamStmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +108,7 @@ class SerializableJsTranslator(
|
|||||||
context: TranslationContext
|
context: TranslationContext
|
||||||
) {
|
) {
|
||||||
if (serializableClass.isInternalSerializable)
|
if (serializableClass.isInternalSerializable)
|
||||||
SerializableJsTranslator(declaration, serializableClass, translator, context).generate()
|
SerializableJsTranslator(declaration, serializableClass, context).generate()
|
||||||
else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) {
|
else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) {
|
||||||
throw CompilationException(
|
throw CompilationException(
|
||||||
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
|
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
|
||||||
|
|||||||
+33
-23
@@ -72,7 +72,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
val pushClassFunc = serialDescImplClass.getFuncDesc(CallingConventions.addClassAnnotation).single()
|
val pushClassFunc = serialDescImplClass.getFuncDesc(CallingConventions.addClassAnnotation).single()
|
||||||
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(generatedSerialDescPropertyDescriptor), JsThisRef())
|
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(generatedSerialDescPropertyDescriptor), JsThisRef())
|
||||||
|
|
||||||
for (prop in orderedProperties) {
|
for (prop in serializableProperties) {
|
||||||
if (prop.transient) continue
|
if (prop.transient) continue
|
||||||
val call = JsInvocation(
|
val call = JsInvocation(
|
||||||
JsNameRef(context.getNameForDescriptor(addFunc), serialClassDescRef),
|
JsNameRef(context.getNameForDescriptor(addFunc), serialClassDescRef),
|
||||||
@@ -100,7 +100,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun generateChildSerializersGetter(function: FunctionDescriptor) = generateFunction(function) { _, _ ->
|
override fun generateChildSerializersGetter(function: FunctionDescriptor) = generateFunction(function) { _, _ ->
|
||||||
val allSerializers = orderedProperties.map { requireNotNull(serializerTower(it)) { "Property ${it.name} must have a serializer" } }
|
val allSerializers = serializableProperties.map { requireNotNull(serializerTower(it)) { "Property ${it.name} must have a serializer" } }
|
||||||
+JsReturn(JsArrayLiteral(allSerializers))
|
+JsReturn(JsArrayLiteral(allSerializers))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
fun SerializableProperty.jsNameRef() = JsNameRef(ctx.getNameForDescriptor(descriptor), objRef)
|
fun SerializableProperty.jsNameRef() = JsNameRef(ctx.getNameForDescriptor(descriptor), objRef)
|
||||||
|
|
||||||
// todo: internal serialization via virtual calls
|
// todo: internal serialization via virtual calls
|
||||||
val labeledProperties = orderedProperties.filter { !it.transient }
|
val labeledProperties = serializableProperties.filter { !it.transient }
|
||||||
for (index in labeledProperties.indices) {
|
for (index in labeledProperties.indices) {
|
||||||
val property = labeledProperties[index]
|
val property = labeledProperties[index]
|
||||||
if (property.transient) continue
|
if (property.transient) continue
|
||||||
@@ -224,15 +224,15 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
+JsVars(JsVars.JsVar(indexVar.name), JsVars.JsVar(readAllVar.name, JsBooleanLiteral(false)))
|
+JsVars(JsVars.JsVar(indexVar.name), JsVars.JsVar(readAllVar.name, JsBooleanLiteral(false)))
|
||||||
|
|
||||||
// calculating bit mask vars
|
// calculating bit mask vars
|
||||||
val blocksCnt = orderedProperties.size / 32 + 1
|
val blocksCnt = serializableProperties.bitMaskSlotCount()
|
||||||
fun bitMaskOff(i: Int) = i / 32
|
fun bitMaskOff(i: Int) = bitMaskSlotAt(i)
|
||||||
|
|
||||||
// var bitMask0 = 0, bitMask1 = 0...
|
// var bitMask0 = 0, bitMask1 = 0...
|
||||||
val bitMasks = (0 until blocksCnt).map { JsNameRef(jsFun.scope.declareFreshName("bitMask$it")) }
|
val bitMasks = (0 until blocksCnt).map { JsNameRef(jsFun.scope.declareFreshName("bitMask$it")) }
|
||||||
+JsVars(bitMasks.map { JsVars.JsVar(it.name, JsIntLiteral(0)) }, false)
|
+JsVars(bitMasks.map { JsVars.JsVar(it.name, JsIntLiteral(0)) }, false)
|
||||||
|
|
||||||
// var localProp0, localProp1, ...
|
// var localProp0, localProp1, ...
|
||||||
val localProps = orderedProperties.mapIndexed {i, _ -> JsNameRef(jsFun.scope.declareFreshName("local$i")) }
|
val localProps = serializableProperties.mapIndexed { i, _ -> JsNameRef(jsFun.scope.declareFreshName("local$i")) }
|
||||||
+JsVars(localProps.map { JsVars.JsVar(it.name) }, true)
|
+JsVars(localProps.map { JsVars.JsVar(it.name) }, true)
|
||||||
|
|
||||||
//input = input.readBegin(...)
|
//input = input.readBegin(...)
|
||||||
@@ -241,8 +241,10 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
}
|
}
|
||||||
val inputVar = JsNameRef(jsFun.scope.declareFreshName("input"))
|
val inputVar = JsNameRef(jsFun.scope.declareFreshName("input"))
|
||||||
val readBeginF = decoderClass.getFuncDesc(CallingConventions.begin).single()
|
val readBeginF = decoderClass.getFuncDesc(CallingConventions.begin).single()
|
||||||
val readBeginCall = JsInvocation(JsNameRef(context.getNameForDescriptor(readBeginF), JsNameRef(jsFun.parameters[0].name)),
|
val readBeginCall = JsInvocation(
|
||||||
serialClassDescRef, JsArrayLiteral(typeParams))
|
JsNameRef(context.getNameForDescriptor(readBeginF), JsNameRef(jsFun.parameters[0].name)),
|
||||||
|
serialClassDescRef, JsArrayLiteral(typeParams)
|
||||||
|
)
|
||||||
+JsVars(JsVars.JsVar(inputVar.name, readBeginCall))
|
+JsVars(JsVars.JsVar(inputVar.name, readBeginCall))
|
||||||
|
|
||||||
// while(true) {
|
// while(true) {
|
||||||
@@ -265,7 +267,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
).makeStmt()
|
).makeStmt()
|
||||||
}
|
}
|
||||||
// all properties
|
// all properties
|
||||||
for ((i, property) in orderedProperties.withIndex()) {
|
for ((i, property) in serializableProperties.withIndex()) {
|
||||||
case(JsIntLiteral(i)) {
|
case(JsIntLiteral(i)) {
|
||||||
// input.readXxxElementValue
|
// input.readXxxElementValue
|
||||||
val sti = getSerialTypeInfo(property)
|
val sti = getSerialTypeInfo(property)
|
||||||
@@ -278,26 +280,33 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
.single { !unknownSer || (it.valueParameters.size == 3) }
|
.single { !unknownSer || (it.valueParameters.size == 3) }
|
||||||
.let { context.getNameForDescriptor(it) }
|
.let { context.getNameForDescriptor(it) }
|
||||||
val readArgs = mutableListOf(serialClassDescRef, JsIntLiteral(i))
|
val readArgs = mutableListOf(serialClassDescRef, JsIntLiteral(i))
|
||||||
if (unknownSer) readArgs.add(ExpressionVisitor.getObjectKClass(
|
if (unknownSer) readArgs.add(
|
||||||
|
ExpressionVisitor.getObjectKClass(
|
||||||
this@SerializerJsTranslator.context,
|
this@SerializerJsTranslator.context,
|
||||||
property.type.toClassDescriptor!!
|
property.type.toClassDescriptor!!
|
||||||
))
|
)
|
||||||
|
)
|
||||||
JsInvocation(JsNameRef(readFunc, inputVar), readArgs)
|
JsInvocation(JsNameRef(readFunc, inputVar), readArgs)
|
||||||
}
|
} else {
|
||||||
else {
|
val notSeenTest = propNotSeenTest(bitMasks[bitMaskOff(i)], i)
|
||||||
val notSeenTest = propNotSeenTest(bitMasks[i / 32], i)
|
|
||||||
val readFunc =
|
val readFunc =
|
||||||
inputClass.getFuncDesc("${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}").single()
|
inputClass.getFuncDesc("${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
|
||||||
|
.single()
|
||||||
.let { context.getNameForDescriptor(it) }
|
.let { context.getNameForDescriptor(it) }
|
||||||
val updateFunc =
|
val updateFunc =
|
||||||
inputClass.getFuncDesc("${CallingConventions.update}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}").single()
|
inputClass.getFuncDesc("${CallingConventions.update}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
|
||||||
|
.single()
|
||||||
.let { context.getNameForDescriptor(it) }
|
.let { context.getNameForDescriptor(it) }
|
||||||
JsConditional(notSeenTest,
|
JsConditional(
|
||||||
JsInvocation(JsNameRef(readFunc, inputVar),
|
notSeenTest,
|
||||||
|
JsInvocation(
|
||||||
|
JsNameRef(readFunc, inputVar),
|
||||||
serialClassDescRef,
|
serialClassDescRef,
|
||||||
JsIntLiteral(i),
|
JsIntLiteral(i),
|
||||||
innerSerial),
|
innerSerial
|
||||||
JsInvocation(JsNameRef(updateFunc, inputVar),
|
),
|
||||||
|
JsInvocation(
|
||||||
|
JsNameRef(updateFunc, inputVar),
|
||||||
serialClassDescRef,
|
serialClassDescRef,
|
||||||
JsIntLiteral(i),
|
JsIntLiteral(i),
|
||||||
innerSerial,
|
innerSerial,
|
||||||
@@ -328,8 +337,9 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
|
|
||||||
// bitMask[i] |= 1 << x
|
// bitMask[i] |= 1 << x
|
||||||
val bitPos = 1 shl (i % 32)
|
val bitPos = 1 shl (i % 32)
|
||||||
+JsBinaryOperation(JsBinaryOperator.ASG_BIT_OR,
|
+JsBinaryOperation(
|
||||||
bitMasks[i / 32],
|
JsBinaryOperator.ASG_BIT_OR,
|
||||||
|
bitMasks[bitMaskOff(i)],
|
||||||
JsIntLiteral(bitPos)
|
JsIntLiteral(bitPos)
|
||||||
).makeStmt()
|
).makeStmt()
|
||||||
// if (!readAll) break
|
// if (!readAll) break
|
||||||
@@ -361,7 +371,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
// todo: external deserialization with primary constructor and setters calls after resolution of KT-11586
|
// todo: external deserialization with primary constructor and setters calls after resolution of KT-11586
|
||||||
val constrDesc = KSerializerDescriptorResolver.createLoadConstructorDescriptor(serializableDescriptor, context.bindingContext())
|
val constrDesc = KSerializerDescriptorResolver.createLoadConstructorDescriptor(serializableDescriptor, context.bindingContext())
|
||||||
val constrRef = context.getInnerNameForDescriptor(constrDesc).makeRef()
|
val constrRef = context.getInnerNameForDescriptor(constrDesc).makeRef()
|
||||||
val args: MutableList<JsExpression> = mutableListOf(bitMasks[0])
|
val args: MutableList<JsExpression> = bitMasks.toMutableList()
|
||||||
args += localProps
|
args += localProps
|
||||||
args += JsNullLiteral()
|
args += JsNullLiteral()
|
||||||
+JsReturn(JsInvocation(constrRef, args))
|
+JsReturn(JsInvocation(constrRef, args))
|
||||||
|
|||||||
+15
-5
@@ -120,9 +120,17 @@ fun InstructionAdapter.genKOutputMethodCall(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun InstructionAdapter.buildInternalConstructorDesc(propsStartVar: Int, bitMaskBase: Int, codegen: ClassBodyCodegen, args: List<SerializableProperty>): String {
|
internal fun InstructionAdapter.buildInternalConstructorDesc(
|
||||||
val constructorDesc = StringBuilder("(I")
|
propsStartVar: Int,
|
||||||
load(bitMaskBase, OPT_MASK_TYPE)
|
bitMaskBase: Int,
|
||||||
|
codegen: ClassBodyCodegen,
|
||||||
|
args: List<SerializableProperty>
|
||||||
|
): String {
|
||||||
|
val constructorDesc = StringBuilder("(")
|
||||||
|
repeat(args.bitMaskSlotCount()) {
|
||||||
|
constructorDesc.append("I")
|
||||||
|
load(bitMaskBase + it, Type.INT_TYPE)
|
||||||
|
}
|
||||||
var propVar = propsStartVar
|
var propVar = propsStartVar
|
||||||
for (property in args) {
|
for (property in args) {
|
||||||
val propertyType = codegen.typeMapper.mapType(property.type)
|
val propertyType = codegen.typeMapper.mapType(property.type)
|
||||||
@@ -135,8 +143,10 @@ internal fun InstructionAdapter.buildInternalConstructorDesc(propsStartVar: Int,
|
|||||||
return constructorDesc.toString()
|
return constructorDesc.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ImplementationBodyCodegen.generateMethod(function: FunctionDescriptor,
|
internal fun ImplementationBodyCodegen.generateMethod(
|
||||||
block: InstructionAdapter.(JvmMethodSignature, ExpressionCodegen) -> Unit) {
|
function: FunctionDescriptor,
|
||||||
|
block: InstructionAdapter.(JvmMethodSignature, ExpressionCodegen) -> Unit
|
||||||
|
) {
|
||||||
this.functionCodegen.generateMethod(OtherOrigin(this.myClass.psiOrParent, function), function,
|
this.functionCodegen.generateMethod(OtherOrigin(this.myClass.psiOrParent, function), function,
|
||||||
object : FunctionGenerationStrategy.CodegenBased(this.state) {
|
object : FunctionGenerationStrategy.CodegenBased(this.state) {
|
||||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||||
|
|||||||
+6
-5
@@ -178,13 +178,15 @@ class SerializableCodegenImpl(
|
|||||||
|
|
||||||
private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) {
|
private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) {
|
||||||
val seenMask = 1
|
val seenMask = 1
|
||||||
var (propIndex, propOffset) = generateSuperSerializableCall(2)
|
val bitMaskOff = fun(it: Int): Int { return seenMask + bitMaskSlotAt(it) }
|
||||||
|
val bitMaskEnd = seenMask + properties.serializableProperties.bitMaskSlotCount()
|
||||||
|
var (propIndex, propOffset) = generateSuperSerializableCall(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
|
// primary were validated before constructor call
|
||||||
genValidateProperty(i) { seenMask }
|
genValidateProperty(i, bitMaskOff)
|
||||||
val nonThrowLabel = Label()
|
val nonThrowLabel = Label()
|
||||||
ificmpne(nonThrowLabel)
|
ificmpne(nonThrowLabel)
|
||||||
genExceptionThrow(serializationExceptionMissingFieldName, prop.name)
|
genExceptionThrow(serializationExceptionMissingFieldName, prop.name)
|
||||||
@@ -194,12 +196,11 @@ class SerializableCodegenImpl(
|
|||||||
load(propOffset, propType)
|
load(propOffset, propType)
|
||||||
putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
|
putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
|
||||||
} else {
|
} else {
|
||||||
genValidateProperty(i) { seenMask }
|
genValidateProperty(i, bitMaskOff)
|
||||||
val setLbl = Label()
|
val setLbl = Label()
|
||||||
val nextLabel = Label()
|
val nextLabel = Label()
|
||||||
ificmpeq(setLbl)
|
ificmpeq(setLbl)
|
||||||
// setting field
|
// setting field
|
||||||
// todo: validate nullability
|
|
||||||
load(0, thisAsmType)
|
load(0, thisAsmType)
|
||||||
load(propOffset, propType)
|
load(propOffset, propType)
|
||||||
putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
|
putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
|
||||||
@@ -228,7 +229,7 @@ class SerializableCodegenImpl(
|
|||||||
.forEach { (t, u) -> exprCodegen.genInitParam(t, u) }
|
.forEach { (t, u) -> exprCodegen.genInitParam(t, u) }
|
||||||
|
|
||||||
// init blocks
|
// init blocks
|
||||||
// todo: proper order with other initializers
|
// todo: proper order with other initializers?
|
||||||
classCodegen.myClass.anonymousInitializers()
|
classCodegen.myClass.anonymousInitializers()
|
||||||
.forEach { exprCodegen.gen(it, Type.VOID_TYPE) }
|
.forEach { exprCodegen.gen(it, Type.VOID_TYPE) }
|
||||||
areturn(Type.VOID_TYPE)
|
areturn(Type.VOID_TYPE)
|
||||||
|
|||||||
+45
-36
@@ -89,7 +89,7 @@ class SerializerCodegenImpl(
|
|||||||
}
|
}
|
||||||
invokespecial(descImplType.internalName, "<init>", "(Ljava/lang/String;${generatedSerializerType.descriptor})V", false)
|
invokespecial(descImplType.internalName, "<init>", "(Ljava/lang/String;${generatedSerializerType.descriptor})V", false)
|
||||||
store(descriptorVar, descImplType)
|
store(descriptorVar, descImplType)
|
||||||
for (property in orderedProperties) {
|
for (property in serializableProperties) {
|
||||||
if (property.transient) continue
|
if (property.transient) continue
|
||||||
load(descriptorVar, descImplType)
|
load(descriptorVar, descImplType)
|
||||||
aconst(property.name)
|
aconst(property.name)
|
||||||
@@ -187,13 +187,13 @@ class SerializerCodegenImpl(
|
|||||||
|
|
||||||
override fun generateChildSerializersGetter(function: FunctionDescriptor) {
|
override fun generateChildSerializersGetter(function: FunctionDescriptor) {
|
||||||
codegen.generateMethod(function) { _, _ ->
|
codegen.generateMethod(function) { _, _ ->
|
||||||
val size = orderedProperties.size
|
val size = serializableProperties.size
|
||||||
iconst(size)
|
iconst(size)
|
||||||
newarray(kSerializerType)
|
newarray(kSerializerType)
|
||||||
for (i in 0 until size) {
|
for (i in 0 until size) {
|
||||||
dup() // array
|
dup() // array
|
||||||
iconst(i) // index
|
iconst(i) // index
|
||||||
val prop = orderedProperties[i]
|
val prop = serializableProperties[i]
|
||||||
assert(
|
assert(
|
||||||
stackValueSerializerInstanceFromSerializerWithoutSti(
|
stackValueSerializerInstanceFromSerializerWithoutSti(
|
||||||
codegen,
|
codegen,
|
||||||
@@ -224,7 +224,8 @@ class SerializerCodegenImpl(
|
|||||||
invokeinterface(
|
invokeinterface(
|
||||||
encoderType.internalName, CallingConventions.begin,
|
encoderType.internalName, CallingConventions.begin,
|
||||||
"(" + descType.descriptor + kSerializerArrayType.descriptor +
|
"(" + descType.descriptor + kSerializerArrayType.descriptor +
|
||||||
")" + kOutputType.descriptor)
|
")" + kOutputType.descriptor
|
||||||
|
)
|
||||||
store(outputVar, kOutputType)
|
store(outputVar, kOutputType)
|
||||||
if (serializableDescriptor.isInternalSerializable) {
|
if (serializableDescriptor.isInternalSerializable) {
|
||||||
val sig = StringBuilder("(${kOutputType.descriptor}${descType.descriptor}")
|
val sig = StringBuilder("(${kOutputType.descriptor}${descType.descriptor}")
|
||||||
@@ -240,11 +241,11 @@ class SerializerCodegenImpl(
|
|||||||
sig.append(")V")
|
sig.append(")V")
|
||||||
invokevirtual(
|
invokevirtual(
|
||||||
objType.internalName, SerialEntityNames.WRITE_SELF_NAME.asString(),
|
objType.internalName, SerialEntityNames.WRITE_SELF_NAME.asString(),
|
||||||
sig.toString(), false)
|
sig.toString(), false
|
||||||
}
|
)
|
||||||
else {
|
} else {
|
||||||
// loop for all properties
|
// loop for all properties
|
||||||
val labeledProperties = orderedProperties.filter { !it.transient }
|
val labeledProperties = serializableProperties.filter { !it.transient }
|
||||||
for (index in labeledProperties.indices) {
|
for (index in labeledProperties.indices) {
|
||||||
val property = labeledProperties[index]
|
val property = labeledProperties[index]
|
||||||
if (property.transient) continue
|
if (property.transient) continue
|
||||||
@@ -260,7 +261,8 @@ class SerializerCodegenImpl(
|
|||||||
load(descVar, descType)
|
load(descVar, descType)
|
||||||
invokeinterface(
|
invokeinterface(
|
||||||
kOutputType.internalName, CallingConventions.end,
|
kOutputType.internalName, CallingConventions.end,
|
||||||
"(" + descType.descriptor + ")V")
|
"(" + descType.descriptor + ")V"
|
||||||
|
)
|
||||||
// return
|
// return
|
||||||
areturn(Type.VOID_TYPE)
|
areturn(Type.VOID_TYPE)
|
||||||
}
|
}
|
||||||
@@ -289,9 +291,9 @@ class SerializerCodegenImpl(
|
|||||||
val indexVar = 3
|
val indexVar = 3
|
||||||
val readAllVar = 4
|
val readAllVar = 4
|
||||||
val bitMaskBase = 5
|
val bitMaskBase = 5
|
||||||
val blocksCnt = orderedProperties.size / OPT_MASK_BITS + 1
|
val blocksCnt = serializableProperties.bitMaskSlotCount()
|
||||||
fun bitMaskOff(i: Int) = bitMaskBase + (i / OPT_MASK_BITS) * OPT_MASK_TYPE.size
|
val bitMaskOff = fun(it: Int): Int { return bitMaskBase + bitMaskSlotAt(it) }
|
||||||
val propsStartVar = bitMaskBase + OPT_MASK_TYPE.size * blocksCnt
|
val propsStartVar = bitMaskBase + blocksCnt
|
||||||
stackSerialClassDesc(descVar)
|
stackSerialClassDesc(descVar)
|
||||||
// boolean readAll = false
|
// boolean readAll = false
|
||||||
iconst(0)
|
iconst(0)
|
||||||
@@ -304,7 +306,7 @@ class SerializerCodegenImpl(
|
|||||||
}
|
}
|
||||||
// initialize all prop vars
|
// initialize all prop vars
|
||||||
var propVar = propsStartVar
|
var propVar = propsStartVar
|
||||||
for (property in orderedProperties) {
|
for (property in serializableProperties) {
|
||||||
val propertyType = codegen.typeMapper.mapType(property.type)
|
val propertyType = codegen.typeMapper.mapType(property.type)
|
||||||
stackValueDefault(propertyType)
|
stackValueDefault(propertyType)
|
||||||
store(propVar, propertyType)
|
store(propVar, propertyType)
|
||||||
@@ -317,7 +319,8 @@ class SerializerCodegenImpl(
|
|||||||
invokeinterface(
|
invokeinterface(
|
||||||
decoderType.internalName, CallingConventions.begin,
|
decoderType.internalName, CallingConventions.begin,
|
||||||
"(" + descType.descriptor + kSerializerArrayType.descriptor +
|
"(" + descType.descriptor + kSerializerArrayType.descriptor +
|
||||||
")" + kInputType.descriptor)
|
")" + kInputType.descriptor
|
||||||
|
)
|
||||||
store(inputVar, kInputType)
|
store(inputVar, kInputType)
|
||||||
// readElement: int index = input.readElement(classDesc)
|
// readElement: int index = input.readElement(classDesc)
|
||||||
val readElementLabel = Label()
|
val readElementLabel = Label()
|
||||||
@@ -326,10 +329,11 @@ class SerializerCodegenImpl(
|
|||||||
load(descVar, descType)
|
load(descVar, descType)
|
||||||
invokeinterface(
|
invokeinterface(
|
||||||
kInputType.internalName, CallingConventions.decodeElementIndex,
|
kInputType.internalName, CallingConventions.decodeElementIndex,
|
||||||
"(" + descType.descriptor + ")I")
|
"(" + descType.descriptor + ")I"
|
||||||
|
)
|
||||||
store(indexVar, Type.INT_TYPE)
|
store(indexVar, Type.INT_TYPE)
|
||||||
// switch(index)
|
// switch(index)
|
||||||
val labeledProperties = orderedProperties.filter { !it.transient }
|
val labeledProperties = serializableProperties.filter { !it.transient }
|
||||||
val readAllLabel = Label()
|
val readAllLabel = Label()
|
||||||
val readEndLabel = Label()
|
val readEndLabel = Label()
|
||||||
val incorrectIndLabel = Label()
|
val incorrectIndLabel = Label()
|
||||||
@@ -348,7 +352,7 @@ class SerializerCodegenImpl(
|
|||||||
// loop for all properties
|
// loop for all properties
|
||||||
propVar = propsStartVar
|
propVar = propsStartVar
|
||||||
var labelNum = 0
|
var labelNum = 0
|
||||||
for ((index, property) in orderedProperties.withIndex()) {
|
for ((index, property) in serializableProperties.withIndex()) {
|
||||||
val propertyType = codegen.typeMapper.mapType(property.type)
|
val propertyType = codegen.typeMapper.mapType(property.type)
|
||||||
if (!property.transient) {
|
if (!property.transient) {
|
||||||
// labelI:
|
// labelI:
|
||||||
@@ -382,7 +386,7 @@ class SerializerCodegenImpl(
|
|||||||
// we can choose either it is read or update
|
// we can choose either it is read or update
|
||||||
val readLabel = Label()
|
val readLabel = Label()
|
||||||
val endL = Label()
|
val endL = Label()
|
||||||
genValidateProperty(index, ::bitMaskOff)
|
genValidateProperty(index, bitMaskOff)
|
||||||
ificmpeq(readLabel)
|
ificmpeq(readLabel)
|
||||||
load(propVar, propertyType)
|
load(propVar, propertyType)
|
||||||
StackValue.coerce(propertyType, sti.type, this)
|
StackValue.coerce(propertyType, sti.type, this)
|
||||||
@@ -398,8 +402,7 @@ class SerializerCodegenImpl(
|
|||||||
|
|
||||||
if (sti.unit) {
|
if (sti.unit) {
|
||||||
StackValue.putUnitInstance(this)
|
StackValue.putUnitInstance(this)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
StackValue.coerce(sti.type, propertyType, this)
|
StackValue.coerce(sti.type, propertyType, this)
|
||||||
}
|
}
|
||||||
store(propVar, propertyType)
|
store(propVar, propertyType)
|
||||||
@@ -425,8 +428,10 @@ class SerializerCodegenImpl(
|
|||||||
visitLabel(readEndLabel)
|
visitLabel(readEndLabel)
|
||||||
load(inputVar, kInputType)
|
load(inputVar, kInputType)
|
||||||
load(descVar, descType)
|
load(descVar, descType)
|
||||||
invokeinterface(kInputType.internalName, CallingConventions.end,
|
invokeinterface(
|
||||||
"(" + descType.descriptor + ")V")
|
kInputType.internalName, CallingConventions.end,
|
||||||
|
"(" + descType.descriptor + ")V"
|
||||||
|
)
|
||||||
if (!serializableDescriptor.isInternalSerializable) {
|
if (!serializableDescriptor.isInternalSerializable) {
|
||||||
//validate all required (constructor) fields
|
//validate all required (constructor) fields
|
||||||
val nonThrowLabel = Label()
|
val nonThrowLabel = Label()
|
||||||
@@ -435,10 +440,13 @@ class SerializerCodegenImpl(
|
|||||||
if (property.optional || property.transient) {
|
if (property.optional || property.transient) {
|
||||||
// todo: Normal reporting of error
|
// todo: Normal reporting of error
|
||||||
if (!property.isConstructorParameterWithDefault)
|
if (!property.isConstructorParameterWithDefault)
|
||||||
throw CompilationException("Property ${property.name} was declared as optional/transient but has no default value", null, null)
|
throw CompilationException(
|
||||||
}
|
"Property ${property.name} was declared as optional/transient but has no default value",
|
||||||
else {
|
null,
|
||||||
genValidateProperty(i, ::bitMaskOff)
|
null
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
genValidateProperty(i, bitMaskOff)
|
||||||
// todo: print name of each variable?
|
// todo: print name of each variable?
|
||||||
ificmpeq(throwLabel)
|
ificmpeq(throwLabel)
|
||||||
}
|
}
|
||||||
@@ -460,8 +468,9 @@ class SerializerCodegenImpl(
|
|||||||
// result := ... <created object>
|
// result := ... <created object>
|
||||||
store(resultVar, serializableAsmType)
|
store(resultVar, serializableAsmType)
|
||||||
// set other properties
|
// set other properties
|
||||||
propVar = propsStartVar + properties.serializableConstructorProperties.map { codegen.typeMapper.mapType(it.type).size }.sum()
|
propVar = propsStartVar +
|
||||||
genSetSerializableStandaloneProperties(expressionCodegen, propVar, resultVar, ::bitMaskOff)
|
properties.serializableConstructorProperties.map { codegen.typeMapper.mapType(it.type).size }.sum()
|
||||||
|
genSetSerializableStandaloneProperties(expressionCodegen, propVar, resultVar, bitMaskOff)
|
||||||
// load result
|
// load result
|
||||||
load(resultVar, serializableAsmType)
|
load(resultVar, serializableAsmType)
|
||||||
// will return result
|
// will return result
|
||||||
@@ -491,8 +500,7 @@ class SerializerCodegenImpl(
|
|||||||
}
|
}
|
||||||
if (!properties.primaryConstructorWithDefaults) {
|
if (!properties.primaryConstructorWithDefaults) {
|
||||||
constructorDesc.append(")V")
|
constructorDesc.append(")V")
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val cnt = properties.serializableConstructorProperties.size.coerceAtMost(32) //only 32 default values are supported
|
val cnt = properties.serializableConstructorProperties.size.coerceAtMost(32) //only 32 default values are supported
|
||||||
val mask = if (cnt == 32) -1 else ((1 shl cnt) - 1)
|
val mask = if (cnt == 32) -1 else ((1 shl cnt) - 1)
|
||||||
load(bitMaskBase, OPT_MASK_TYPE)
|
load(bitMaskBase, OPT_MASK_TYPE)
|
||||||
@@ -505,7 +513,8 @@ class SerializerCodegenImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun InstructionAdapter.genSetSerializableStandaloneProperties(
|
private fun InstructionAdapter.genSetSerializableStandaloneProperties(
|
||||||
expressionCodegen: ExpressionCodegen, propVarStart: Int, resultVar: Int, bitMaskPos: (Int) -> Int) {
|
expressionCodegen: ExpressionCodegen, propVarStart: Int, resultVar: Int, bitMaskPos: (Int) -> Int
|
||||||
|
) {
|
||||||
var propVar = propVarStart
|
var propVar = propVarStart
|
||||||
val offset = properties.serializableConstructorProperties.size
|
val offset = properties.serializableConstructorProperties.size
|
||||||
for ((index, property) in properties.serializableStandaloneProperties.withIndex()) {
|
for ((index, property) in properties.serializableStandaloneProperties.withIndex()) {
|
||||||
@@ -518,8 +527,7 @@ class SerializerCodegenImpl(
|
|||||||
// if (seen)
|
// if (seen)
|
||||||
// set
|
// set
|
||||||
ificmpeq(nextLabel)
|
ificmpeq(nextLabel)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// if (!seen)
|
// if (!seen)
|
||||||
// throw
|
// throw
|
||||||
// set
|
// set
|
||||||
@@ -530,9 +538,10 @@ class SerializerCodegenImpl(
|
|||||||
|
|
||||||
// generate setter call
|
// generate setter call
|
||||||
val propertyType = codegen.typeMapper.mapType(property.type)
|
val propertyType = codegen.typeMapper.mapType(property.type)
|
||||||
expressionCodegen.intermediateValueForProperty(property.descriptor, false, null,
|
expressionCodegen.intermediateValueForProperty(
|
||||||
StackValue.local(resultVar, serializableAsmType)).
|
property.descriptor, false, null,
|
||||||
store(StackValue.local(propVar, propertyType), this)
|
StackValue.local(resultVar, serializableAsmType)
|
||||||
|
).store(StackValue.local(propVar, propertyType), this)
|
||||||
propVar += propertyType.size
|
propVar += propertyType.size
|
||||||
if (property.optional)
|
if (property.optional)
|
||||||
visitLabel(nextLabel)
|
visitLabel(nextLabel)
|
||||||
|
|||||||
+6
-2
@@ -280,15 +280,19 @@ object KSerializerDescriptorResolver {
|
|||||||
val markerDesc = classDescriptor.getKSerializerConstructorMarker()
|
val markerDesc = classDescriptor.getKSerializerConstructorMarker()
|
||||||
val markerType = markerDesc.toSimpleType()
|
val markerType = markerDesc.toSimpleType()
|
||||||
|
|
||||||
val parameterDescsAsProps = SerializableProperties(classDescriptor, bindingContext).serializableProperties.map { it.descriptor }
|
val serializableProperties = SerializableProperties(classDescriptor, bindingContext).serializableProperties
|
||||||
|
val parameterDescsAsProps = serializableProperties.map { it.descriptor }
|
||||||
|
val bitMaskSlotsCount = serializableProperties.bitMaskSlotCount()
|
||||||
var i = 0
|
var i = 0
|
||||||
val consParams = mutableListOf<ValueParameterDescriptor>()
|
val consParams = mutableListOf<ValueParameterDescriptor>()
|
||||||
|
repeat(bitMaskSlotsCount) {
|
||||||
consParams.add(
|
consParams.add(
|
||||||
ValueParameterDescriptorImpl(
|
ValueParameterDescriptorImpl(
|
||||||
functionDescriptor, null, i++, Annotations.EMPTY, Name.identifier("seen"), functionDescriptor.builtIns.intType, false,
|
functionDescriptor, null, i++, Annotations.EMPTY, Name.identifier("seen$i"), functionDescriptor.builtIns.intType, false,
|
||||||
false, false, null, functionDescriptor.source
|
false, false, null, functionDescriptor.source
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
for (prop in parameterDescsAsProps) {
|
for (prop in parameterDescsAsProps) {
|
||||||
consParams.add(
|
consParams.add(
|
||||||
ValueParameterDescriptorImpl(
|
ValueParameterDescriptorImpl(
|
||||||
|
|||||||
+3
@@ -74,3 +74,6 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
|
|||||||
val primaryConstructorWithDefaults = serializableClass.unsubstitutedPrimaryConstructor
|
val primaryConstructorWithDefaults = serializableClass.unsubstitutedPrimaryConstructor
|
||||||
?.original?.valueParameters?.any { it.declaresDefaultValue() } ?: false
|
?.original?.valueParameters?.any { it.declaresDefaultValue() } ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun List<SerializableProperty>.bitMaskSlotCount() = size / 32 + 1
|
||||||
|
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
|
||||||
Reference in New Issue
Block a user