All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackAnalyzer.kt Maven / Gradle / Ivy

There is a newer version: 2.1.20-RC3
Show newest version
/*
 * 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.
 */

package org.jetbrains.kotlin.codegen.optimization.fixStack

import com.intellij.util.SmartList
import com.intellij.util.containers.Stack
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
import java.util.*

internal class FixStackAnalyzer(
        owner: String,
        methodNode: MethodNode,
        val context: FixStackContext
) : MethodAnalyzer(owner, methodNode, OptimizationBasicInterpreter()) {
    val savedStacks = hashMapOf>()
    var maxExtraStackSize = 0; private set

    override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
        val insnNode = instructions[insn]
        return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
    }

    override fun newFrame(nLocals: Int, nStack: Int): Frame =
            FixStackFrame(nLocals, nStack)

    private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)

    inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame(nLocals, nStack) {
        val extraStack = Stack()

        override fun init(src: Frame): Frame {
            extraStack.clear()
            extraStack.addAll((src as FixStackFrame).extraStack)
            return super.init(src)
        }

        override fun clearStack() {
            extraStack.clear()
            super.clearStack()
        }

        override fun execute(insn: AbstractInsnNode, interpreter: Interpreter) {
            when {
                PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
                    executeSaveStackBeforeTry(insn)
                PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.isa(insn) ->
                    executeRestoreStackInTryCatch(insn)
                InlineCodegenUtil.isBeforeInlineMarker(insn) ->
                    executeBeforeInlineCallMarker(insn)
                InlineCodegenUtil.isAfterInlineMarker(insn) ->
                    executeAfterInlineCallMarker(insn)
                InlineCodegenUtil.isMarkedReturn(insn) -> {
                    // KT-9644: might throw "Incompatible return type" on non-local return, in fact we don't care.
                    if (insn.opcode == Opcodes.RETURN) return
                }
            }

            super.execute(insn, interpreter)
        }

        fun getStackContent(): List {
            val savedStack = arrayListOf()
            IntRange(0, super.getStackSize() - 1).mapTo(savedStack) { super.getStack(it) }
            savedStack.addAll(extraStack)
            return savedStack
        }

        override fun push(value: BasicValue) {
            if (super.getStackSize() < maxStackSize) {
                super.push(value)
            }
            else {
                extraStack.add(value)
                maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size)
            }
        }

        fun pushAll(values: Collection) {
            values.forEach { push(it) }
        }

        override fun pop(): BasicValue {
            if (extraStack.isNotEmpty()) {
                return extraStack.pop()
            }
            else {
                return super.pop()
            }
        }

        override fun getStack(i: Int): BasicValue {
            if (i < super.getMaxStackSize()) {
                return super.getStack(i)
            }
            else {
                return extraStack[i - maxStackSize]
            }
        }
    }

    private fun FixStackFrame.executeBeforeInlineCallMarker(insn: AbstractInsnNode) {
        saveStackAndClear(insn)
    }

    private fun FixStackFrame.saveStackAndClear(insn: AbstractInsnNode) {
        val savedValues = getStackContent()
        savedStacks[insn] = savedValues
        clearStack()
    }

    private fun FixStackFrame.executeAfterInlineCallMarker(insn: AbstractInsnNode) {
        val beforeInlineMarker = context.openingInlineMethodMarker[insn]
        if (stackSize > 0) {
            val returnValue = pop()
            clearStack()
            val savedValues = savedStacks[beforeInlineMarker]
            pushAll(savedValues!!)
            push(returnValue)
        }
        else {
            val savedValues = savedStacks[beforeInlineMarker]
            pushAll(savedValues!!)
        }
    }

    private fun FixStackFrame.executeRestoreStackInTryCatch(insn: AbstractInsnNode) {
        val saveNode = context.saveStackMarkerForRestoreMarker[insn]
        val savedValues = savedStacks.getOrElse(saveNode!!) {
            throw AssertionError("${indexOf(insn)}: Restore stack is unavailable for ${indexOf(saveNode)}")
        }
        pushAll(savedValues)
    }

    private fun FixStackFrame.executeSaveStackBeforeTry(insn: AbstractInsnNode) {
        saveStackAndClear(insn)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy