I'm checking kotlinc
bytecode of capturing lambdas. And trying to understand the reason why resulting bytecode has nop
instructions.
kotlinc -jvm-target 1.6 .
private inline fun lambdaCapturing(f: () -> Int): Int = f()
fun main(args: Array<String>) {
lambdaCapturing { 42 }
}
As a result I'm getting
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
}
with several nop
instructions in main function.
If I will compile the same code snippet with -Xno-optimize
, main
function will look like
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
There are nop
s as well.
nop
s in non-optimised code? (debug info/...)nop
s in optimized code?The reason for nop
s in the bytecode that the Kotlin compiler emits is the possibility for the debugger to put a breakpoint at the closing brace, i.e. after the last statement, of a function or an if
-clause and other clauses, and to make it possible to step to those locations. Doing that requires an instruction present in the bytecode that is also marked with the line number.
Some nop
s are then optimized away if they are redundant, such as when there's already a valid instruction following the last statement instructions.