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