diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt index a4d34f8bd3e..292076ba75a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.codegen.optimization.common @@ -40,6 +29,10 @@ class VariableLivenessFrame(val maxLocals: Int) : VarFrame { val typeAnnotatedFrames = MethodTransformer.analyze("fake", node, OptimizationBasicInterpreter()) + val visibleByDebuggerVariables = analyzeVisibleByDebuggerVariables(node, typeAnnotatedFrames) return analyze(node, object : BackwardAnalysisInterpreter { override fun newFrame(maxLocals: Int) = VariableLivenessFrame(maxLocals) override fun def(frame: VariableLivenessFrame, insn: AbstractInsnNode) = defVar(frame, insn) override fun use(frame: VariableLivenessFrame, insn: AbstractInsnNode) = - useVar(frame, insn, node, typeAnnotatedFrames[node.instructions.indexOf(insn)]) - + useVar(frame, insn, node, visibleByDebuggerVariables[node.instructions.indexOf(insn)]) }) } +private fun analyzeVisibleByDebuggerVariables( + node: MethodNode, + typeAnnotatedFrames: Array?> +): Array { + val res = Array(node.instructions.size()) { BitSet(node.maxLocals) } + for (local in node.localVariables) { + if (local.name.isInvisibleDebuggerVariable()) continue + for (index in node.instructions.indexOf(local.start) until node.instructions.indexOf(local.end)) { + if (Type.getType(local.desc).sort == typeAnnotatedFrames[index]?.getLocal(local.index)?.type?.sort) { + res[index].set(local.index) + } + } + } + return res +} + private fun defVar(frame: VariableLivenessFrame, insn: AbstractInsnNode) { if (insn is VarInsnNode && insn.isStoreOperation()) { frame.markDead(insn.`var`) @@ -75,18 +84,9 @@ private fun useVar( frame: VariableLivenessFrame, insn: AbstractInsnNode, node: MethodNode, - // May be null in case of dead code - typeAnnotatedFrame: Frame? + visibleByDebuggerVariables: BitSet ) { - val index = node.instructions.indexOf(insn) - node.localVariables.filter { - // Inliner fake variables, despite being present in LVT, are not read, thus are always dead - !it.name.isInvisibleDebuggerVariable() && - node.instructions.indexOf(it.start) < index && index < node.instructions.indexOf(it.end) && - Type.getType(it.desc).sort == typeAnnotatedFrame?.getLocal(it.index)?.type?.sort - }.forEach { - frame.markAlive(it.index) - } + frame.markAllAlive(visibleByDebuggerVariables) if (insn is VarInsnNode && insn.isLoadOperation()) { frame.markAlive(insn.`var`)