Kotlin 编译器:字节码中的 `nop`

Kotlin Compiler: `nop`s in bytecode

我正在检查 kotlinc 捕获 lambda 的字节码。并试图理解生成的字节码具有 nop 指令的原因。

kotlinc -jvm-target 1.6 .

private inline fun lambdaCapturing(f: () -> Int): Int = f()

fun main(args: Array<String>) {
    lambdaCapturing { 42 }
}

结果我得到

public final class x.y.z.LambdaCaptKt {
  private static final int lambdaCapturing(kotlin.jvm.functions.Function0<java.lang.Integer>);
    Code:
       0: ldc           #8                  // int 0
       2: istore_1
       3: aload_0
       4: invokeinterface #14,  1           // InterfaceMethod kotlin/jvm/functions/Function0.invoke:()Ljava/lang/Object;
       9: checkcast     #16                 // class java/lang/Number
      12: invokevirtual #20                 // Method java/lang/Number.intValue:()I
      15: ireturn

  public static final void main(java.lang.String[]);
    Code:
       0: aload_0
       1: ldc           #29                 // String args
       3: invokestatic  #35                 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
       6: iconst_0
       7: istore_1
       8: iconst_0
       9: istore_2
      10: nop
      11: nop
      12: nop
      13: return
}

在 main 函数中有几个 nop 指令。

如果我用 -Xno-optimize 编译相同的代码片段,main 函数将类似于

public static final void main(java.lang.String[]);
    Code:
       0: aload_0
       1: ldc           #29                 // String args
       3: invokestatic  #35                 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
       6: nop
       7: iconst_0
       8: istore_1
       9: nop
      10: iconst_0
      11: istore_2
      12: bipush        10
      14: nop
      15: goto          18
      18: invokestatic  #41                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      21: checkcast     #16                 // class java/lang/Number
      24: invokevirtual #20                 // Method java/lang/Number.intValue:()I
      27: nop
      28: goto          31
      31: pop
      32: return

还有nop

  1. 未优化代码中有 nop 的原因是什么? (调试信息/...)
  2. 是否有任何理由在优化代码中包含 nop

Kotlin 编译器生成的字节码中出现 nop 的原因是调试器可能会在函数或 [= 的最后一个语句之后的右大括号处放置断点11=]-子句和其他子句,并使跳转到那些位置成为可能。这样做需要字节码中存在一条指令,该指令也标有行号。

一些 nop 如果它们是冗余的,例如当最后一条语句指令之后已经有一个有效指令时,它们将被优化掉。