[FIR] Hide modifications of CFG from public API

This commit is contained in:
Dmitriy Novozhilov
2020-01-29 12:57:39 +03:00
parent 6716cb0bf3
commit ec0f8a9c77
2 changed files with 46 additions and 27 deletions
@@ -3,6 +3,8 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("Reformat")
package org.jetbrains.kotlin.fir.resolve.dfa.cfg package org.jetbrains.kotlin.fir.resolve.dfa.cfg
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
@@ -15,9 +17,18 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.fir.visitors.FirVisitor
class ControlFlowGraph(val name: String, val kind: Kind) { class ControlFlowGraph(val name: String, val kind: Kind) {
val nodes = mutableListOf<CFGNode<*>>() private val _nodes: MutableList<CFGNode<*>> = mutableListOf()
val nodes: List<CFGNode<*>> get() = _nodes
internal fun addNode(node: CFGNode<*>) {
_nodes += node
}
lateinit var enterNode: CFGNode<*> lateinit var enterNode: CFGNode<*>
internal set
lateinit var exitNode: CFGNode<*> lateinit var exitNode: CFGNode<*>
internal set
enum class Kind { enum class Kind {
Function, ClassInitializer, PropertyInitializer, TopLevel Function, ClassInitializer, PropertyInitializer, TopLevel
@@ -30,12 +41,12 @@ enum class EdgeKind {
sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level: Int, private val id: Int) { sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level: Int, private val id: Int) {
companion object { companion object {
fun addEdge(from: CFGNode<*>, to: CFGNode<*>, kind: EdgeKind, propagateDeadness: Boolean) { internal fun addEdge(from: CFGNode<*>, to: CFGNode<*>, kind: EdgeKind, propagateDeadness: Boolean) {
from.followingNodes += to from._followingNodes += to
to.previousNodes += from to._previousNodes += from
if (kind != EdgeKind.Simple) { if (kind != EdgeKind.Simple) {
from.outgoingEdges[to] = kind from._outgoingEdges[to] = kind
to.incomingEdges[from] = kind to._incomingEdges[from] = kind
} }
if (propagateDeadness && kind == EdgeKind.Dead) { if (propagateDeadness && kind == EdgeKind.Dead) {
to.isDead = true to.isDead = true
@@ -44,19 +55,29 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
} }
init { init {
owner.nodes += this @Suppress("LeakingThis")
owner.addNode(this)
} }
val previousNodes: MutableList<CFGNode<*>> = mutableListOf() private val _previousNodes: MutableList<CFGNode<*>> = mutableListOf()
val followingNodes: MutableList<CFGNode<*>> = mutableListOf() private val _followingNodes: MutableList<CFGNode<*>> = mutableListOf()
val incomingEdges = mutableMapOf<CFGNode<*>, EdgeKind>().withDefault { EdgeKind.Simple } val previousNodes: List<CFGNode<*>> get() = _previousNodes
val outgoingEdges = mutableMapOf<CFGNode<*>, EdgeKind>().withDefault { EdgeKind.Simple } val followingNodes: List<CFGNode<*>> get() = _followingNodes
val firstPreviousNode: CFGNode<*> get() = previousNodes.first() private val _incomingEdges = mutableMapOf<CFGNode<*>, EdgeKind>().withDefault { EdgeKind.Simple }
private val _outgoingEdges = mutableMapOf<CFGNode<*>, EdgeKind>().withDefault { EdgeKind.Simple }
val incomingEdges: Map<CFGNode<*>, EdgeKind> get() = _incomingEdges
val outgoingEdges: Map<CFGNode<*>, EdgeKind> get() = _outgoingEdges
abstract val fir: E abstract val fir: E
var isDead: Boolean = false var isDead: Boolean = false
protected set
internal fun updateDeadStatus() {
isDead = incomingEdges.size == previousNodes.size && incomingEdges.values.all { it == EdgeKind.Dead }
}
final override fun equals(other: Any?): Boolean { final override fun equals(other: Any?): Boolean {
if (other !is CFGNode<*>) return false if (other !is CFGNode<*>) return false
@@ -68,6 +89,8 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
} }
} }
val CFGNode<*>.firstPreviousNode: CFGNode<*> get() = previousNodes.first()
interface EnterNode interface EnterNode
interface ExitNode interface ExitNode
@@ -131,7 +131,7 @@ class ControlFlowGraphBuilder {
} }
lexicalScopes.pop() lexicalScopes.pop()
} }
exitNode.markAsDeadIfNecessary() exitNode.updateDeadStatus()
val graph = if (!isInplace) { val graph = if (!isInplace) {
graphs.pop() graphs.pop()
} else { } else {
@@ -175,7 +175,7 @@ class ControlFlowGraphBuilder {
functionExitNodes.top().also { functionExitNodes.top().also {
addEdge(lastNodes.pop(), it) addEdge(lastNodes.pop(), it)
lastNodes.push(it) lastNodes.push(it)
it.markAsDeadIfNecessary() it.updateDeadStatus()
} }
} else { } else {
levelCounter-- levelCounter--
@@ -201,7 +201,7 @@ class ControlFlowGraphBuilder {
fun exitProperty(property: FirProperty): Pair<PropertyInitializerExitNode, ControlFlowGraph> { fun exitProperty(property: FirProperty): Pair<PropertyInitializerExitNode, ControlFlowGraph> {
val topLevelVariableExitNode = topLevelVariableInitializerExitNodes.pop().also { val topLevelVariableExitNode = topLevelVariableInitializerExitNodes.pop().also {
addNewSimpleNode(it) addNewSimpleNode(it)
it.markAsDeadIfNecessary() it.updateDeadStatus()
} }
levelCounter-- levelCounter--
exitNodes.pop() exitNodes.pop()
@@ -285,7 +285,7 @@ class ControlFlowGraphBuilder {
addEdge(this, whenExitNode) addEdge(this, whenExitNode)
} }
} else null } else null
whenExitNode.markAsDeadIfNecessary() whenExitNode.updateDeadStatus()
lastNodes.push(whenExitNode) lastNodes.push(whenExitNode)
levelCounter-- levelCounter--
return whenExitNode to syntheticElseBranchNode return whenExitNode to syntheticElseBranchNode
@@ -332,7 +332,7 @@ class ControlFlowGraphBuilder {
addEdge(loopBlockExitNode, conditionEnterNode, propagateDeadness = false) addEdge(loopBlockExitNode, conditionEnterNode, propagateDeadness = false)
} }
val loopExitNode = loopExitNodes.pop() val loopExitNode = loopExitNodes.pop()
loopExitNode.markAsDeadIfNecessary() loopExitNode.updateDeadStatus()
lastNodes.push(loopExitNode) lastNodes.push(loopExitNode)
levelCounter-- levelCounter--
return loopBlockExitNode to loopExitNode return loopBlockExitNode to loopExitNode
@@ -373,7 +373,7 @@ class ControlFlowGraphBuilder {
addEdge(conditionExitNode, blockEnterNode, propagateDeadness = false, isDead = conditionBooleanValue == false) addEdge(conditionExitNode, blockEnterNode, propagateDeadness = false, isDead = conditionBooleanValue == false)
val loopExit = loopExitNodes.pop() val loopExit = loopExitNodes.pop()
addEdge(conditionExitNode, loopExit, propagateDeadness = false, isDead = conditionBooleanValue == true) addEdge(conditionExitNode, loopExit, propagateDeadness = false, isDead = conditionBooleanValue == true)
loopExit.markAsDeadIfNecessary() loopExit.updateDeadStatus()
lastNodes.push(loopExit) lastNodes.push(loopExit)
levelCounter-- levelCounter--
return conditionExitNode to loopExit return conditionExitNode to loopExit
@@ -410,7 +410,7 @@ class ControlFlowGraphBuilder {
return binaryAndExitNodes.pop().also { return binaryAndExitNodes.pop().also {
val rightNode = lastNodes.pop() val rightNode = lastNodes.pop()
addEdge(rightNode, it, propagateDeadness = false, isDead = it.leftOperandNode.booleanConstValue == false) addEdge(rightNode, it, propagateDeadness = false, isDead = it.leftOperandNode.booleanConstValue == false)
it.markAsDeadIfNecessary() it.updateDeadStatus()
lastNodes.push(it) lastNodes.push(it)
} }
} }
@@ -456,7 +456,7 @@ class ControlFlowGraphBuilder {
return binaryOrExitNodes.pop().also { return binaryOrExitNodes.pop().also {
val rightNode = lastNodes.pop() val rightNode = lastNodes.pop()
addEdge(rightNode, it, propagateDeadness = false) addEdge(rightNode, it, propagateDeadness = false)
it.markAsDeadIfNecessary() it.updateDeadStatus()
lastNodes.push(it) lastNodes.push(it)
} }
} }
@@ -531,7 +531,7 @@ class ControlFlowGraphBuilder {
levelCounter-- levelCounter--
catchNodeStorages.pop() catchNodeStorages.pop()
val node = tryExitNodes.pop() val node = tryExitNodes.pop()
node.markAsDeadIfNecessary() node.updateDeadStatus()
lastNodes.push(node) lastNodes.push(node)
return node return node
} }
@@ -616,7 +616,7 @@ class ControlFlowGraphBuilder {
levelCounter-- levelCounter--
return initBlockExitNodes.pop().also { return initBlockExitNodes.pop().also {
addNewSimpleNode(it) addNewSimpleNode(it)
it.markAsDeadIfNecessary() it.updateDeadStatus()
lexicalScopes.pop() lexicalScopes.pop()
exitNodes.pop() exitNodes.pop()
graphs.pop() graphs.pop()
@@ -639,16 +639,12 @@ class ControlFlowGraphBuilder {
fun exitSafeCall(qualifiedAccess: FirQualifiedAccess): ExitSafeCallNode { fun exitSafeCall(qualifiedAccess: FirQualifiedAccess): ExitSafeCallNode {
return exitSafeCallNodes.pop().also { return exitSafeCallNodes.pop().also {
addNewSimpleNode(it) addNewSimpleNode(it)
it.markAsDeadIfNecessary() it.updateDeadStatus()
} }
} }
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
private fun CFGNode<*>.markAsDeadIfNecessary() {
isDead = incomingEdges.size == previousNodes.size && incomingEdges.values.all { it == EdgeKind.Dead }
}
private fun addNodeThatReturnsNothing(node: CFGNode<*>) { private fun addNodeThatReturnsNothing(node: CFGNode<*>) {
/* /*
* `return` is temporary solution that is needed for init block * `return` is temporary solution that is needed for init block