
org.jetbrains.kotlin.cfg.pseudocode.ControlFlowInstructionsGenerator.kt Maven / Gradle / Ivy
/*
* 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.cfg.pseudocode
import com.intellij.util.containers.Stack
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cfg.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.LexicalScope
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.*
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import java.util.*
class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
private var builder: ControlFlowBuilder? = null
override val delegateBuilder: ControlFlowBuilder
get() = builder ?: throw AssertionError("Builder stack is empty in ControlFlowInstructionsGenerator!")
private val loopInfo = Stack()
private val lexicalScopes = Stack()
private val elementToBlockInfo = HashMap()
private var labelCount = 0
private val builders = Stack()
private val allBlocks = Stack()
private fun pushBuilder(scopingElement: KtElement, subroutine: KtElement) {
val worker = ControlFlowInstructionsGeneratorWorker(scopingElement, subroutine)
builders.push(worker)
builder = worker
}
private fun popBuilder(): ControlFlowInstructionsGeneratorWorker {
val worker = builders.pop()
if (!builders.isEmpty()) {
builder = builders.peek()
}
else {
builder = null
}
return worker
}
override fun enterSubroutine(subroutine: KtElement) {
val builder = builder
if (builder != null && subroutine is KtFunctionLiteral) {
pushBuilder(subroutine, builder.returnSubroutine)
}
else {
pushBuilder(subroutine, subroutine)
}
delegateBuilder.enterLexicalScope(subroutine)
delegateBuilder.enterSubroutine(subroutine)
}
override fun exitSubroutine(subroutine: KtElement): Pseudocode {
super.exitSubroutine(subroutine)
delegateBuilder.exitLexicalScope(subroutine)
val worker = popBuilder()
if (!builders.empty()) {
val builder = builders.peek()
builder.declareFunction(subroutine, worker.pseudocode)
}
return worker.pseudocode
}
private inner class ControlFlowInstructionsGeneratorWorker(scopingElement: KtElement, override val returnSubroutine: KtElement) : ControlFlowBuilder {
val pseudocode: PseudocodeImpl
private val error: Label
private val sink: Label
private val valueFactory = object : PseudoValueFactoryImpl() {
override fun newValue(element: KtElement?, instruction: InstructionWithValue?): PseudoValue {
val value = super.newValue(element, instruction)
if (element != null) {
bindValue(value, element)
}
return value
}
}
init {
this.pseudocode = PseudocodeImpl(scopingElement)
this.error = pseudocode.createLabel("error", null)
this.sink = pseudocode.createLabel("sink", null)
}
private fun add(instruction: Instruction) {
pseudocode.addInstruction(instruction)
}
override fun createUnboundLabel(): Label {
return pseudocode.createLabel("L" + labelCount++, null)
}
override fun createUnboundLabel(name: String): Label {
return pseudocode.createLabel("L" + labelCount++, name)
}
override fun enterLoop(expression: KtLoopExpression): LoopInfo {
val info = LoopInfo(
expression,
createUnboundLabel("loop entry point"),
createUnboundLabel("loop exit point"),
createUnboundLabel("body entry point"),
createUnboundLabel("body exit point"),
createUnboundLabel("condition entry point"))
bindLabel(info.entryPoint)
elementToBlockInfo.put(expression, info)
return info
}
override fun enterLoopBody(expression: KtLoopExpression) {
val info = elementToBlockInfo[expression] as LoopInfo
bindLabel(info.bodyEntryPoint)
loopInfo.push(info)
allBlocks.push(info)
}
override fun exitLoopBody(expression: KtLoopExpression) {
val info = loopInfo.pop()
elementToBlockInfo.remove(expression)
allBlocks.pop()
bindLabel(info.bodyExitPoint)
}
override val currentLoop: KtLoopExpression?
get() = if (loopInfo.empty()) null else loopInfo.peek().element
override fun enterSubroutine(subroutine: KtElement) {
val blockInfo = BreakableBlockInfo(
subroutine,
/* entry point */ createUnboundLabel(),
/* exit point */ createUnboundLabel())
elementToBlockInfo.put(subroutine, blockInfo)
allBlocks.push(blockInfo)
bindLabel(blockInfo.entryPoint)
add(SubroutineEnterInstruction(subroutine, currentScope))
}
override val currentSubroutine: KtElement
get() = pseudocode.correspondingElement
override fun getConditionEntryPoint(labelElement: KtElement): Label {
val blockInfo = elementToBlockInfo[labelElement]
assert(blockInfo is LoopInfo) { "expected LoopInfo for " + labelElement.text }
return (blockInfo as LoopInfo).conditionEntryPoint
}
override fun getExitPoint(labelElement: KtElement): Label? {
// It's quite possible to have null here, e.g. for non-local returns (see KT-10823)
return elementToBlockInfo[labelElement]?.exitPoint
}
private val currentScope: LexicalScope
get() = lexicalScopes.peek()
override fun enterLexicalScope(element: KtElement) {
val current = if (lexicalScopes.isEmpty()) null else currentScope
val scope = LexicalScope(current, element)
lexicalScopes.push(scope)
}
override fun exitLexicalScope(element: KtElement) {
val currentScope = currentScope
assert(currentScope.element === element) {
"Exit from not the current lexical scope.\n" +
"Current scope is for: " + currentScope.element + ".\n" +
"Exit from the scope for: " + element.text
}
lexicalScopes.pop()
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private fun handleJumpInsideTryFinally(jumpTarget: Label) {
val finallyBlocks = ArrayList()
for (i in allBlocks.indices.reversed()) {
val blockInfo = allBlocks[i]
if (blockInfo is BreakableBlockInfo) {
if (blockInfo.referablePoints.contains(jumpTarget) || jumpTarget === error) {
for (j in finallyBlocks.indices.reversed()) {
finallyBlocks[j].generateFinallyBlock()
}
break
}
}
else if (blockInfo is TryFinallyBlockInfo) {
finallyBlocks.add(blockInfo)
}
}
}
override fun exitSubroutine(subroutine: KtElement): Pseudocode {
getExitPoint(subroutine)?.let { bindLabel(it) }
pseudocode.addExitInstruction(SubroutineExitInstruction(subroutine, currentScope, false))
bindLabel(error)
pseudocode.addErrorInstruction(SubroutineExitInstruction(subroutine, currentScope, true))
bindLabel(sink)
pseudocode.addSinkInstruction(SubroutineSinkInstruction(subroutine, currentScope, ""))
elementToBlockInfo.remove(subroutine)
allBlocks.pop()
return pseudocode
}
override fun mark(element: KtElement) {
add(MarkInstruction(element, currentScope))
}
override fun getBoundValue(element: KtElement?): PseudoValue? {
return pseudocode.getElementValue(element)
}
override fun bindValue(value: PseudoValue, element: KtElement) {
pseudocode.bindElementToValue(element, value)
}
override fun newValue(element: KtElement?): PseudoValue {
return valueFactory.newValue(element, null)
}
override fun returnValue(returnExpression: KtExpression, returnValue: PseudoValue, subroutine: KtElement) {
val exitPoint = getExitPoint(subroutine) ?: return
handleJumpInsideTryFinally(exitPoint)
add(ReturnValueInstruction(returnExpression, currentScope, exitPoint, returnValue))
}
override fun returnNoValue(returnExpression: KtReturnExpression, subroutine: KtElement) {
val exitPoint = getExitPoint(subroutine) ?: return
handleJumpInsideTryFinally(exitPoint)
add(ReturnNoValueInstruction(returnExpression, currentScope, exitPoint))
}
override fun write(
assignment: KtElement,
lValue: KtElement,
rValue: PseudoValue,
target: AccessTarget,
receiverValues: Map) {
add(WriteValueInstruction(assignment, currentScope, target, receiverValues, lValue, rValue))
}
override fun declareParameter(parameter: KtParameter) {
add(VariableDeclarationInstruction(parameter, currentScope))
}
override fun declareVariable(property: KtVariableDeclaration) {
add(VariableDeclarationInstruction(property, currentScope))
}
override fun declareFunction(subroutine: KtElement, pseudocode: Pseudocode) {
add(LocalFunctionDeclarationInstruction(subroutine, pseudocode, currentScope))
}
override fun loadUnit(expression: KtExpression) {
add(LoadUnitValueInstruction(expression, currentScope))
}
override fun jump(label: Label, element: KtElement) {
handleJumpInsideTryFinally(label)
add(UnconditionalJumpInstruction(element, label, currentScope))
}
override fun jumpOnFalse(label: Label, element: KtElement, conditionValue: PseudoValue?) {
handleJumpInsideTryFinally(label)
add(ConditionalJumpInstruction(element, false, currentScope, label, conditionValue))
}
override fun jumpOnTrue(label: Label, element: KtElement, conditionValue: PseudoValue?) {
handleJumpInsideTryFinally(label)
add(ConditionalJumpInstruction(element, true, currentScope, label, conditionValue))
}
override fun bindLabel(label: Label) {
pseudocode.bindLabel(label)
}
override fun nondeterministicJump(label: Label, element: KtElement, inputValue: PseudoValue?) {
handleJumpInsideTryFinally(label)
add(NondeterministicJumpInstruction(element, listOf(label), currentScope, inputValue))
}
override fun nondeterministicJump(label: List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy