[JVM] Implement new inlined variable naming format

^KT-65478 fixed
This commit is contained in:
Nikita Nazarov
2023-09-18 16:27:46 +02:00
committed by Alexander Udalov
parent 9ea775cbed
commit 407448d8e3
104 changed files with 88125 additions and 92 deletions
+96
View File
@@ -0,0 +1,96 @@
## Introduction
The Kotlin debugger uses inline marker variables (`$i$f$...`, `$i$a$...`) that are produced by the Kotlin compiler
to handle stepping into/over/out of inline functions and lambdas and also to build inline stack traces. This scheme
does not work for dex code, where the same variable may be duplicated in different registers and where basic blocks can be reordered.
This leads to many debugging issues on Android from inconsistent locals in the variables view to bad stepping in inline functions.
## **New format description**
The new format affects 3 types of variables:
1. Inline function marker variables
`$i$f$name\[scope number]\[call site line number]`
2. Inline lambda marker variables
`$i$a$name\[scope number]\[call site line number]\[surrounding scope number]`
3. Local variables from inline functions or lambdas
`name\[scope number]`
Lets break it down on the following example:
```
fun main() {
val inMain = 0
g(0) {
val inLambdaG1 = 1 // breakpoint 1
h()
g(4) {
val inLambdaG2 = 2 // breakpoint 2
}
}
}
inline fun g(gParam: Int, block: () -> Unit) {
block()
}
inline fun h() {
val inH = 3
i()
}
inline fun i() {
val inI = 4
}
```
How LVT used to look:
```
LocalVariableTable:
Start Length Slot Name Signature
20 4 7 $i$f$i I
23 1 8 inI$iv$iv I
14 11 5 $i$f$h I
17 8 6 inH$iv I
34 4 7 $i$a$-g-SandboxKt$main$1$1 I
37 1 8 inLambdaG2 I
31 9 6 $i$f$g I
28 12 5 gParam$iv I
8 33 3 $i$a$-g-SandboxKt$main$1 I
11 30 4 inLambdaG1 I
6 37 2 $i$f$g I
4 39 1 gParam$iv I
2 42 0 inMain I
```
How LVT looks with the new format:
```
LocalVariableTable:
Start Length Slot Name Signature
20 4 7 $i$f$i\4\30 I
23 1 8 inI\4 I
14 11 5 $i$f$h\3\7 I
17 8 6 inH\3 I
34 4 7 $i$a$-g-SandboxKt$main$1$1\6\36\2 I
37 1 8 inLambdaG2\6 I
31 9 6 $i$f$g\5\8 I
28 12 5 gParam\5 I
8 33 3 $i$a$-g-SandboxKt$main$1\2\28\0 I
11 30 4 inLambdaG1\2 I
6 37 2 $i$f$g\1\5 I
4 39 1 gParam\1 I
2 42 0 inMain I
```
Previously the compiler added the `$iv` suffixes to distinguish locals that belong to different inline functions.
Now we assign scope numbers to marker and local variables. Locals with a scope number belong to the function
which is represented by a marker variable with the same scope number.
Lets see how it works in our example:
* `$i$f$g\1\5` has scope number 1, as well as `gParam\1`.
* `$i$a$-g-SandboxKt$main$1\2\28\0` has scope number 2, as well as `inLambdaG1\2`. It also has a surrounding scope number equal to 0.
The scope number 0 belongs to the top frame, and basically means that the `inMain` variable should be included in the variables view
when we stop at breakpoint 1.
* `$i$f$h\3\7` has scope number 3, as well as `inH\3`.
* `$i$f$i\4\30` has scope number 4, as well as `inI\4`.
* `$i$f$g\5\8` has scope number 5, as well as `gParam\5`.
* `$i$a$-g-SandboxKt$main$1$1\6\36\2` has scope number 6, as well as `inLambdaG2\6`, and surrounding scope number 2, which means that
we should include variables that are visible in scope 2 when we stop at breakpoint 2. In our example these variables are `inMain`
and `inLambdaG1\2`.