[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:
Mads Ager
2020-10-16 14:52:26 +02:00
committed by Dmitry Petrov
parent 69127445a3
commit 0505bd958a
4 changed files with 18 additions and 27 deletions
@@ -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))
}
}
}
@@ -23,4 +23,4 @@ fun simpleFunVoid(f: () -> Unit): Unit {
return f()
}
// 3 NOP
// 0 NOP
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at stepOverInlinedLambdaStdlib.kt:5
Run Java
Connected to the target VM
+1 -2
View File
@@ -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),,
1 Test key Issue State (optional: MUTE or FAIL) Status (optional: FLAKY)
48 org.jetbrains.kotlin.jvm.compiler.CompileKotlinAgainstJavaTestGenerated.WithAPT.testClassWithTypeParameter KT-36448
49 org.jetbrains.kotlin.jvm.compiler.CompileKotlinAgainstJavaTestGenerated.WithoutAPT.testClassWithTypeParameter KT-36448
50 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
51 org.jetbrains.kotlin.incremental.IncrementalJsKlibCompilerRunnerTestGenerated.ClassHierarchyAffected.testMethodRemoved full fledged FO in klib required
52 org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.ConvertToAnonymousObject.testHasConcreateMember2 Unprocessed
53 org.jetbrains.uast.test.kotlin.KotlinUastTypesTest.testEa101715 Unprocessed
82 org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.Facades.testSingleJvmClassName Invalid behavior of old lightclasses in common tests
83 org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.CompilationErrors.testActualTypeAliasCustomJvmPackageName Invalid behavior of old lightclasses in common tests
84 org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.CompilationErrors.testJvmPackageName Invalid behavior of old lightclasses in common tests
85 org.jetbrains.uast.test.kotlin.SimpleKotlinRenderLogTest.testReceiverFun Analysing of facade annotation with receiver site is broken (connected with KT-40403)