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. " +
|
||||||
|
|||||||
+63
-53
@@ -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) {
|
||||||
@@ -252,20 +254,20 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
// index = input.readElement(classDesc)
|
// index = input.readElement(classDesc)
|
||||||
val readElementF = context.getNameForDescriptor(inputClass.getFuncDesc(CallingConventions.decodeElementIndex).single())
|
val readElementF = context.getNameForDescriptor(inputClass.getFuncDesc(CallingConventions.decodeElementIndex).single())
|
||||||
+JsAstUtils.assignment(
|
+JsAstUtils.assignment(
|
||||||
indexVar,
|
indexVar,
|
||||||
JsInvocation(JsNameRef(readElementF, inputVar), serialClassDescRef)
|
JsInvocation(JsNameRef(readElementF, inputVar), serialClassDescRef)
|
||||||
).makeStmt()
|
).makeStmt()
|
||||||
// switch(index)
|
// switch(index)
|
||||||
jsSwitch(indexVar) {
|
jsSwitch(indexVar) {
|
||||||
// -2: readAll = true
|
// -2: readAll = true
|
||||||
case(JsIntLiteral(-2)) {
|
case(JsIntLiteral(-2)) {
|
||||||
+JsAstUtils.assignment(
|
+JsAstUtils.assignment(
|
||||||
readAllVar,
|
readAllVar,
|
||||||
JsBooleanLiteral(true)
|
JsBooleanLiteral(true)
|
||||||
).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)
|
||||||
@@ -273,64 +275,72 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
val call: JsExpression = if (innerSerial == null) {
|
val call: JsExpression = if (innerSerial == null) {
|
||||||
val unknownSer = (sti.elementMethodPrefix.isEmpty())
|
val unknownSer = (sti.elementMethodPrefix.isEmpty())
|
||||||
val readFunc =
|
val readFunc =
|
||||||
inputClass.getFuncDesc("${CallingConventions.decode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
|
inputClass.getFuncDesc("${CallingConventions.decode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
|
||||||
// if readElementValue, must have 3 parameters, if readXXXElementValue - 2
|
// if readElementValue, must have 3 parameters, if readXXXElementValue - 2
|
||||||
.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(
|
||||||
this@SerializerJsTranslator.context,
|
ExpressionVisitor.getObjectKClass(
|
||||||
property.type.toClassDescriptor!!
|
this@SerializerJsTranslator.context,
|
||||||
))
|
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}")
|
||||||
.let { context.getNameForDescriptor(it) }
|
.single()
|
||||||
|
.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}")
|
||||||
.let { context.getNameForDescriptor(it) }
|
.single()
|
||||||
JsConditional(notSeenTest,
|
.let { context.getNameForDescriptor(it) }
|
||||||
JsInvocation(JsNameRef(readFunc, inputVar),
|
JsConditional(
|
||||||
serialClassDescRef,
|
notSeenTest,
|
||||||
JsIntLiteral(i),
|
JsInvocation(
|
||||||
innerSerial),
|
JsNameRef(readFunc, inputVar),
|
||||||
JsInvocation(JsNameRef(updateFunc, inputVar),
|
serialClassDescRef,
|
||||||
serialClassDescRef,
|
JsIntLiteral(i),
|
||||||
JsIntLiteral(i),
|
innerSerial
|
||||||
innerSerial,
|
),
|
||||||
localProps[i]
|
JsInvocation(
|
||||||
)
|
JsNameRef(updateFunc, inputVar),
|
||||||
|
serialClassDescRef,
|
||||||
|
JsIntLiteral(i),
|
||||||
|
innerSerial,
|
||||||
|
localProps[i]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// localPropI = ...
|
// localPropI = ...
|
||||||
+JsAstUtils.assignment(
|
+JsAstUtils.assignment(
|
||||||
localProps[i],
|
localProps[i],
|
||||||
call
|
call
|
||||||
).makeStmt()
|
).makeStmt()
|
||||||
// need explicit unit instance
|
// need explicit unit instance
|
||||||
if (sti.unit) {
|
if (sti.unit) {
|
||||||
+JsAstUtils.assignment(
|
+JsAstUtils.assignment(
|
||||||
localProps[i],
|
localProps[i],
|
||||||
context.getQualifiedReference(property.type.builtIns.unit)
|
context.getQualifiedReference(property.type.builtIns.unit)
|
||||||
).makeStmt()
|
).makeStmt()
|
||||||
}
|
}
|
||||||
// char unboxing crutch
|
// char unboxing crutch
|
||||||
if (KotlinBuiltIns.isCharOrNullableChar(property.type)) {
|
if (KotlinBuiltIns.isCharOrNullableChar(property.type)) {
|
||||||
val coerceTo = TranslationUtils.getReturnTypeForCoercion(property.descriptor)
|
val coerceTo = TranslationUtils.getReturnTypeForCoercion(property.descriptor)
|
||||||
+JsAstUtils.assignment(
|
+JsAstUtils.assignment(
|
||||||
localProps[i],
|
localProps[i],
|
||||||
TranslationUtils.coerce(context, localProps[i], coerceTo)
|
TranslationUtils.coerce(context, localProps[i], coerceTo)
|
||||||
).makeStmt()
|
).makeStmt()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,
|
||||||
JsIntLiteral(bitPos)
|
bitMasks[bitMaskOff(i)],
|
||||||
|
JsIntLiteral(bitPos)
|
||||||
).makeStmt()
|
).makeStmt()
|
||||||
// if (!readAll) break
|
// if (!readAll) break
|
||||||
+JsIf(JsAstUtils.not(readAllVar), JsBreak())
|
+JsIf(JsAstUtils.not(readAllVar), JsBreak())
|
||||||
@@ -343,7 +353,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
// default: throw
|
// default: throw
|
||||||
default {
|
default {
|
||||||
val excClassRef = serializableDescriptor.getClassFromSerializationPackage(SerialEntityNames.UNKNOWN_FIELD_EXC)
|
val excClassRef = serializableDescriptor.getClassFromSerializationPackage(SerialEntityNames.UNKNOWN_FIELD_EXC)
|
||||||
.let { context.translateQualifiedReference(it) }
|
.let { context.translateQualifiedReference(it) }
|
||||||
+JsThrow(JsNew(excClassRef, listOf(indexVar)))
|
+JsThrow(JsNew(excClassRef, listOf(indexVar)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,17 +361,17 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
|
|
||||||
// input.readEnd(desc)
|
// input.readEnd(desc)
|
||||||
val readEndF = inputClass.getFuncDesc(CallingConventions.end).single()
|
val readEndF = inputClass.getFuncDesc(CallingConventions.end).single()
|
||||||
.let { context.getNameForDescriptor(it) }
|
.let { context.getNameForDescriptor(it) }
|
||||||
+JsInvocation(
|
+JsInvocation(
|
||||||
JsNameRef(readEndF, inputVar),
|
JsNameRef(readEndF, inputVar),
|
||||||
serialClassDescRef
|
serialClassDescRef
|
||||||
).makeStmt()
|
).makeStmt()
|
||||||
|
|
||||||
// deserialization constructor call
|
// deserialization constructor call
|
||||||
// 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)
|
||||||
|
|||||||
+52
-43
@@ -30,8 +30,8 @@ import org.jetbrains.org.objectweb.asm.Type
|
|||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
class SerializerCodegenImpl(
|
class SerializerCodegenImpl(
|
||||||
private val codegen: ImplementationBodyCodegen,
|
private val codegen: ImplementationBodyCodegen,
|
||||||
serializableClass: ClassDescriptor
|
serializableClass: ClassDescriptor
|
||||||
) : SerializerCodegen(codegen.descriptor, codegen.bindingContext) {
|
) : SerializerCodegen(codegen.descriptor, codegen.bindingContext) {
|
||||||
|
|
||||||
|
|
||||||
@@ -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,
|
||||||
@@ -208,7 +208,7 @@ class SerializerCodegenImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun generateSave(
|
override fun generateSave(
|
||||||
function: FunctionDescriptor
|
function: FunctionDescriptor
|
||||||
) {
|
) {
|
||||||
codegen.generateMethod(function) { signature, expressionCodegen ->
|
codegen.generateMethod(function) { signature, expressionCodegen ->
|
||||||
// fun save(output: KOutput, obj : T)
|
// fun save(output: KOutput, obj : T)
|
||||||
@@ -223,8 +223,9 @@ class SerializerCodegenImpl(
|
|||||||
genArrayOfTypeParametersSerializers()
|
genArrayOfTypeParametersSerializers()
|
||||||
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}")
|
||||||
@@ -232,7 +233,7 @@ class SerializerCodegenImpl(
|
|||||||
load(objVar, objType)
|
load(objVar, objType)
|
||||||
load(outputVar, kOutputType)
|
load(outputVar, kOutputType)
|
||||||
load(descVar, descType)
|
load(descVar, descType)
|
||||||
serializableDescriptor.declaredTypeParameters.forEachIndexed {i, _ ->
|
serializableDescriptor.declaredTypeParameters.forEachIndexed { i, _ ->
|
||||||
load(0, kSerializerType)
|
load(0, kSerializerType)
|
||||||
getfield(codegen.typeMapper.mapClass(codegen.descriptor).internalName, "$typeArgPrefix$i", kSerializerType.descriptor)
|
getfield(codegen.typeMapper.mapClass(codegen.descriptor).internalName, "$typeArgPrefix$i", kSerializerType.descriptor)
|
||||||
sig.append(kSerializerType.descriptor)
|
sig.append(kSerializerType.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)
|
||||||
}
|
}
|
||||||
@@ -280,7 +282,7 @@ class SerializerCodegenImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun generateLoad(
|
override fun generateLoad(
|
||||||
function: FunctionDescriptor
|
function: FunctionDescriptor
|
||||||
) {
|
) {
|
||||||
codegen.generateMethod(function) { _, expressionCodegen ->
|
codegen.generateMethod(function) { _, expressionCodegen ->
|
||||||
// fun load(input: KInput): T
|
// fun load(input: KInput): T
|
||||||
@@ -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)
|
||||||
@@ -316,8 +318,9 @@ class SerializerCodegenImpl(
|
|||||||
genArrayOfTypeParametersSerializers()
|
genArrayOfTypeParametersSerializers()
|
||||||
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)
|
||||||
|
|||||||
+10
-6
@@ -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>()
|
||||||
consParams.add(
|
repeat(bitMaskSlotsCount) {
|
||||||
ValueParameterDescriptorImpl(
|
consParams.add(
|
||||||
functionDescriptor, null, i++, Annotations.EMPTY, Name.identifier("seen"), functionDescriptor.builtIns.intType, false,
|
ValueParameterDescriptorImpl(
|
||||||
false, false, null, functionDescriptor.source
|
functionDescriptor, null, i++, Annotations.EMPTY, Name.identifier("seen$i"), functionDescriptor.builtIns.intType, false,
|
||||||
|
false, false, null, functionDescriptor.source
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
for (prop in parameterDescsAsProps) {
|
for (prop in parameterDescsAsProps) {
|
||||||
consParams.add(
|
consParams.add(
|
||||||
ValueParameterDescriptorImpl(
|
ValueParameterDescriptorImpl(
|
||||||
|
|||||||
+4
-1
@@ -73,4 +73,7 @@ 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