From ec0f8a9c7713d4c51a559ad96dec33e0e35bada6 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 29 Jan 2020 12:57:39 +0300 Subject: [PATCH] [FIR] Hide modifications of CFG from public API --- .../fir/resolve/dfa/cfg/ControlFlowGraph.kt | 47 ++++++++++++++----- .../dfa/cfg/ControlFlowGraphBuilder.kt | 26 +++++----- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt index 1cc2639f81e..3cb9f9560b1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt @@ -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. */ +@file:Suppress("Reformat") + package org.jetbrains.kotlin.fir.resolve.dfa.cfg import org.jetbrains.kotlin.fir.FirElement @@ -15,9 +17,18 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor class ControlFlowGraph(val name: String, val kind: Kind) { - val nodes = mutableListOf>() + private val _nodes: MutableList> = mutableListOf() + + val nodes: List> get() = _nodes + + internal fun addNode(node: CFGNode<*>) { + _nodes += node + } + lateinit var enterNode: CFGNode<*> + internal set lateinit var exitNode: CFGNode<*> + internal set enum class Kind { Function, ClassInitializer, PropertyInitializer, TopLevel @@ -30,12 +41,12 @@ enum class EdgeKind { sealed class CFGNode(val owner: ControlFlowGraph, val level: Int, private val id: Int) { companion object { - fun addEdge(from: CFGNode<*>, to: CFGNode<*>, kind: EdgeKind, propagateDeadness: Boolean) { - from.followingNodes += to - to.previousNodes += from + internal fun addEdge(from: CFGNode<*>, to: CFGNode<*>, kind: EdgeKind, propagateDeadness: Boolean) { + from._followingNodes += to + to._previousNodes += from if (kind != EdgeKind.Simple) { - from.outgoingEdges[to] = kind - to.incomingEdges[from] = kind + from._outgoingEdges[to] = kind + to._incomingEdges[from] = kind } if (propagateDeadness && kind == EdgeKind.Dead) { to.isDead = true @@ -44,19 +55,29 @@ sealed class CFGNode(val owner: ControlFlowGraph, val level: } init { - owner.nodes += this + @Suppress("LeakingThis") + owner.addNode(this) } - val previousNodes: MutableList> = mutableListOf() - val followingNodes: MutableList> = mutableListOf() + private val _previousNodes: MutableList> = mutableListOf() + private val _followingNodes: MutableList> = mutableListOf() - val incomingEdges = mutableMapOf, EdgeKind>().withDefault { EdgeKind.Simple } - val outgoingEdges = mutableMapOf, EdgeKind>().withDefault { EdgeKind.Simple } + val previousNodes: List> get() = _previousNodes + val followingNodes: List> get() = _followingNodes - val firstPreviousNode: CFGNode<*> get() = previousNodes.first() + private val _incomingEdges = mutableMapOf, EdgeKind>().withDefault { EdgeKind.Simple } + private val _outgoingEdges = mutableMapOf, EdgeKind>().withDefault { EdgeKind.Simple } + + val incomingEdges: Map, EdgeKind> get() = _incomingEdges + val outgoingEdges: Map, EdgeKind> get() = _outgoingEdges abstract val fir: E 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 { if (other !is CFGNode<*>) return false @@ -68,6 +89,8 @@ sealed class CFGNode(val owner: ControlFlowGraph, val level: } } +val CFGNode<*>.firstPreviousNode: CFGNode<*> get() = previousNodes.first() + interface EnterNode interface ExitNode diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index c4e04559bdc..c175b2dd568 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -131,7 +131,7 @@ class ControlFlowGraphBuilder { } lexicalScopes.pop() } - exitNode.markAsDeadIfNecessary() + exitNode.updateDeadStatus() val graph = if (!isInplace) { graphs.pop() } else { @@ -175,7 +175,7 @@ class ControlFlowGraphBuilder { functionExitNodes.top().also { addEdge(lastNodes.pop(), it) lastNodes.push(it) - it.markAsDeadIfNecessary() + it.updateDeadStatus() } } else { levelCounter-- @@ -201,7 +201,7 @@ class ControlFlowGraphBuilder { fun exitProperty(property: FirProperty): Pair { val topLevelVariableExitNode = topLevelVariableInitializerExitNodes.pop().also { addNewSimpleNode(it) - it.markAsDeadIfNecessary() + it.updateDeadStatus() } levelCounter-- exitNodes.pop() @@ -285,7 +285,7 @@ class ControlFlowGraphBuilder { addEdge(this, whenExitNode) } } else null - whenExitNode.markAsDeadIfNecessary() + whenExitNode.updateDeadStatus() lastNodes.push(whenExitNode) levelCounter-- return whenExitNode to syntheticElseBranchNode @@ -332,7 +332,7 @@ class ControlFlowGraphBuilder { addEdge(loopBlockExitNode, conditionEnterNode, propagateDeadness = false) } val loopExitNode = loopExitNodes.pop() - loopExitNode.markAsDeadIfNecessary() + loopExitNode.updateDeadStatus() lastNodes.push(loopExitNode) levelCounter-- return loopBlockExitNode to loopExitNode @@ -373,7 +373,7 @@ class ControlFlowGraphBuilder { addEdge(conditionExitNode, blockEnterNode, propagateDeadness = false, isDead = conditionBooleanValue == false) val loopExit = loopExitNodes.pop() addEdge(conditionExitNode, loopExit, propagateDeadness = false, isDead = conditionBooleanValue == true) - loopExit.markAsDeadIfNecessary() + loopExit.updateDeadStatus() lastNodes.push(loopExit) levelCounter-- return conditionExitNode to loopExit @@ -410,7 +410,7 @@ class ControlFlowGraphBuilder { return binaryAndExitNodes.pop().also { val rightNode = lastNodes.pop() addEdge(rightNode, it, propagateDeadness = false, isDead = it.leftOperandNode.booleanConstValue == false) - it.markAsDeadIfNecessary() + it.updateDeadStatus() lastNodes.push(it) } } @@ -456,7 +456,7 @@ class ControlFlowGraphBuilder { return binaryOrExitNodes.pop().also { val rightNode = lastNodes.pop() addEdge(rightNode, it, propagateDeadness = false) - it.markAsDeadIfNecessary() + it.updateDeadStatus() lastNodes.push(it) } } @@ -531,7 +531,7 @@ class ControlFlowGraphBuilder { levelCounter-- catchNodeStorages.pop() val node = tryExitNodes.pop() - node.markAsDeadIfNecessary() + node.updateDeadStatus() lastNodes.push(node) return node } @@ -616,7 +616,7 @@ class ControlFlowGraphBuilder { levelCounter-- return initBlockExitNodes.pop().also { addNewSimpleNode(it) - it.markAsDeadIfNecessary() + it.updateDeadStatus() lexicalScopes.pop() exitNodes.pop() graphs.pop() @@ -639,16 +639,12 @@ class ControlFlowGraphBuilder { fun exitSafeCall(qualifiedAccess: FirQualifiedAccess): ExitSafeCallNode { return exitSafeCallNodes.pop().also { 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<*>) { /* * `return` is temporary solution that is needed for init block