All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2019 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.fir.resolve.dfa.cfg
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
class ControlFlowGraph(val declaration: FirDeclaration?, val name: String, val kind: Kind) {
private var _nodes: MutableList> = mutableListOf()
val nodes: List>
get() = _nodes
internal fun addNode(node: CFGNode<*>) {
assertState(State.Building)
_nodes.add(node)
}
lateinit var enterNode: CFGNode<*>
internal set
lateinit var exitNode: CFGNode<*>
internal set
var owner: ControlFlowGraph? = null
private set
var state: State = State.Building
private set
private val _subGraphs: MutableList = mutableListOf()
val subGraphs: List get() = _subGraphs
internal fun complete() {
assertState(State.Building)
state = State.Completed
if (kind == Kind.Stub) return
val sortedNodes = orderNodes()
// TODO Fix this
// assert(sortedNodes.size == _nodes.size)
// for (node in _nodes) {
// assert(node in sortedNodes)
// }
_nodes.clear()
_nodes.addAll(sortedNodes)
}
internal fun addSubGraph(graph: ControlFlowGraph) {
assert(graph.owner == null) {
"SubGraph already has owner"
}
graph.owner = this
_subGraphs += graph
}
internal fun removeSubGraph(graph: ControlFlowGraph) {
assert(graph.owner == this)
_subGraphs.remove(graph)
graph.owner = null
CFGNode.removeAllIncomingEdges(graph.enterNode)
CFGNode.removeAllOutgoingEdges(graph.exitNode)
}
private fun assertState(state: State) {
assert(this.state == state) {
"This action can not be performed at $this state"
}
}
enum class State {
Building,
Completed;
}
enum class Kind(val withBody: Boolean) {
Function(withBody = true),
AnonymousFunction(withBody = true),
ClassInitializer(withBody = true),
PropertyInitializer(withBody = true),
TopLevel(withBody = false),
AnnotationCall(withBody = true),
DefaultArgument(withBody = false),
Stub(withBody = true)
}
}
enum class EdgeKind(
val usedInDfa: Boolean,
val usedInCfa: Boolean,
val isBack: Boolean,
val isDead: Boolean
) {
Forward(usedInDfa = true, usedInCfa = true, isBack = false, isDead = false),
DeadForward(usedInDfa = false, usedInCfa = true, isBack = false, isDead = true),
DfgForward(usedInDfa = true, usedInCfa = false, isBack = false, isDead = false),
CfgForward(usedInDfa = false, usedInCfa = true, isBack = false, isDead = false),
CfgBackward(usedInDfa = false, usedInCfa = true, isBack = true, isDead = false),
DeadBackward(usedInDfa = false, usedInCfa = true, isBack = true, isDead = true)
}
@OptIn(ExperimentalStdlibApi::class)
private fun ControlFlowGraph.orderNodes(): LinkedHashSet> {
val visitedNodes = LinkedHashSet>()
/*
* [delayedNodes] is needed to accomplish next order contract:
* for each node all previous node lays before it
*/
val delayedNodes = LinkedHashSet>()
val stack = ArrayDeque>()
stack.addFirst(enterNode)
while (stack.isNotEmpty()) {
val node = stack.removeFirst()
val previousNodes = node.previousNodes
if (previousNodes.any { it !in visitedNodes && it.owner == this && !node.incomingEdges.getValue(it).isBack }) {
delayedNodes.add(node)
stack.addLast(node)
continue
}
if (!visitedNodes.add(node)) continue
val followingNodes = node.followingNodes
for (followingNode in followingNodes) {
if (followingNode.owner == this) {
if (followingNode !in visitedNodes) {
stack.addFirst(followingNode)
}
} else {
walkThrowSubGraphs(followingNode.owner, visitedNodes, stack)
}
}
}
return visitedNodes
}
@OptIn(ExperimentalStdlibApi::class)
private fun ControlFlowGraph.walkThrowSubGraphs(
otherGraph: ControlFlowGraph,
visitedNodes: Set>,
stack: ArrayDeque>
) {
if (otherGraph.owner != this) return
for (otherNode in otherGraph.exitNode.followingNodes) {
if (otherNode.owner == this) {
if (otherNode !in visitedNodes) {
stack.addFirst(otherNode)
}
} else if (otherNode.owner != otherGraph) {
walkThrowSubGraphs(otherNode.owner, visitedNodes, stack)
}
}
}