kotlinbytecode

Why Kotlin compiler inserts additional $i$f variable to inline functions?


When you compile following Kotlin code:

inline fun hello(s: Int) {
    println("Hi")
}

You get this bytecode:

public final static hello(I)V
 L0
  ICONST_0
  ISTORE 1
 L1
  LINENUMBER 6 L1
  LDC "Hi"
  GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
  SWAP
  INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
 L2
  LINENUMBER 7 L2
  RETURN
 L3
  LOCALVARIABLE $i$f$hello I L1 L3 1
  LOCALVARIABLE s I L0 L3 0
  MAXSTACK = 2
  MAXLOCALS = 2

As you can see LOCALVARIABLE $i$f$hello I L1 L3 1 Kotlin creates a variable $i$f$hello for some reason and inserts it at the beginning L0 of the function with a value of 0 (boolean false probably). When you remove inline modifier the variable also disappears. The variable is never used. Why does it do it?


Solution

  • This is explained by Ilmir Usmanov here in KT-31949:

    These booleans are used by debugger to determine whether we are inside inline function/lambda or not. [...] you will variables like $i$f$<functionName> and $i$a$<functionName> in LVT. The value of these variables is not important (always false, although it can be changed in the future), but range of these variables is what the debugger is looking at. If we are inside $i$f... range, we are inside inline function, if we are inside $i$a... range, we are inside inline lambda.

    So these extra variables will also get inlined into the caller, and their ranges (the L1 L3 part in the bytecode, meaning line 1 to line 3), will get changed accordingly to match the line numbers in the caller. I think they technically could have generated this variable on the caller's side only, but generating it in the inline function is probably simpler.