[JVM] Fix the nop removal optimization.
Never remove a nop if that would cause a line number to move across a local lifetime boundary. This fixes KT-42725.
This commit is contained in:
+16
-23
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.findNextOrNull
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
@@ -53,41 +52,35 @@ class RedundantNopsCleanupMethodTransformer : MethodTransformer() {
|
||||
}
|
||||
|
||||
private fun recordNopsRequiredForDebugger(methodNode: MethodNode, requiredNops: MutableSet<AbstractInsnNode>) {
|
||||
// We two subsets of labels that are "special" for the debugger:
|
||||
// We consider two subsets of labels that are special for the debugger:
|
||||
//
|
||||
// 1) Labels for line numbers.
|
||||
// 2) Labels for observable local variables lifetimes.
|
||||
// NB this includes synthetic variables denoting inlined function bodies and arguments
|
||||
// (see JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION, JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT).
|
||||
//
|
||||
// If we enumerate labels in a given subset in order of occurrence in the method code:
|
||||
// L[0], L[1], ..., L[n-1], L[n]
|
||||
// then for each k, 1 <= k <= n-1:
|
||||
// an instruction interval I[k] = [L[k]; L[k+1]) should contain at least one bytecode instruction (which can be a NOP).
|
||||
|
||||
for (insn in methodNode.instructions) {
|
||||
if (insn is LineNumberNode) {
|
||||
val nextLineNumber = insn.findNextOrNull { it is LineNumberNode && it.line != insn.line }
|
||||
requiredNops.addIfNotNull(getRequiredNopInRange(insn, nextLineNumber))
|
||||
}
|
||||
}
|
||||
|
||||
val localVariableLabels = run {
|
||||
val labels = hashSetOf<LabelNode>().apply {
|
||||
// We must not remove nops if that leads to a line number having no instructions before the next line number
|
||||
// or a linenumber crossing a local variable lifetime boundary.
|
||||
//
|
||||
// We enumerate all special labels, and make sure to leave nops if they are the only real
|
||||
// instruction between a line number label and any other special label.
|
||||
val specialLabels = run {
|
||||
val localVarLables = hashSetOf<LabelNode>().apply {
|
||||
for (localVariable in methodNode.localVariables) {
|
||||
add(localVariable.start)
|
||||
add(localVariable.end)
|
||||
}
|
||||
}
|
||||
|
||||
methodNode.instructions.toArray().filter { labels.contains(it) }
|
||||
methodNode.instructions.toArray().filter { localVarLables.contains(it) || it is LineNumberNode }
|
||||
}
|
||||
|
||||
|
||||
for (i in 0..localVariableLabels.size - 2) {
|
||||
val begin = localVariableLabels[i]
|
||||
val end = localVariableLabels[i + 1]
|
||||
if (InsnSequence(begin, end).any { it in requiredNops }) continue
|
||||
requiredNops.addIfNotNull(getRequiredNopInRange(begin, end))
|
||||
for (i in 0..specialLabels.size - 2) {
|
||||
val begin = specialLabels[i]
|
||||
val end = specialLabels[i + 1]
|
||||
if (begin is LineNumberNode) {
|
||||
requiredNops.addIfNotNull(getRequiredNopInRange(begin, end))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -23,4 +23,4 @@ fun simpleFunVoid(f: () -> Unit): Unit {
|
||||
return f()
|
||||
}
|
||||
|
||||
// 3 NOP
|
||||
// 0 NOP
|
||||
|
||||
Vendored
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
LineBreakpoint created at stepOverInlinedLambdaStdlib.kt:5
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
|
||||
@@ -48,7 +48,6 @@ org.jetbrains.kotlin.util.KotlinVersionsTest.testVersionsAreConsistent, KT-35567
|
||||
org.jetbrains.kotlin.jvm.compiler.CompileKotlinAgainstJavaTestGenerated.WithAPT.testClassWithTypeParameter, KT-36448,,
|
||||
org.jetbrains.kotlin.jvm.compiler.CompileKotlinAgainstJavaTestGenerated.WithoutAPT.testClassWithTypeParameter, KT-36448,,
|
||||
org.jetbrains.kotlin.idea.debugger.test.AsyncStackTraceTestGenerated.testAsyncLambdas, redesign test AsyncStackTraces,,
|
||||
org.jetbrains.kotlin.idea.debugger.test.KotlinSteppingTestGenerated.StepOver.testStepOverInlinedLambdaStdlib, fails after advancing bootstrap KT-37879,,
|
||||
org.jetbrains.kotlin.incremental.IncrementalJsKlibCompilerRunnerTestGenerated.ClassHierarchyAffected.testMethodRemoved, full fledged FO in klib required,,
|
||||
org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.ConvertToAnonymousObject.testHasConcreateMember2, Unprocessed,,
|
||||
org.jetbrains.uast.test.kotlin.KotlinUastTypesTest.testEa101715, Unprocessed,,
|
||||
@@ -83,4 +82,4 @@ org.jetbrains.kotlin.asJava.classes.UltraLightClassSanityTestGenerated.testAnnot
|
||||
org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.Facades.testSingleJvmClassName, Invalid behavior of old lightclasses in common tests,,
|
||||
org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.CompilationErrors.testActualTypeAliasCustomJvmPackageName, Invalid behavior of old lightclasses in common tests,,
|
||||
org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.CompilationErrors.testJvmPackageName, Invalid behavior of old lightclasses in common tests,,
|
||||
org.jetbrains.uast.test.kotlin.SimpleKotlinRenderLogTest.testReceiverFun, Analysing of facade annotation with receiver site is broken (connected with KT-40403),,
|
||||
org.jetbrains.uast.test.kotlin.SimpleKotlinRenderLogTest.testReceiverFun, Analysing of facade annotation with receiver site is broken (connected with KT-40403),,
|
||||
|
||||
|
Reference in New Issue
Block a user