101010

プログラミング備忘録とともに、ポエムってます。

IntelliJでちょっと便利な機能、KotlinからJavaへ逆コンパイル | Android Kotlin

f:id:araemonz:20190224163635p:plain

IntelliJにて、KotlinからJavaに逆コンパイルする方法をメモっておく。(このことはKotlinコードと等価なJavaコードを見たい場合に便利である。)

Kotlinで書かれたソースコードを、Kotlinコンパイラで一旦バイトコードへ変換する。それを更に、Javaのソースコードに逆コンパイルするという流れになる。これをIntelliJで行っていこう。

手順

  1. 対象となるソースコードを表示した上で「Shift」キーを2度押す。
  2. 「show kotlin」と入力すると、「Show Kotlin Bytecode」が現れるのでそれを選択する。(図1)
  3. Decompileボタンを押す。(図2)
  4. Javaに逆コンパイルされたコードが表示される。(図3)

f:id:araemonz:20190224160648j:plain
図1

f:id:araemonz:20190224160644j:plain
図2

f:id:araemonz:20190224160639j:plain
図3

逆コンパイルのサンプル

fun main(args: Array<String>) {
    val name = "Madrigal"
    val healthPoints = 89
    val isBlessed = true
    val isImmortal = false
    var inebriation = 0

    val auraColor = auraColor(isBlessed, healthPoints, isImmortal)

    val healthStatus = formatHealthStatus(healthPoints, isBlessed)

    printPlayerStatus(auraColor, isBlessed, name, healthStatus)

    inebriation += castFireball(120)

    printInebriationStatus(inebriation)
}

このKotlinコードをJavaに逆コンパイルしてみると次のようになった。

public final class GameKt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      String name = "Madrigal";
      int healthPoints = 89;
      boolean isBlessed = true;
      boolean isImmortal = false;
      int inebriation = 0;
      String auraColor = auraColor(isBlessed, healthPoints, isImmortal);
      String healthStatus = formatHealthStatus(healthPoints, isBlessed);
      printPlayerStatus(auraColor, isBlessed, name, healthStatus);
      int inebriation = inebriation + castFireball(120);
      printInebriationStatus(inebriation);
   }

KotlinファイルであるGame.ktというのは、GameKtクラスに置き換わっていることがわかる。 Kotlinの関数はstaticメソッドになるようである。

ちなみにバイトコードでは次のように表現される。

// ================GameKt.class =================
// class version 50.0 (50)
// access flags 0x31
public final class GameKt {


  // access flags 0x19
  public final static main([Ljava/lang/String;)V
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   L0
    ALOAD 0
    LDC "args"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
   L1
    LINENUMBER 3 L1
    LDC "Madrigal"
    ASTORE 1
   L2
    LINENUMBER 4 L2
    BIPUSH 89
    ISTORE 2
   L3
    LINENUMBER 5 L3
    ICONST_1
    ISTORE 3
   L4
    LINENUMBER 6 L4
    ICONST_0
    ISTORE 4
   L5
    LINENUMBER 7 L5
    ICONST_0
    ISTORE 5
   L6
    LINENUMBER 9 L6
    ILOAD 3
    ILOAD 2
    ILOAD 4
    INVOKESTATIC GameKt.auraColor (ZIZ)Ljava/lang/String;
    ASTORE 6
   L7
    LINENUMBER 11 L7
    ILOAD 2
    ILOAD 3
    INVOKESTATIC GameKt.formatHealthStatus (IZ)Ljava/lang/String;
    ASTORE 7
   L8
    LINENUMBER 13 L8
    ALOAD 6
    ILOAD 3
    ALOAD 1
    ALOAD 7
    INVOKESTATIC GameKt.printPlayerStatus (Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V
   L9
    LINENUMBER 15 L9
    ILOAD 5
    BIPUSH 120
    INVOKESTATIC GameKt.castFireball (I)I
    IADD
    ISTORE 5
   L10
    LINENUMBER 17 L10
    ILOAD 5
    INVOKESTATIC GameKt.printInebriationStatus (I)V
   L11
    LINENUMBER 18 L11
    RETURN
   L12
    LOCALVARIABLE healthStatus Ljava/lang/String; L8 L12 7
    LOCALVARIABLE auraColor Ljava/lang/String; L7 L12 6
    LOCALVARIABLE inebriation I L6 L12 5
    LOCALVARIABLE isImmortal Z L5 L12 4
    LOCALVARIABLE isBlessed Z L4 L12 3
    LOCALVARIABLE healthPoints I L3 L12 2
    LOCALVARIABLE name Ljava/lang/String; L2 L12 1
    LOCALVARIABLE args [Ljava/lang/String; L0 L12 0
    MAXSTACK = 4
    MAXLOCALS = 8

参考