ilyagulya
09/13/2023, 11:12 AMkotlin-parcelize plugin which will call .toPersistentList() on result of another generator.
Currently I have this code:
class IrSimplePersistentListParcelSerializerDecorator(
private val delegated: IrParcelSerializer,
private val symbols: AndroidSymbols,
) : IrParcelSerializer by delegated {
override fun AndroidIrBuilder.readParcel(parcel: IrValueDeclaration): IrExpression {
return irBlock {
val arrayList = with(delegated) {
readParcel(parcel)
}
val persistentList = irTemporary(irCall(symbols.kotlinIterableToPersistentListExtension).apply {
extensionReceiver = arrayList
})
irGet(persistentList)
}
}
}
Compiler generates following JVM bytecode:
public final createFromParcel(Landroid/os/Parcel;)Ltest/Test;
@Lorg/jetbrains/annotations/NotNull;() // invisible
// annotable parameter count: 1 (visible)
// annotable parameter count: 1 (invisible)
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 1
LDC "parcel"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkNotNullParameter (Ljava/lang/Object;Ljava/lang/String;)V
NEW test/Test
DUP
ALOAD 1
INVOKEVIRTUAL android/os/Parcel.createStringArrayList ()Ljava/util/ArrayList;
CHECKCAST java/lang/Iterable
INVOKESTATIC kotlinx/collections/immutable/ExtensionsKt.toPersistentList (Ljava/lang/Iterable;)Lkotlinx/collections/immutable/PersistentList;
POP
ACONST_NULL
INVOKESPECIAL test/Test.<init> (Lkotlinx/collections/immutable/PersistentList;)V
ARETURN
Current issue is that somehow compiler decides to POP the result of ExtensionsKt.toPersistentList call from stack and pushes null there instead.
It results in Test constructor being called with wrong argument (null instead of result of toPersistentList call)
I can’t understand what is wrong with my code inside IrSimplePersistentListParcelSerializerDecorator.readParcel method.dmitriy.novozhilov
09/13/2023, 11:15 AMudalov
-Xphases-to-dump=ALL and dump output to a file, and then investigate if the IR is correct at the beginning of lowerings and at the end, and if not, which lowering is responsible for the problem. If IR is correct at the end, the next suspect is OptimizationMethodVisitor, where we can check the bytecode (only manually in debugger, unfortunately) before/after each step and see which one introduces the problem.ilyagulya
09/13/2023, 11:39 AMAbstractParcelizeIrBytecodeListingTest which I suppose dumps IR, right? (.asm.ir.txt file)
Or there’s easier way to get an IR dump?dmitriy.novozhilov
09/13/2023, 11:42 AMAbstractParcelizeBoxTestBase suite and add // DUMP_IR line at the beginning of the test file
It will trigger tests to dump IR after plugins phase and before backend itself into fileilyagulya
09/13/2023, 11:42 AMilyagulya
09/13/2023, 12:03 PMirBlock completely and now everything seems to work fine, Thanks!
class IrSimplePersistentListParcelSerializerDecorator(
private val delegated: IrParcelSerializer,
private val symbols: AndroidSymbols,
) : IrParcelSerializer by delegated {
override fun AndroidIrBuilder.readParcel(parcel: IrValueDeclaration): IrExpression {
val arrayList = with(delegated) {
readParcel(parcel)
}
return irCall(symbols.kotlinIterableToPersistentListExtension).apply {
extensionReceiver = arrayList
}
}
}ilyagulya
09/13/2023, 12:09 PM+ before irGet.udalov
Or there’s easier way to get an IR dump?Just in case my message was overlooked, the compiler argument
-Xphases-to-dump=ALL dumps all IR before and after each lowering, including at the beginning (which is right after plugins are applied).ilyagulya
09/13/2023, 1:00 PM