diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt index f7f850cff27..7a703da2802 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt @@ -45,7 +45,7 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter import org.jetbrains.org.objectweb.asm.tree.analysis.Value /** - * @see FlexibleMethodAnalyzer + * @see org.jetbrains.kotlin.codegen.optimization.fixStack.HackedFixStackMethodAnalyzerBase */ @Suppress("DuplicatedCode") open class FastMethodAnalyzer( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt index fddcbe7fb30..d1c9d875a23 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt @@ -20,7 +20,6 @@ import com.intellij.util.containers.Stack import org.jetbrains.kotlin.codegen.inline.isAfterInlineMarker import org.jetbrains.kotlin.codegen.inline.isBeforeInlineMarker import org.jetbrains.kotlin.codegen.inline.isMarkedReturn -import org.jetbrains.kotlin.codegen.optimization.common.FlexibleMethodAnalyzer import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.org.objectweb.asm.Opcodes @@ -93,7 +92,7 @@ internal class FixStackAnalyzer( private val analyzer = InternalAnalyzer(owner) private inner class InternalAnalyzer(owner: String) : - FlexibleMethodAnalyzer(owner, method, FixStackInterpreter()) { + HackedFixStackMethodAnalyzerBase(owner, method, FixStackInterpreter()) { val spilledStacks = hashMapOf>() var maxExtraStackSize = 0; private set diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FlexibleMethodAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/HackedFixStackMethodAnalyzerBase.kt similarity index 70% rename from compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FlexibleMethodAnalyzer.kt rename to compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/HackedFixStackMethodAnalyzerBase.kt index 5b0e567d941..7338470b82f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FlexibleMethodAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/HackedFixStackMethodAnalyzerBase.kt @@ -1,50 +1,9 @@ /* - * Copyright 2010-2015 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. - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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 +package org.jetbrains.kotlin.codegen.optimization.fixStack import org.jetbrains.kotlin.codegen.inline.insnText import org.jetbrains.org.objectweb.asm.Opcodes @@ -56,15 +15,10 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter import org.jetbrains.org.objectweb.asm.tree.analysis.Value /** - * This class is a modified version of `org.objectweb.asm.tree.analysis.Analyzer` - * - * @see FastMethodAnalyzer - * - * @author Eric Bruneton - * @author Dmitry Petrov + * @see org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer */ @Suppress("DuplicatedCode") -open class FlexibleMethodAnalyzer( +internal open class HackedFixStackMethodAnalyzerBase( private val owner: String, val method: MethodNode, protected val interpreter: Interpreter @@ -72,7 +26,7 @@ open class FlexibleMethodAnalyzer( protected val insnsArray: Array = method.instructions.toArray() private val nInsns = insnsArray.size - val frames: Array?> = arrayOfNulls(nInsns) + private val frames: Array?> = arrayOfNulls(nInsns) private val handlers: Array?> = arrayOfNulls(nInsns) private val queued = BooleanArray(nInsns) @@ -92,7 +46,7 @@ open class FlexibleMethodAnalyzer( checkAssertions() - computeExceptionHandlersForEachInsn() + computeExceptionEdges() initSinglePredBlocks() @@ -136,7 +90,7 @@ open class FlexibleMethodAnalyzer( handler.init(f) handler.clearStack() handler.push(interpreter.newValue(exnType)) - mergeControlFlowEdge(insn, jump, handler) + mergeControlFlowEdge(jump, handler) } } @@ -281,7 +235,7 @@ open class FlexibleMethodAnalyzer( private fun processControlFlowEdge(current: Frame, insn: Int, jump: Int) { if (visitControlFlowEdge(insn, jump)) { - mergeControlFlowEdge(insn, jump, current) + mergeControlFlowEdge(jump, current) } } @@ -302,44 +256,31 @@ open class FlexibleMethodAnalyzer( while (local < m.maxLocals) { current.setLocal(local++, interpreter.newValue(null)) } - mergeControlFlowEdge(0, 0, current) + mergeControlFlowEdge(0, current) } - private fun computeExceptionHandlersForEachInsn() { + private fun computeExceptionEdges() { for (tcb in method.tryCatchBlocks) { - val begin = tcb.start.indexOf() - val end = tcb.end.indexOf() - for (j in begin until end) { - val insn = insnsArray[j] - if (!insn.isMeaningful) continue - var insnHandlers: MutableList? = handlers[j] - if (insnHandlers == null) { - insnHandlers = ArrayList() - handlers[j] = insnHandlers - } - insnHandlers.add(tcb) + // Don't have to visit same exception handler multiple times - we care only about stack state at TCB start. + val start = tcb.start.indexOf() + var insnHandlers: MutableList? = handlers[start] + if (insnHandlers == null) { + insnHandlers = ArrayList() + handlers[start] = insnHandlers } + insnHandlers.add(tcb) } } - private fun mergeControlFlowEdge(src: Int, dest: Int, frame: Frame) { - val oldFrame = frames[dest] - val changes = when { - oldFrame == null -> { - frames[dest] = newFrame(frame.locals, frame.maxStackSize).apply { init(frame) } - true + private fun mergeControlFlowEdge(dest: Int, frame: Frame) { + val destFrame = frames[dest] + if (destFrame == null) { + // Don't have to visit same instruction multiple times - we care only about "initial" stack state. + frames[dest] = newFrame(frame.locals, frame.maxStackSize).apply { init(frame) } + if (!queued[dest]) { + queued[dest] = true + queue[top++] = dest } - dest == src + 1 && singlePredBlock[src] == singlePredBlock[dest] -> { - // Forward jump within a single predecessor block, no need to merge. - oldFrame.init(frame) - true - } - else -> - oldFrame.merge(frame, interpreter) - } - if (changes && !queued[dest]) { - queued[dest] = true - queue[top++] = dest } } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/doWhileWithInline.kt b/compiler/testData/codegen/box/coroutines/controlFlow/doWhileWithInline.kt index 48939642d0c..dd1f9cb57ba 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/doWhileWithInline.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/doWhileWithInline.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM // WITH_RUNTIME // WITH_COROUTINES // KT-27830