Putting them in the local variable table means that the debugger
needs to have special handling for parameters with specific names.
That forces us to generate mangled names for these.
Instead of also implementing the name mangling for FIR, this
change gets rid of the parameters from the LVT instead.
Their call sites are all in the same file, so we can check whether the
declarations used in the inline function are accessible from all the
places where it will be inlined.
#KT-48736 Fixed
This ensures that the debugger always has a bytecode offset for
the line number of a break/continue so that you step there and
so that you can set breakpoints there.
The `nop` instruction is optimized out if it has no line number
information.
^KT-46450 Fixed
This avoids an extra call to 'analyze', which is rather costly.
Update debugger testData: Constant condition
elimination now performs DCE more consistently.
CoroutineTransformermethodVisitor attempts to extend the ranges
of local variables in various situations. Probably in an attempt
to give a better debugging experience. However, all of these
range extensions lead to invalid local variable tables where
something is in the local variable table where nothing is in the
corresponding slot.
The code that extends variables to the next suspension point
instead of ending them when they are no longer live has issues
with loops. When resuming and reentering the loop, the locals
table will mention a local that we did not spill and which
is therefore not restored when resuming.
The code that extends local variable table entries if there
are no suspension points between two entries doesn't work
for code such as:
```
var s: String
if (suspendHere() == "OK") {
s = "OK"
} else {
s = "FAIL"
}
```
If the local variable ranges are collapsed into one, one of
the branches will have the local defined in the local variable
table before the slot is initialized.
For code such as:
```
try {
var y = "y"
for (i in 0 until 1) {
return y
}
} finally {
println("finally")
}
```
The local variables `y` and `i` ended up covering the finally block as
well in the debugger.
This change splits the range of the locals so that they do
not cover the finally block.
This change does not change the inliner to do similar transformations,
so the range of locals is still wrong win finally blocks when inlined
into an inline function. Added a failing test to that effect.
The coroutine transformation would leave locals in the local
variable table across the code that reloads local variables from
the continuation on reentry. However, when reentering the function
the local has no value until after the reloads from the
continuation.
This change splits the locals in the local variable table to
avoid such uninitialized locals. A local alive across a
suspension point has its range split in two. One that goes
from the original start to the state label for the restart
after the suspension. The other goes from after the local
has been reloaded from the continuation until the previous
end of the local.
This solves no immediate deficiency, but is a to-do that arose as part
of an ongoing effort to port the old, slightly too restrictive
checkLocalVariableTable tests to the more "functional" debugger
infrastructure.
This just shaves a little bit of overhead off the test expectations
and couples them less tightly to the specifics of the test
infrastructure.
This change improves the debugging experience around local functions
on the IR backend. The changes include moving old
checkLocalVariablesTable (cLVT) tests to the new stepping/local variable
infrastructure in order to refine the tests and further define the
behavior of the two JVM backends, and their differences.
The primary ported test case is cLVT/localFun.kt that documents the
discrepancy in implementation strategy for local functions on the two
backends. The old backend implements local functions as lambdas
assigned to a local variable while the IR backend lifts them out as
static funtions on the surrounding class. The discrepancies and their
consequences are documented in bytecodeListing, idea-stepping,
localVariableTable and debugStepping tests.
The only _code change_ is disabling the captured variable name
mangling for captured variables on the IR backend. Captured variables
are passed as arguments to the static function, so in the debugger,
they really just are local variables. For them to show properly in the
debugger and be detectable by evaluate expression, they simply need no
mangling.
Finally, this change cleans 3 redundant cLVT tests, copyFunction.kt
and destructuringInlineLambda.kt and destructuringInFor.kt, that are
all covered in the new suite. The stepping behavior needs to be made
precise around for loops, but that is an entirely seperate issue.
Reveals discrepancy in LVT presence on lambda implementations on the
old and new backend.
The generated code in the constructors of Suspend Lambda objects is
identical, but the IR backend generates an LVT with the constructor
parameters.
The user has to be very insistent to see this ("for step into" +
disabling "Show only kotlin variables"), but it is an observable
difference.
The existing backend restores LVs and parameters from the suspend lambda
fields used for spilling between suspension points, hence they are
visible in the debugger as local variables, plain and simple.
This PR introduces the same pattern to the IR backend, to bring the
debugging experience in line with the existing backend.
Both backends are still at the mercy of the liveness analysis
performed in the coroutine transformer where a liveness analysis
minimizes live ranges of entries in the LVT. E.g. an unused parameter
will be dropped entirely.
Adjusted existing test expectations accounting for the differences in
LV behavior.
The debug experiece of destructuring patterns in lambdas is different
across the two backends due to the IR backend moving local variables
to fields.
However, since the destructuring variable is never actually visible in
the debugger (no linenumbers in the live range of the variable), and
the variable is never used for anything other than hiding it from the
debugger, we propose that it is not actually necessary to include it
in the LVT (and in fact, could be left out of the LVT on the old
backend).
This commit unifies the expectation format between the stepping and
LVT tests in the new debugging test harness.
Furthermore, it introduces a compression of runs of locations without
linenumbers. These default to showing as bytecode offsets from
previous line number, which overspecifies the tests: the bytecodes
chosen should not be constrained by a debugging step test.
This commit enables the execution of suspend box tests in a separate
test. It's a QoL improvement in the existing bb tests but, motivating
these changes, enables the new debugger stepping tests to step
coroutine code.
This is the first step in a push to improve the test coverage of the
IR debugging experience. This commit improves on the sketch of local
variable table tests built on the new debugger stepping
infrastructure. As improvements on the existing
checkLocalVariableTableTest they:
- don't overspecify codegen strategy: no hard requirements on slots.
- test the observed lifespans of locals by stepping through code.
Ultimately this should enable us to bring over all existing tests for
improved coverage of both old and new JVM backends.
WIP list:
- Gracefully handle absent LVT: treat as empty Add type of local and
- type of value stored there to expectations Print values in local
- slots if primitive or java.lang.String Enable specifying
- expectations per backend Gracefully handle absent box methods
- Gracefully handle null values in slots of reference type
- Port a first LVT test
The current backend does that for some bridges. We do it consistently
for all bridges.
The line number used differs. For the JVM_IR backend, we use the
line number of the class to which the bridge is added. For the
JVM backend, that does not appear to be the case for bridges
in lambdas. I prefer the line number for a lambda invoke bridge
to be the line for the lambda instead os some surrounding class.
The JVM BE inlines calls to the underlying function in a $default stub
verbatim, e.g., without renaming LVT entries or regenerating anonymous
objects. This commit introduces the same behavior in the JVM IR BE.
Fixes KT-36769.
Reimplement the same hacky approach used in the old backend (see
cc2fe6b0c6).
Previously, the debugger incorrectly stepped into Collections.kt on
"step over" inline function calls from stdlib like 'any'.
Since `if` and `when` expressions are represented the same way in IR,
the behavior is fixed for both of them. It's not the case in the old JVM
backend, where stepping over `when` conditions still suffers from the
same problem, which the newly added test checks.
Loads of temporary variables that contain constants are replaced
with a copy of the constant. This avoids locals loads and stores.
However, the copy of the constant needs to have the offset of
the load and not of the original constant.
Fixes KT-41963.
JVM_IR has consistent stepping behavior for secondary constructors
and init blocks. This change fixes the expectations for tests that
expect the less consistent JVM backend behavior.