Support .decodeSequentially call on JVM and Native and remove READ_ALL handling from all platforms

Fix codegen test

Ignore JVM IR codegen test for a while since it requires updated kotlinx-serialization-runtime in classpath
This commit is contained in:
Leonid Startsev
2019-12-13 15:19:11 +03:00
parent cb98588202
commit f2026a49bb
8 changed files with 245 additions and 192 deletions
@@ -17,9 +17,11 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.util.withScope
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
@@ -331,8 +333,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
val flagVar = irTemporaryVar(irBoolean(true), "flag")
val indexVar = irTemporaryVar(irInt(0), "index")
// val readAll = irTemporaryVar(irBoolean(false), "readAll", parent = loadFunc)
//
// calculating bit mask vars
val blocksCnt = serializableProperties.bitMaskSlotCount()
@@ -358,54 +359,61 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
)
val localInput = irTemporary(call, "input")
+irWhile().also { loop ->
// prepare all .decodeXxxElement calls
val decoderCalls: List<Pair<Int, IrExpression>> =
serializableProperties.mapIndexed { index, property ->
val body = irBlock {
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(
this@SerializerIrGenerator,
loadFunc.dispatchReceiverParameter!!,
sti.serializer,
property.module,
property.type,
genericIndex = property.genericIndex
)
// todo: update
val decodeFuncToCall =
(if (innerSerial != null) "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}"
else "${CallingConventions.decode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
.let {
inputClass.referenceMethod(it)
}
val typeArgs =
if (decodeFuncToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
val args = mutableListOf<IrExpression>(localSerialDesc.get(), irInt(index))
if (innerSerial != null)
args.add(innerSerial)
// local$i = localInput.decode...(...)
+irSetVar(
localProps[index].symbol,
irInvoke(localInput.get(), decodeFuncToCall, typeArgs, args, returnTypeHint = property.type.toIrType())
)
// bitMask[i] |= 1 << x
val bitPos = 1 shl (index % 32)
val or = irBinOp(OperatorNameConventions.OR, bitMasks[index / 32].get(), irInt(bitPos))
+irSetVar(bitMasks[index / 32].symbol, or)
}
index to body
}
// if (decoder.decodeSequentially())
val decodeSequentiallyCall = irInvoke(localInput.get(), inputClass.referenceMethod(CallingConventions.decodeSequentially))
val sequentialPart = irBlock {
decoderCalls.forEach { (_, expr) -> +expr.deepCopyWithVariables() }
}
val byIndexPart: IrExpression = irWhile().also { loop ->
loop.condition = flagVar.get()
loop.body = irBlock {
val readElementF = inputClass.referenceMethod(CallingConventions.decodeElementIndex)
+irSetVar(indexVar.symbol, irInvoke(localInput.get(), readElementF, localSerialDesc.get()))
+irWhen {
// if index == -2 (READ_ALL) todo...
// if index == -1 (READ_DONE) break loop
+IrBranchImpl(irEquals(indexVar.get(), irInt(-1)), irSetVar(flagVar.symbol, irBoolean(false)))
val branchBodies: List<Pair<Int, IrExpression>> =
serializableProperties.mapIndexed { index, property ->
val body = irBlock {
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(
this@SerializerIrGenerator,
loadFunc.dispatchReceiverParameter!!,
sti.serializer,
property.module,
property.type,
genericIndex = property.genericIndex
)
// todo: update
val decodeFuncToCall =
(if (innerSerial != null) "${CallingConventions.decode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}"
else "${CallingConventions.decode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}")
.let {
inputClass.referenceMethod(it)
}
val typeArgs =
if (decodeFuncToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
val args = mutableListOf<IrExpression>(localSerialDesc.get(), irInt(index))
if (innerSerial != null)
args.add(innerSerial)
// local$i = localInput.decode...(...)
+irSetVar(
localProps[index].symbol,
irInvoke(localInput.get(), decodeFuncToCall, typeArgs, args, returnTypeHint = property.type.toIrType())
)
// bitMask[i] |= 1 << x
val bitPos = 1 shl (index % 32)
val or = irBinOp(OperatorNameConventions.OR, bitMasks[index / 32].get(), irInt(bitPos))
+irSetVar(bitMasks[index / 32].symbol, or)
}
index to body
}
branchBodies.forEach { (i, e) -> +IrBranchImpl(irEquals(indexVar.get(), irInt(i)), e) }
decoderCalls.forEach { (i, e) -> +IrBranchImpl(irEquals(indexVar.get(), irInt(i)), e) }
// throw exception on unknown field
val exceptionCtor =
@@ -425,6 +433,8 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
}
}
+irIfThenElse(compilerContext.irBuiltIns.unitType, decodeSequentiallyCall, sequentialPart, byIndexPart)
//input.endStructure(...)
val endFunc = inputClass.referenceMethod(CallingConventions.end)
+irInvoke(
@@ -244,8 +244,7 @@ open class SerializerJsTranslator(
// var index = -1, readAll = false
val indexVar = JsNameRef(jsFun.scope.declareFreshName("index"))
val readAllVar = JsNameRef(jsFun.scope.declareFreshName("readAll"))
+JsVars(JsVars.JsVar(indexVar.name), JsVars.JsVar(readAllVar.name, JsBooleanLiteral(false)))
+JsVars(JsVars.JsVar(indexVar.name))
// calculating bit mask vars
val blocksCnt = serializableProperties.bitMaskSlotCount()
@@ -283,14 +282,7 @@ open class SerializerJsTranslator(
).makeStmt()
// switch(index)
jsSwitch(indexVar) {
// -2: readAll = true
case(JsIntLiteral(-2)) {
+JsAstUtils.assignment(
readAllVar,
JsBooleanLiteral(true)
).makeStmt()
}
// all properties
// all properties
for ((i, property) in serializableProperties.withIndex()) {
case(JsIntLiteral(i)) {
// input.readXxxElementValue
@@ -366,8 +358,7 @@ open class SerializerJsTranslator(
bitMasks[bitMaskOff(i)],
JsIntLiteral(bitPos)
).makeStmt()
// if (!readAll) break
+JsIf(JsAstUtils.not(readAllVar), JsBreak())
+JsBreak()
}
}
// case -1: break loop
@@ -76,9 +76,8 @@ val OPT_MASK_TYPE: Type = Type.INT_TYPE
val OPT_MASK_BITS = 32
// compare with zero. if result == 0, property was not seen.
internal fun InstructionAdapter.genValidateProperty(index: Int, bitMaskPos: (Int) -> Int) {
val addr = bitMaskPos(index)
load(addr, OPT_MASK_TYPE)
internal fun InstructionAdapter.genValidateProperty(index: Int, bitMaskAddress: Int) {
load(bitMaskAddress, OPT_MASK_TYPE)
iconst(1 shl (index % OPT_MASK_BITS))
and(OPT_MASK_TYPE)
iconst(0)
@@ -188,7 +188,7 @@ class SerializableCodegenImpl(
val propType = prop.asmType
if (!prop.optional) {
// primary were validated before constructor call
genValidateProperty(i, bitMaskOff)
genValidateProperty(i, bitMaskOff(i))
val nonThrowLabel = Label()
ificmpne(nonThrowLabel)
genExceptionThrow(serializationExceptionMissingFieldName, prop.name)
@@ -198,7 +198,7 @@ class SerializableCodegenImpl(
load(propOffset, propType)
putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
} else {
genValidateProperty(i, bitMaskOff)
genValidateProperty(i, bitMaskOff(i))
val setLbl = Label()
val nextLabel = Label()
ificmpeq(setLbl)
@@ -299,15 +299,11 @@ open class SerializerCodegenImpl(
val inputVar = 1
val descVar = 2
val indexVar = 3
val readAllVar = 4
val bitMaskBase = 5
val bitMaskBase = 4
val blocksCnt = serializableProperties.bitMaskSlotCount()
val bitMaskOff = fun(it: Int): Int { return bitMaskBase + bitMaskSlotAt(it) }
val propsStartVar = bitMaskBase + blocksCnt
stackSerialClassDesc(descVar)
// boolean readAll = false
iconst(0)
store(readAllVar, Type.BOOLEAN_TYPE)
// initialize bit mask
for (i in 0 until blocksCnt) {
//int bitMaskN = 0
@@ -332,8 +328,31 @@ open class SerializerCodegenImpl(
")" + kInputType.descriptor
)
store(inputVar, kInputType)
// readElement: int index = input.readElement(classDesc)
val readElementLabel = Label()
val readEndLabel = Label()
// if (decoder.decodeSequentially)
load(inputVar, kInputType)
invokeinterface(
kInputType.internalName, CallingConventions.decodeSequentially,
"()Z"
)
ifeq(readElementLabel)
// decodeSequentially = true
propVar = propsStartVar
for ((index, property) in serializableProperties.withIndex()) {
val propertyType = codegen.typeMapper.mapType(property.type)
callReadProperty(property, propertyType, index, inputVar, descVar, -1, propVar)
propVar += propertyType.size
}
// set all bit masks to true
for (maskVar in bitMaskBase until propsStartVar) {
iconst(Int.MAX_VALUE)
store(maskVar, OPT_MASK_TYPE)
}
// go to end
goTo(readEndLabel)
// branch with decodeSequentially = false
// readElement: int index = input.readElement(classDesc)
visitLabel(readElementLabel)
load(inputVar, kInputType)
load(descVar, descType)
@@ -344,78 +363,24 @@ open class SerializerCodegenImpl(
store(indexVar, Type.INT_TYPE)
// switch(index)
val labeledProperties = serializableProperties.filter { !it.transient }
val readAllLabel = Label()
val readEndLabel = Label()
val incorrectIndLabel = Label()
val labels = arrayOfNulls<Label>(labeledProperties.size + 2)
labels[0] = readAllLabel // READ_ALL
labels[1] = readEndLabel // READ_DONE
val labels = arrayOfNulls<Label>(labeledProperties.size + 1)
labels[0] = readEndLabel // READ_DONE
for (i in labeledProperties.indices) {
labels[i + 2] = Label()
labels[i + 1] = Label()
}
load(indexVar, Type.INT_TYPE)
tableswitch(-2, labeledProperties.size - 1, incorrectIndLabel, *labels)
// readAll: readAll := true
visitLabel(readAllLabel)
iconst(1)
store(readAllVar, Type.BOOLEAN_TYPE)
tableswitch(-1, labeledProperties.size - 1, incorrectIndLabel, *labels)
// loop for all properties
propVar = propsStartVar
var labelNum = 0
for ((index, property) in serializableProperties.withIndex()) {
val propertyType = codegen.typeMapper.mapType(property.type)
if (!property.transient) {
val propertyAddressInBitMask = bitMaskOff(index)
// labelI:
visitLabel(labels[labelNum + 2])
// propX := input.readXxxValue(value)
load(inputVar, kInputType)
load(descVar, descType)
iconst(labelNum)
val sti = getSerialTypeInfo(property, propertyType)
val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti, this@SerializerCodegenImpl)
val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty())
if (unknownSer) {
aconst(codegen.typeMapper.mapType(property.type))
AsmUtil.wrapJavaClassIntoKClass(this)
}
fun produceCall(update: Boolean) {
invokeinterface(
kInputType.internalName,
(if (update) CallingConventions.update else CallingConventions.decode) + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + CallingConventions.elementPostfix,
"(" + descType.descriptor + "I" +
(if (useSerializer) kSerialLoaderType.descriptor else "")
+ (if (unknownSer) AsmTypes.K_CLASS_TYPE.descriptor else "")
+ (if (update) sti.type.descriptor else "")
+ ")" + (if (sti.unit) "V" else sti.type.descriptor)
)
}
if (useSerializer) {
// we can choose either it is read or update
val readLabel = Label()
val endL = Label()
genValidateProperty(index, bitMaskOff)
ificmpeq(readLabel)
load(propVar, propertyType)
StackValue.coerce(propertyType, sti.type, this)
produceCall(true)
goTo(endL)
visitLabel(readLabel)
produceCall(false)
visitLabel(endL)
} else {
// update not supported for primitive types
produceCall(false)
}
if (sti.unit) {
StackValue.putUnitInstance(this)
} else {
StackValue.coerce(sti.type, propertyType, this)
}
store(propVar, propertyType)
visitLabel(labels[labelNum + 1])
callReadProperty(property, propertyType, index, inputVar, descVar, propertyAddressInBitMask, propVar)
// mark read bit in mask
// bitMask = bitMask | 1 << index
@@ -424,10 +389,7 @@ open class SerializerCodegenImpl(
iconst(1 shl (index % OPT_MASK_BITS))
or(OPT_MASK_TYPE)
store(addr, OPT_MASK_TYPE)
// if (readAll == false) goto readElement
load(readAllVar, Type.BOOLEAN_TYPE)
iconst(0)
ificmpeq(readElementLabel)
goTo(readElementLabel)
labelNum++
}
// next
@@ -456,7 +418,7 @@ open class SerializerCodegenImpl(
null
)
} else {
genValidateProperty(i, bitMaskOff)
genValidateProperty(i, bitMaskOff(i))
// todo: print name of each variable?
ificmpeq(throwLabel)
}
@@ -499,6 +461,66 @@ open class SerializerCodegenImpl(
}
}
private fun InstructionAdapter.callReadProperty(
property: SerializableProperty,
propertyType: Type,
index: Int,
inputVar: Int,
descriptorVar: Int,
propertyAddressInBitMask: Int,
propertyVar: Int
) {
// propX := input.readXxxValue(value)
load(inputVar, kInputType)
load(descriptorVar, descType)
iconst(index)
val sti = getSerialTypeInfo(property, propertyType)
val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti, this@SerializerCodegenImpl)
val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty())
if (unknownSer) {
aconst(codegen.typeMapper.mapType(property.type))
AsmUtil.wrapJavaClassIntoKClass(this)
}
fun produceCall(update: Boolean) {
invokeinterface(
kInputType.internalName,
(if (update) CallingConventions.update else CallingConventions.decode) + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + CallingConventions.elementPostfix,
"(" + descType.descriptor + "I" +
(if (useSerializer) kSerialLoaderType.descriptor else "")
+ (if (unknownSer) AsmTypes.K_CLASS_TYPE.descriptor else "")
+ (if (update) sti.type.descriptor else "")
+ ")" + (if (sti.unit) "V" else sti.type.descriptor)
)
}
if (useSerializer && propertyAddressInBitMask != -1) {
// we can choose either it is read or update
val readLabel = Label()
val endL = Label()
genValidateProperty(index, propertyAddressInBitMask)
ificmpeq(readLabel)
load(propertyVar, propertyType)
StackValue.coerce(propertyType, sti.type, this)
produceCall(true)
goTo(endL)
visitLabel(readLabel)
produceCall(false)
visitLabel(endL)
} else {
// update not supported for primitive types or decodeSequentially
produceCall(false)
}
if (sti.unit) {
StackValue.putUnitInstance(this)
} else {
StackValue.coerce(sti.type, propertyType, this)
}
store(propertyVar, propertyType)
}
private fun InstructionAdapter.buildExternalConstructorDesc(propsStartVar: Int, bitMaskBase: Int): String {
val constructorDesc = StringBuilder("(")
var propVar = propsStartVar
@@ -532,7 +554,7 @@ open class SerializerCodegenImpl(
//check if property has been seen and should be set
val nextLabel = Label()
// seen = bitMask & 1 << pos != 0
genValidateProperty(i, bitMaskPos)
genValidateProperty(i, bitMaskPos(i))
if (property.optional) {
// if (seen)
// set
@@ -95,6 +95,7 @@ object CallingConventions {
const val encodeEnum = "encodeEnum"
const val decodeEnum = "decodeEnum"
const val decodeElementIndex = "decodeElementIndex"
const val decodeSequentially = "decodeSequentially"
const val elementPostfix = "Element"
const val shouldEncodeDefault = "shouldEncodeElementDefault"
@@ -9,6 +9,7 @@ import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import java.io.File;
@@ -19,6 +20,7 @@ import java.util.regex.Pattern;
@TestMetadata("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@Ignore // todo: unignore when new serialziation version will be publicly available & update it in build.gradle.kts
public class SerializationIrBytecodeListingTestGenerated extends AbstractSerializationIrBytecodeListingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
@@ -62,16 +62,31 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa
ASTORE (2)
ICONST_0
ISTORE (4)
ICONST_0
ISTORE (5)
ACONST_NULL
ASTORE (6)
ASTORE (5)
ALOAD (1)
ALOAD (2)
ICONST_0
ANEWARRAY
INVOKEINTERFACE (kotlinx/serialization/Decoder, beginStructure, (Lkotlinx/serialization/SerialDescriptor;[Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/CompositeDecoder;)
ASTORE (1)
ALOAD (1)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeSequentially, ()Z)
IFEQ (L1)
ALOAD (1)
ALOAD (2)
ICONST_0
NEW
DUP
GETSTATIC (INSTANCE, LUser$$serializer;)
CHECKCAST
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeSerializableElement, (Lkotlinx/serialization/SerialDescriptor;ILkotlinx/serialization/DeserializationStrategy;)Ljava/lang/Object;)
CHECKCAST
ASTORE (5)
LDC (2147483647)
ISTORE (4)
GOTO (L2)
LABEL (L1)
ALOAD (1)
ALOAD (2)
@@ -79,9 +94,6 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa
ISTORE (3)
ILOAD (3)
TABLESWITCH
LABEL (L2)
ICONST_1
ISTORE (4)
LABEL (L3)
ALOAD (1)
ALOAD (2)
@@ -91,43 +103,42 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa
GETSTATIC (INSTANCE, LUser$$serializer;)
CHECKCAST
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
ILOAD (5)
ILOAD (4)
ICONST_1
IAND
IFEQ (L4)
ALOAD (6)
ALOAD (5)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, updateSerializableElement, (Lkotlinx/serialization/SerialDescriptor;ILkotlinx/serialization/DeserializationStrategy;Ljava/lang/Object;)Ljava/lang/Object;)
GOTO (L5)
LABEL (L4)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeSerializableElement, (Lkotlinx/serialization/SerialDescriptor;ILkotlinx/serialization/DeserializationStrategy;)Ljava/lang/Object;)
LABEL (L5)
CHECKCAST
ASTORE (6)
ILOAD (5)
ASTORE (5)
ILOAD (4)
ICONST_1
IOR
ISTORE (5)
ILOAD (4)
IFEQ (L1)
LABEL (L6)
ISTORE (4)
GOTO (L1)
LABEL (L2)
ALOAD (1)
ALOAD (2)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V)
NEW
DUP
ILOAD (5)
ALOAD (6)
ILOAD (4)
ALOAD (5)
ACONST_NULL
INVOKESPECIAL (ListOfUsers, <init>, (ILjava/util/List;Lkotlinx/serialization/SerializationConstructorMarker;)V)
ARETURN
LABEL (L7)
LABEL (L6)
NEW
DUP
ILOAD (3)
INVOKESPECIAL (kotlinx/serialization/UnknownFieldException, <init>, (I)V)
CHECKCAST
ATHROW
LABEL (L8)
LABEL (L7)
}
public java.lang.Object deserialize(kotlinx.serialization.Decoder p0) {
@@ -348,16 +359,28 @@ public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serializ
ASTORE (2)
ICONST_0
ISTORE (4)
ICONST_0
ISTORE (5)
ACONST_NULL
ASTORE (6)
ASTORE (5)
ALOAD (1)
ALOAD (2)
ICONST_0
ANEWARRAY
INVOKEINTERFACE (kotlinx/serialization/Decoder, beginStructure, (Lkotlinx/serialization/SerialDescriptor;[Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/CompositeDecoder;)
ASTORE (1)
ALOAD (1)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeSequentially, ()Z)
IFEQ (L1)
ALOAD (1)
ALOAD (2)
ICONST_0
GETSTATIC (INSTANCE, LUser$$serializer;)
CHECKCAST
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeSerializableElement, (Lkotlinx/serialization/SerialDescriptor;ILkotlinx/serialization/DeserializationStrategy;)Ljava/lang/Object;)
CHECKCAST
ASTORE (5)
LDC (2147483647)
ISTORE (4)
GOTO (L2)
LABEL (L1)
ALOAD (1)
ALOAD (2)
@@ -365,52 +388,48 @@ public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serializ
ISTORE (3)
ILOAD (3)
TABLESWITCH
LABEL (L2)
ICONST_1
ISTORE (4)
LABEL (L3)
ALOAD (1)
ALOAD (2)
ICONST_0
GETSTATIC (INSTANCE, LUser$$serializer;)
CHECKCAST
ILOAD (5)
ILOAD (4)
ICONST_1
IAND
IFEQ (L4)
ALOAD (6)
ALOAD (5)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, updateSerializableElement, (Lkotlinx/serialization/SerialDescriptor;ILkotlinx/serialization/DeserializationStrategy;Ljava/lang/Object;)Ljava/lang/Object;)
GOTO (L5)
LABEL (L4)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeSerializableElement, (Lkotlinx/serialization/SerialDescriptor;ILkotlinx/serialization/DeserializationStrategy;)Ljava/lang/Object;)
LABEL (L5)
CHECKCAST
ASTORE (6)
ILOAD (5)
ASTORE (5)
ILOAD (4)
ICONST_1
IOR
ISTORE (5)
ILOAD (4)
IFEQ (L1)
LABEL (L6)
ISTORE (4)
GOTO (L1)
LABEL (L2)
ALOAD (1)
ALOAD (2)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V)
NEW
DUP
ILOAD (5)
ALOAD (6)
ILOAD (4)
ALOAD (5)
ACONST_NULL
INVOKESPECIAL (OptionalUser, <init>, (ILUser;Lkotlinx/serialization/SerializationConstructorMarker;)V)
ARETURN
LABEL (L7)
LABEL (L6)
NEW
DUP
ILOAD (3)
INVOKESPECIAL (kotlinx/serialization/UnknownFieldException, <init>, (I)V)
CHECKCAST
ATHROW
LABEL (L8)
LABEL (L7)
}
public java.lang.Object deserialize(kotlinx.serialization.Decoder p0) {
@@ -691,18 +710,32 @@ public final class User$$serializer : java/lang/Object, kotlinx/serialization/in
ASTORE (2)
ICONST_0
ISTORE (4)
ICONST_0
ISTORE (5)
ACONST_NULL
ASTORE (5)
ACONST_NULL
ASTORE (6)
ACONST_NULL
ASTORE (7)
ALOAD (1)
ALOAD (2)
ICONST_0
ANEWARRAY
INVOKEINTERFACE (kotlinx/serialization/Decoder, beginStructure, (Lkotlinx/serialization/SerialDescriptor;[Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/CompositeDecoder;)
ASTORE (1)
ALOAD (1)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeSequentially, ()Z)
IFEQ (L1)
ALOAD (1)
ALOAD (2)
ICONST_0
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeStringElement, (Lkotlinx/serialization/SerialDescriptor;I)Ljava/lang/String;)
ASTORE (5)
ALOAD (1)
ALOAD (2)
ICONST_1
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeStringElement, (Lkotlinx/serialization/SerialDescriptor;I)Ljava/lang/String;)
ASTORE (6)
LDC (2147483647)
ISTORE (4)
GOTO (L2)
LABEL (L1)
ALOAD (1)
ALOAD (2)
@@ -710,53 +743,48 @@ public final class User$$serializer : java/lang/Object, kotlinx/serialization/in
ISTORE (3)
ILOAD (3)
TABLESWITCH
LABEL (L2)
ICONST_1
ISTORE (4)
LABEL (L3)
ALOAD (1)
ALOAD (2)
ICONST_0
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeStringElement, (Lkotlinx/serialization/SerialDescriptor;I)Ljava/lang/String;)
ASTORE (6)
ILOAD (5)
ASTORE (5)
ILOAD (4)
ICONST_1
IOR
ISTORE (5)
ILOAD (4)
IFEQ (L1)
ISTORE (4)
GOTO (L1)
LABEL (L4)
ALOAD (1)
ALOAD (2)
ICONST_1
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, decodeStringElement, (Lkotlinx/serialization/SerialDescriptor;I)Ljava/lang/String;)
ASTORE (7)
ILOAD (5)
ASTORE (6)
ILOAD (4)
ICONST_2
IOR
ISTORE (5)
ILOAD (4)
IFEQ (L1)
LABEL (L5)
ISTORE (4)
GOTO (L1)
LABEL (L2)
ALOAD (1)
ALOAD (2)
INVOKEINTERFACE (kotlinx/serialization/CompositeDecoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V)
NEW
DUP
ILOAD (5)
ILOAD (4)
ALOAD (5)
ALOAD (6)
ALOAD (7)
ACONST_NULL
INVOKESPECIAL (User, <init>, (ILjava/lang/String;Ljava/lang/String;Lkotlinx/serialization/SerializationConstructorMarker;)V)
ARETURN
LABEL (L6)
LABEL (L5)
NEW
DUP
ILOAD (3)
INVOKESPECIAL (kotlinx/serialization/UnknownFieldException, <init>, (I)V)
CHECKCAST
ATHROW
LABEL (L7)
LABEL (L6)
}
public java.lang.Object deserialize(kotlinx.serialization.Decoder p0) {