diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index 4ec1d3aea8f..c6af4cd084e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -1347,6 +1347,27 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction: } } + // Merge consequent LVT records, otherwise, atomicfu goes crazy (KT-47749) + val toRemove = arrayListOf() + val sortedLVT = method.localVariables.sortedBy { method.instructions.indexOf(it.start) } + for (i in sortedLVT.indices) { + var endIndex = method.instructions.indexOf(sortedLVT[i].end) + for (j in (i + 1) until sortedLVT.size) { + val startIndex = method.instructions.indexOf(sortedLVT[j].start) + if (endIndex < startIndex) break + if (endIndex != startIndex || + sortedLVT[i].index != sortedLVT[j].index || + sortedLVT[i].name != sortedLVT[j].name || + sortedLVT[i].desc != sortedLVT[j].desc + ) continue + sortedLVT[i].end = sortedLVT[j].end + endIndex = method.instructions.indexOf(sortedLVT[j].end) + toRemove += sortedLVT[j] + } + } + + method.localVariables.removeAll(toRemove) + for (variable in oldLvt) { // $continuation and $result are dead, but they are used by debugger, as well as fake inliner variables // For example, $continuation is used to create async stack trace diff --git a/compiler/testData/codegen/bytecodeText/coroutines/mergeLvt.kt b/compiler/testData/codegen/bytecodeText/coroutines/mergeLvt.kt index 4ead75c2b6a..71f61f61bb4 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/mergeLvt.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/mergeLvt.kt @@ -22,4 +22,4 @@ class MyBlockingAdapter() { } } -// 2 LOCALVARIABLE \$this\$extensionFun\$iv\$iv LAtomicInt; +// 1 LOCALVARIABLE \$this\$extensionFun\$iv\$iv LAtomicInt;