Hi! I’m a bit confused about IR -> JVM bytecode...
# compiler
i
Hi! I’m a bit confused about IR -> JVM bytecode generation process. I’m trying to create a delegate for IR generator inside
kotlin-parcelize
plugin which will call
.toPersistentList()
on result of another generator. Currently I have this code:
Copy 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:
Copy code
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.
d
I can suggest to write the code equal to your conversion and compare IR generated by compiler with one generated by you
u
I'd compile some small sample with
-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.
i
Ok, I will try this approach, thanks. Is there any example on how to do IR dump? Currently I’m just running the box test and inspecting the bytecode printed on failure. Also, I have the
AbstractParcelizeIrBytecodeListingTest
which I suppose dumps IR, right? (
.asm.ir.txt
file) Or there’s easier way to get an IR dump?
d
You can create test in
AbstractParcelizeBoxTestBase
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 file
i
Nice, thanks!
Ok, I’ve removed the
irBlock
completely and now everything seems to work fine, Thanks!
Copy code
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
        }
    }

}
👍 2
Ok, I’ve just figured out what was the original issue about. I forgot to add
+
before
irGet
.
u
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).
i
Yeah, I’ve seen your message, but for now running a test was much easier, since I don’t know yet how to run compiler correctly 😅
👍 1