FIR CFA: automatically compute node levels

This commit is contained in:
pyos
2022-12-11 18:03:08 +01:00
committed by Dmitriy Novozhilov
parent 0dd949bb36
commit b548473544
2 changed files with 119 additions and 184 deletions
@@ -30,6 +30,11 @@ class ControlFlowGraphBuilder {
val currentGraph: ControlFlowGraph val currentGraph: ControlFlowGraph
get() = graphs.top() get() = graphs.top()
val levelCounter: Int
// `try` expressions aren't subgraphs, but they increase the level in order to tell which nodes
// are inside the try and which aren't
get() = graphs.size + tryExitNodes.size - 1 /* top-level graph */
private val lastNodes: Stack<CFGNode<*>> = stackOf() private val lastNodes: Stack<CFGNode<*>> = stackOf()
val lastNode: CFGNode<*> val lastNode: CFGNode<*>
get() = lastNodes.top() get() = lastNodes.top()
@@ -37,8 +42,6 @@ class ControlFlowGraphBuilder {
val lastNodeOrNull: CFGNode<*>? val lastNodeOrNull: CFGNode<*>?
get() = lastNodes.topOrNull() get() = lastNodes.topOrNull()
var levelCounter: Int = 0
// ----------------------------------- Node caches ----------------------------------- // ----------------------------------- Node caches -----------------------------------
private val exitTargetsForReturn: SymbolBasedNodeStorage<FirFunction, FunctionExitNode> = SymbolBasedNodeStorage() private val exitTargetsForReturn: SymbolBasedNodeStorage<FirFunction, FunctionExitNode> = SymbolBasedNodeStorage()
@@ -114,7 +117,6 @@ class ControlFlowGraphBuilder {
nodes: (E) -> Pair<EnterNode, ExitNode> nodes: (E) -> Pair<EnterNode, ExitNode>
): Pair<EnterNode, ExitNode> where EnterNode : CFGNode<T>, EnterNode : GraphEnterNodeMarker, ExitNode : CFGNode<T>, ExitNode : GraphExitNodeMarker { ): Pair<EnterNode, ExitNode> where EnterNode : CFGNode<T>, EnterNode : GraphEnterNodeMarker, ExitNode : CFGNode<T>, ExitNode : GraphExitNodeMarker {
graphs.push(ControlFlowGraph(fir as? FirDeclaration, name, kind)) graphs.push(ControlFlowGraph(fir as? FirDeclaration, name, kind))
levelCounter++
return nodes(fir).also { (enterNode, exitNode) -> return nodes(fir).also { (enterNode, exitNode) ->
currentGraph.enterNode = enterNode currentGraph.enterNode = enterNode
currentGraph.exitNode = exitNode currentGraph.exitNode = exitNode
@@ -123,7 +125,6 @@ class ControlFlowGraphBuilder {
} }
private fun popGraph(): ControlFlowGraph { private fun popGraph(): ControlFlowGraph {
levelCounter--
return graphs.pop().also { it.complete() } return graphs.pop().also { it.complete() }
} }
@@ -385,7 +386,6 @@ class ControlFlowGraphBuilder {
fun enterClass(klass: FirClass, buildGraph: Boolean): Pair<CFGNode<*>?, ClassEnterNode>? { fun enterClass(klass: FirClass, buildGraph: Boolean): Pair<CFGNode<*>?, ClassEnterNode>? {
if (!buildGraph || klass !is FirControlFlowGraphOwner) { if (!buildGraph || klass !is FirControlFlowGraphOwner) {
graphs.push(ControlFlowGraph(null, "<discarded class graph>", ControlFlowGraph.Kind.ClassInitializer)) graphs.push(ControlFlowGraph(null, "<discarded class graph>", ControlFlowGraph.Kind.ClassInitializer))
levelCounter++
return null return null
} }
@@ -432,7 +432,6 @@ class ControlFlowGraphBuilder {
fun exitClass(): Pair<ClassExitNode?, ControlFlowGraph>? { fun exitClass(): Pair<ClassExitNode?, ControlFlowGraph>? {
if (currentGraph.declaration == null) { if (currentGraph.declaration == null) {
levelCounter--
graphs.pop().also { assert(it.kind == ControlFlowGraph.Kind.ClassInitializer) } graphs.pop().also { assert(it.kind == ControlFlowGraph.Kind.ClassInitializer) }
return null return null
} }
@@ -704,7 +703,6 @@ class ControlFlowGraphBuilder {
addNewSimpleNode(node) addNewSimpleNode(node)
whenExitNodes.push(createWhenExitNode(whenExpression)) whenExitNodes.push(createWhenExitNode(whenExpression))
notCompletedFunctionCalls.push(mutableListOf()) notCompletedFunctionCalls.push(mutableListOf())
levelCounter++
splitDataFlowForPostponedLambdas() splitDataFlowForPostponedLambdas()
return node return node
} }
@@ -714,28 +712,20 @@ class ControlFlowGraphBuilder {
} }
fun enterWhenBranchCondition(whenBranch: FirWhenBranch): WhenBranchConditionEnterNode { fun enterWhenBranchCondition(whenBranch: FirWhenBranch): WhenBranchConditionEnterNode {
return createWhenBranchConditionEnterNode(whenBranch).also { addNewSimpleNode(it) }.also { levelCounter++ } return createWhenBranchConditionEnterNode(whenBranch).also { addNewSimpleNode(it) }
} }
fun exitWhenBranchCondition(whenBranch: FirWhenBranch): Pair<WhenBranchConditionExitNode, WhenBranchResultEnterNode> { fun exitWhenBranchCondition(whenBranch: FirWhenBranch): Pair<WhenBranchConditionExitNode, WhenBranchResultEnterNode> {
levelCounter-- val conditionExitNode = createWhenBranchConditionExitNode(whenBranch).also { addNewSimpleNode(it) }
val conditionExitNode = createWhenBranchConditionExitNode(whenBranch).also { lastNodes.push(conditionExitNode) // keep one for next condition entry
addNewSimpleNode(it) val branchEnterNode = createWhenBranchResultEnterNode(whenBranch).also { addNewSimpleNode(it) }
}.also { levelCounter++ }
val branchEnterNode = createWhenBranchResultEnterNode(whenBranch).also {
lastNodes.push(it)
addEdge(conditionExitNode, it)
}
return conditionExitNode to branchEnterNode return conditionExitNode to branchEnterNode
} }
fun exitWhenBranchResult(whenBranch: FirWhenBranch): WhenBranchResultExitNode { fun exitWhenBranchResult(whenBranch: FirWhenBranch): WhenBranchResultExitNode {
levelCounter--
val node = createWhenBranchResultExitNode(whenBranch) val node = createWhenBranchResultExitNode(whenBranch)
popAndAddEdge(node) popAndAddEdge(node)
val whenExitNode = whenExitNodes.top() addEdge(node, whenExitNodes.top(), propagateDeadness = false)
addEdge(node, whenExitNode, propagateDeadness = false)
levelCounter++
return node return node
} }
@@ -743,7 +733,6 @@ class ControlFlowGraphBuilder {
whenExpression: FirWhenExpression, whenExpression: FirWhenExpression,
callCompleted: Boolean callCompleted: Boolean
): Pair<WhenExitNode, WhenSyntheticElseBranchNode?> { ): Pair<WhenExitNode, WhenSyntheticElseBranchNode?> {
levelCounter -= whenExpression.branches.size
val whenExitNode = whenExitNodes.pop() val whenExitNode = whenExitNodes.pop()
// exit from last condition node still on stack // exit from last condition node still on stack
// we should remove it // we should remove it
@@ -758,40 +747,29 @@ class ControlFlowGraphBuilder {
mergeDataFlowFromPostponedLambdas(whenExitNode, callCompleted) mergeDataFlowFromPostponedLambdas(whenExitNode, callCompleted)
whenExitNode.updateDeadStatus() whenExitNode.updateDeadStatus()
lastNodes.push(whenExitNode) lastNodes.push(whenExitNode)
levelCounter--
return whenExitNode to syntheticElseBranchNode return whenExitNode to syntheticElseBranchNode
} }
// ----------------------------------- While Loop ----------------------------------- // ----------------------------------- While Loop -----------------------------------
fun enterWhileLoop(loop: FirLoop): Pair<LoopEnterNode, LoopConditionEnterNode> { fun enterWhileLoop(loop: FirLoop): Pair<LoopEnterNode, LoopConditionEnterNode> {
val loopEnterNode = createLoopEnterNode(loop).also { val loopEnterNode = createLoopEnterNode(loop).also { addNewSimpleNode(it) }
addNewSimpleNode(it)
}
loopExitNodes.push(createLoopExitNode(loop)) loopExitNodes.push(createLoopExitNode(loop))
levelCounter++ val conditionEnterNode = createLoopConditionEnterNode(loop.condition, loop).also { addNewSimpleNode(it) }
val conditionEnterNode = createLoopConditionEnterNode(loop.condition, loop).also { loopConditionEnterNodes.push(conditionEnterNode)
addNewSimpleNode(it)
loopConditionEnterNodes.push(it)
}
levelCounter++
return loopEnterNode to conditionEnterNode return loopEnterNode to conditionEnterNode
} }
fun exitWhileLoopCondition(loop: FirLoop): Pair<LoopConditionExitNode, LoopBlockEnterNode> { fun exitWhileLoopCondition(loop: FirLoop): Pair<LoopConditionExitNode, LoopBlockEnterNode> {
levelCounter-- val conditionExitNode = createLoopConditionExitNode(loop.condition).also { addNewSimpleNode(it) }
val conditionExitNode = createLoopConditionExitNode(loop.condition)
addNewSimpleNode(conditionExitNode)
val conditionConstBooleanValue = loop.condition.booleanConstValue val conditionConstBooleanValue = loop.condition.booleanConstValue
addEdge(conditionExitNode, loopExitNodes.top(), propagateDeadness = false, isDead = conditionConstBooleanValue == true) addEdge(conditionExitNode, loopExitNodes.top(), propagateDeadness = false, isDead = conditionConstBooleanValue == true)
val loopBlockEnterNode = createLoopBlockEnterNode(loop) val loopBlockEnterNode = createLoopBlockEnterNode(loop)
addNewSimpleNode(loopBlockEnterNode, conditionConstBooleanValue == false) addNewSimpleNode(loopBlockEnterNode, conditionConstBooleanValue == false)
levelCounter++
return conditionExitNode to loopBlockEnterNode return conditionExitNode to loopBlockEnterNode
} }
fun exitWhileLoop(loop: FirLoop): Triple<LoopConditionEnterNode, LoopBlockExitNode, LoopExitNode> { fun exitWhileLoop(loop: FirLoop): Triple<LoopConditionEnterNode, LoopBlockExitNode, LoopExitNode> {
levelCounter--
val loopBlockExitNode = createLoopBlockExitNode(loop) val loopBlockExitNode = createLoopBlockExitNode(loop)
popAndAddEdge(loopBlockExitNode) popAndAddEdge(loopBlockExitNode)
val conditionEnterNode = loopConditionEnterNodes.pop() val conditionEnterNode = loopConditionEnterNodes.pop()
@@ -799,41 +777,32 @@ class ControlFlowGraphBuilder {
val loopExitNode = loopExitNodes.pop() val loopExitNode = loopExitNodes.pop()
loopExitNode.updateDeadStatus() loopExitNode.updateDeadStatus()
lastNodes.push(loopExitNode) lastNodes.push(loopExitNode)
levelCounter--
return Triple(conditionEnterNode, loopBlockExitNode, loopExitNode) return Triple(conditionEnterNode, loopBlockExitNode, loopExitNode)
} }
// ----------------------------------- Do while Loop ----------------------------------- // ----------------------------------- Do while Loop -----------------------------------
fun enterDoWhileLoop(loop: FirLoop): Pair<LoopEnterNode, LoopBlockEnterNode> { fun enterDoWhileLoop(loop: FirLoop): Pair<LoopEnterNode, LoopBlockEnterNode> {
val loopEnterNode = createLoopEnterNode(loop) val loopEnterNode = createLoopEnterNode(loop).also { addNewSimpleNode(it) }
addNewSimpleNode(loopEnterNode)
loopExitNodes.push(createLoopExitNode(loop)) loopExitNodes.push(createLoopExitNode(loop))
levelCounter++ val blockEnterNode = createLoopBlockEnterNode(loop).also { addNewSimpleNode(it) }
val blockEnterNode = createLoopBlockEnterNode(loop) lastNodes.push(blockEnterNode) // to add back edge at the end
addNewSimpleNode(blockEnterNode)
// put block enter node twice so we can refer it after exit from loop condition
lastNodes.push(blockEnterNode)
loopConditionEnterNodes.push(createLoopConditionEnterNode(loop.condition, loop)) loopConditionEnterNodes.push(createLoopConditionEnterNode(loop.condition, loop))
levelCounter++
return loopEnterNode to blockEnterNode return loopEnterNode to blockEnterNode
} }
fun enterDoWhileLoopCondition(loop: FirLoop): Pair<LoopBlockExitNode, LoopConditionEnterNode> { fun enterDoWhileLoopCondition(loop: FirLoop): Pair<LoopBlockExitNode, LoopConditionEnterNode> {
levelCounter--
val blockExitNode = createLoopBlockExitNode(loop).also { addNewSimpleNode(it) } val blockExitNode = createLoopBlockExitNode(loop).also { addNewSimpleNode(it) }
// This may sound shocking, but `do...while` conditions can `continue` to themselves, // This may sound shocking, but `do...while` conditions can `continue` to themselves,
// so we can't pop the node off the stack here. // so we can't pop the node off the stack here.
val conditionEnterNode = loopConditionEnterNodes.top().also { addNewSimpleNode(it) } val conditionEnterNode = loopConditionEnterNodes.top().also { addNewSimpleNode(it) }
// Might have had live `continue`s with an unreachable block exit, so recompute deadness. // Might have had live `continue`s with an unreachable block exit, so recompute deadness.
conditionEnterNode.updateDeadStatus() conditionEnterNode.updateDeadStatus()
levelCounter++
return blockExitNode to conditionEnterNode return blockExitNode to conditionEnterNode
} }
fun exitDoWhileLoop(loop: FirLoop): Pair<LoopConditionExitNode, LoopExitNode> { fun exitDoWhileLoop(loop: FirLoop): Pair<LoopConditionExitNode, LoopExitNode> {
loopConditionEnterNodes.pop() loopConditionEnterNodes.pop()
levelCounter--
val conditionExitNode = createLoopConditionExitNode(loop.condition) val conditionExitNode = createLoopConditionExitNode(loop.condition)
val conditionBooleanValue = loop.condition.booleanConstValue val conditionBooleanValue = loop.condition.booleanConstValue
popAndAddEdge(conditionExitNode) popAndAddEdge(conditionExitNode)
@@ -844,7 +813,6 @@ class ControlFlowGraphBuilder {
addEdge(conditionExitNode, loopExit, propagateDeadness = false, isDead = conditionBooleanValue == true) addEdge(conditionExitNode, loopExit, propagateDeadness = false, isDead = conditionBooleanValue == true)
loopExit.updateDeadStatus() loopExit.updateDeadStatus()
lastNodes.push(loopExit) lastNodes.push(loopExit)
levelCounter--
return conditionExitNode to loopExit return conditionExitNode to loopExit
} }
@@ -857,14 +825,12 @@ class ControlFlowGraphBuilder {
} }
addNewSimpleNode(enterNode) addNewSimpleNode(enterNode)
binaryLogicExpressionExitNodes.push(exitNode) binaryLogicExpressionExitNodes.push(exitNode)
levelCounter++
return enterNode return enterNode
} }
fun exitLeftBinaryLogicExpressionArgument( fun exitLeftBinaryLogicExpressionArgument(
binaryLogicExpression: FirBinaryLogicExpression binaryLogicExpression: FirBinaryLogicExpression
): Pair<CFGNode<FirBinaryLogicExpression>, CFGNode<FirBinaryLogicExpression>> { ): Pair<CFGNode<FirBinaryLogicExpression>, CFGNode<FirBinaryLogicExpression>> {
levelCounter--
val leftBooleanConstValue = binaryLogicExpression.leftOperand.booleanConstValue val leftBooleanConstValue = binaryLogicExpression.leftOperand.booleanConstValue
val (leftExitNode, rightEnterNode) = when (binaryLogicExpression.kind) { val (leftExitNode, rightEnterNode) = when (binaryLogicExpression.kind) {
LogicOperationKind.AND -> LogicOperationKind.AND ->
@@ -878,12 +844,10 @@ class ControlFlowGraphBuilder {
addEdge(leftExitNode, binaryLogicExpressionExitNodes.top(), propagateDeadness = false, isDead = leftBooleanConstValue == isAnd) addEdge(leftExitNode, binaryLogicExpressionExitNodes.top(), propagateDeadness = false, isDead = leftBooleanConstValue == isAnd)
addEdge(leftExitNode, rightEnterNode, isDead = leftBooleanConstValue == !isAnd) addEdge(leftExitNode, rightEnterNode, isDead = leftBooleanConstValue == !isAnd)
lastNodes.push(rightEnterNode) lastNodes.push(rightEnterNode)
levelCounter++
return leftExitNode to rightEnterNode return leftExitNode to rightEnterNode
} }
fun exitBinaryLogicExpression(): AbstractBinaryExitNode<FirBinaryLogicExpression> { fun exitBinaryLogicExpression(): AbstractBinaryExitNode<FirBinaryLogicExpression> {
levelCounter--
val exitNode = binaryLogicExpressionExitNodes.pop() val exitNode = binaryLogicExpressionExitNodes.pop()
val rightNode = lastNodes.pop() val rightNode = lastNodes.pop()
addEdge(rightNode, exitNode, propagateDeadness = false) addEdge(rightNode, exitNode, propagateDeadness = false)
@@ -897,14 +861,10 @@ class ControlFlowGraphBuilder {
// ----------------------------------- Try-catch-finally ----------------------------------- // ----------------------------------- Try-catch-finally -----------------------------------
fun enterTryExpression(tryExpression: FirTryExpression): Pair<TryExpressionEnterNode, TryMainBlockEnterNode> { fun enterTryExpression(tryExpression: FirTryExpression): Pair<TryExpressionEnterNode, TryMainBlockEnterNode> {
val enterTryExpressionNode = createTryExpressionEnterNode(tryExpression) val enterTryExpressionNode = createTryExpressionEnterNode(tryExpression).also { addNewSimpleNode(it) }
val exitTryExpressionNode = createTryExpressionExitNode(tryExpression) tryExitNodes.push(createTryExpressionExitNode(tryExpression))
addNewSimpleNode(enterTryExpressionNode)
tryExitNodes.push(exitTryExpressionNode)
levelCounter++
val enterTryMainBlockNode = createTryMainBlockEnterNode(tryExpression) val enterTryMainBlockNode = createTryMainBlockEnterNode(tryExpression).also { addNewSimpleNode(it) }
addNewSimpleNode(enterTryMainBlockNode)
catchNodes.push(tryExpression.catches.map { createCatchClauseEnterNode(it) }) catchNodes.push(tryExpression.catches.map { createCatchClauseEnterNode(it) })
if (tryExpression.finallyBlock != null) { if (tryExpression.finallyBlock != null) {
@@ -923,12 +883,10 @@ class ControlFlowGraphBuilder {
notCompletedFunctionCalls.push(mutableListOf()) notCompletedFunctionCalls.push(mutableListOf())
splitDataFlowForPostponedLambdas() splitDataFlowForPostponedLambdas()
levelCounter++
return enterTryExpressionNode to enterTryMainBlockNode return enterTryExpressionNode to enterTryMainBlockNode
} }
fun exitTryMainBlock(): TryMainBlockExitNode { fun exitTryMainBlock(): TryMainBlockExitNode {
levelCounter--
val exitTryExpressionNode = tryExitNodes.top() val exitTryExpressionNode = tryExitNodes.top()
val node = createTryMainBlockExitNode(exitTryExpressionNode.fir) val node = createTryMainBlockExitNode(exitTryExpressionNode.fir)
popAndAddEdge(node) popAndAddEdge(node)
@@ -956,12 +914,10 @@ class ControlFlowGraphBuilder {
addEdge(catchEnterNode, finallyEnterNodes.top(), propagateDeadness = false, label = UncaughtExceptionPath) addEdge(catchEnterNode, finallyEnterNodes.top(), propagateDeadness = false, label = UncaughtExceptionPath)
} }
lastNodes.push(catchEnterNode) lastNodes.push(catchEnterNode)
levelCounter++
return catchEnterNode return catchEnterNode
} }
fun exitCatchClause(catch: FirCatch): CatchClauseExitNode { fun exitCatchClause(catch: FirCatch): CatchClauseExitNode {
levelCounter--
val exitTryExpressionNode = tryExitNodes.top() val exitTryExpressionNode = tryExitNodes.top()
val catchExitNode = createCatchClauseExitNode(catch) val catchExitNode = createCatchClauseExitNode(catch)
popAndAddEdge(catchExitNode) popAndAddEdge(catchExitNode)
@@ -1030,7 +986,6 @@ class ControlFlowGraphBuilder {
} }
fun exitTryExpression(callCompleted: Boolean): TryExpressionExitNode { fun exitTryExpression(callCompleted: Boolean): TryExpressionExitNode {
levelCounter--
notCompletedFunctionCalls.pop().forEach(::completeFunctionCall) notCompletedFunctionCalls.pop().forEach(::completeFunctionCall)
val node = tryExitNodes.pop() val node = tryExitNodes.pop()
mergeDataFlowFromPostponedLambdas(node, callCompleted) mergeDataFlowFromPostponedLambdas(node, callCompleted)
@@ -1070,7 +1025,7 @@ class ControlFlowGraphBuilder {
// it would be much easier if we could build calls after full completion only, at least for Nothing calls // it would be much easier if we could build calls after full completion only, at least for Nothing calls
private fun completeFunctionCall(node: FunctionCallNode) { private fun completeFunctionCall(node: FunctionCallNode) {
if (!node.fir.resultType.isNothing) return if (!node.fir.resultType.isNothing) return
val stub = withLevelOfNode(node) { createStubNode() } val stub = StubNode(currentGraph, node.level, currentGraph.nodeCount++)
val edges = node.followingNodes.map { it to node.edgeTo(it) } val edges = node.followingNodes.map { it to node.edgeTo(it) }
CFGNode.removeAllOutgoingEdges(node) CFGNode.removeAllOutgoingEdges(node)
CFGNode.addEdge(node, stub, EdgeKind.DeadForward, propagateDeadness = false) CFGNode.addEdge(node, stub, EdgeKind.DeadForward, propagateDeadness = false)
@@ -1111,7 +1066,6 @@ class ControlFlowGraphBuilder {
} }
fun enterCall() { fun enterCall() {
levelCounter++
splitDataFlowForPostponedLambdas() splitDataFlowForPostponedLambdas()
} }
@@ -1130,7 +1084,6 @@ class ControlFlowGraphBuilder {
} }
fun exitFunctionCall(functionCall: FirFunctionCall, callCompleted: Boolean): FunctionCallNode { fun exitFunctionCall(functionCall: FirFunctionCall, callCompleted: Boolean): FunctionCallNode {
levelCounter--
val returnsNothing = functionCall.resultType.isNothing val returnsNothing = functionCall.resultType.isNothing
val node = createFunctionCallNode(functionCall) val node = createFunctionCallNode(functionCall)
unifyDataFlowFromPostponedLambdas(node, callCompleted) unifyDataFlowFromPostponedLambdas(node, callCompleted)
@@ -1146,7 +1099,6 @@ class ControlFlowGraphBuilder {
} }
fun exitDelegatedConstructorCall(call: FirDelegatedConstructorCall, callCompleted: Boolean): DelegatedConstructorCallNode { fun exitDelegatedConstructorCall(call: FirDelegatedConstructorCall, callCompleted: Boolean): DelegatedConstructorCallNode {
levelCounter--
val node = createDelegatedConstructorCallNode(call) val node = createDelegatedConstructorCallNode(call)
unifyDataFlowFromPostponedLambdas(node, callCompleted) unifyDataFlowFromPostponedLambdas(node, callCompleted)
addNewSimpleNode(node) addNewSimpleNode(node)
@@ -1154,7 +1106,6 @@ class ControlFlowGraphBuilder {
} }
fun exitStringConcatenationCall(call: FirStringConcatenationCall): StringConcatenationCallNode { fun exitStringConcatenationCall(call: FirStringConcatenationCall): StringConcatenationCallNode {
levelCounter--
val node = createStringConcatenationCallNode(call) val node = createStringConcatenationCallNode(call)
unifyDataFlowFromPostponedLambdas(node, callCompleted = true) unifyDataFlowFromPostponedLambdas(node, callCompleted = true)
addNewSimpleNode(node) addNewSimpleNode(node)
@@ -1178,7 +1129,6 @@ class ControlFlowGraphBuilder {
} }
fun exitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, callCompleted: Boolean): CheckNotNullCallNode { fun exitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, callCompleted: Boolean): CheckNotNullCallNode {
levelCounter--
val node = createCheckNotNullCallNode(checkNotNullCall) val node = createCheckNotNullCallNode(checkNotNullCall)
unifyDataFlowFromPostponedLambdas(node, callCompleted) unifyDataFlowFromPostponedLambdas(node, callCompleted)
if (checkNotNullCall.resultType.isNothing) { if (checkNotNullCall.resultType.isNothing) {
@@ -1196,7 +1146,6 @@ class ControlFlowGraphBuilder {
// and are never evaluated. We'll push all nodes created in the process into a stub graph, then throw it away. // and are never evaluated. We'll push all nodes created in the process into a stub graph, then throw it away.
// TODO: don't waste time creating the nodes in the first place // TODO: don't waste time creating the nodes in the first place
graphs.push(ControlFlowGraph(null, "<compile-time expression graph>", ControlFlowGraph.Kind.FakeCall)) graphs.push(ControlFlowGraph(null, "<compile-time expression graph>", ControlFlowGraph.Kind.FakeCall))
levelCounter++
return createFakeExpressionEnterNode().also { return createFakeExpressionEnterNode().also {
lastNodes.push(it) lastNodes.push(it)
exitTargetsForTry.push(it) // technically might create CFG loops, but the graph will never be visited anyway... exitTargetsForTry.push(it) // technically might create CFG loops, but the graph will never be visited anyway...
@@ -1204,7 +1153,6 @@ class ControlFlowGraphBuilder {
} }
fun exitFakeExpression() { fun exitFakeExpression() {
levelCounter--
lastNodes.pop() lastNodes.pop()
exitTargetsForTry.pop() exitTargetsForTry.pop()
graphs.pop().also { assert(it.kind == ControlFlowGraph.Kind.FakeCall) } graphs.pop().also { assert(it.kind == ControlFlowGraph.Kind.FakeCall) }
@@ -1395,19 +1343,6 @@ class ControlFlowGraphBuilder {
} }
} }
} }
// ----------------------------------- Utils -----------------------------------
private fun <R> withLevelOfNode(node: CFGNode<*>, f: () -> R): R {
val last = levelCounter
levelCounter = node.level
try {
return f()
} finally {
levelCounter = last
}
}
} }
fun FirDeclaration?.isLocalClassOrAnonymousObject() = ((this as? FirRegularClass)?.isLocal == true) || this is FirAnonymousObject fun FirDeclaration?.isLocalClassOrAnonymousObject() = ((this as? FirRegularClass)?.isLocal == true) || this is FirAnonymousObject
+98 -98
View File
@@ -368,8 +368,8 @@ digraph kt44814_kt {
subgraph cluster_41 { subgraph cluster_41 {
color=blue color=blue
112 [label="Enter function <init> [3]" style="filled" fillcolor=red]; 112 [label="Enter function <init> [3]" style="filled" fillcolor=red];
113 [label="Access variable R|<local>/node| [4]"]; 113 [label="Access variable R|<local>/node| [3]"];
114 [label="Access variable R|<local>/token| [4]"]; 114 [label="Access variable R|<local>/token| [3]"];
115 [label="Delegated constructor call: super<R|FirModifier<LighterASTNode>|>(...) [3]" style="filled" fillcolor=yellow]; 115 [label="Delegated constructor call: super<R|FirModifier<LighterASTNode>|>(...) [3]" style="filled" fillcolor=yellow];
116 [label="Exit function <init> [3]" style="filled" fillcolor=red]; 116 [label="Exit function <init> [3]" style="filled" fillcolor=red];
} }
@@ -387,8 +387,8 @@ digraph kt44814_kt {
subgraph cluster_44 { subgraph cluster_44 {
color=blue color=blue
122 [label="Enter function <init> [3]" style="filled" fillcolor=red]; 122 [label="Enter function <init> [3]" style="filled" fillcolor=red];
123 [label="Access variable R|<local>/node| [4]"]; 123 [label="Access variable R|<local>/node| [3]"];
124 [label="Access variable R|<local>/token| [4]"]; 124 [label="Access variable R|<local>/token| [3]"];
125 [label="Delegated constructor call: super<R|FirModifier<ASTNode>|>(...) [3]" style="filled" fillcolor=yellow]; 125 [label="Delegated constructor call: super<R|FirModifier<ASTNode>|>(...) [3]" style="filled" fillcolor=yellow];
126 [label="Exit function <init> [3]" style="filled" fillcolor=red]; 126 [label="Exit function <init> [3]" style="filled" fillcolor=red];
} }
@@ -462,13 +462,13 @@ digraph kt44814_kt {
subgraph cluster_51 { subgraph cluster_51 {
color=blue color=blue
142 [label="Enter block [3]"]; 142 [label="Enter block [3]"];
143 [label="Function call: R|/LighterASTNode.LighterASTNode|() [6]" style="filled" fillcolor=yellow]; 143 [label="Function call: R|/LighterASTNode.LighterASTNode|() [3]" style="filled" fillcolor=yellow];
144 [label="Function call: R|kotlin/collections/listOf|<R|LighterASTNode|>(...) [5]" style="filled" fillcolor=yellow]; 144 [label="Function call: R|kotlin/collections/listOf|<R|LighterASTNode|>(...) [3]" style="filled" fillcolor=yellow];
145 [label="Function call: R|/LighterASTNode.LighterASTNode|(...) [4]" style="filled" fillcolor=yellow]; 145 [label="Function call: R|/LighterASTNode.LighterASTNode|(...) [3]" style="filled" fillcolor=yellow];
146 [label="Function call: R|/FlyweightCapableTreeStructure.FlyweightCapableTreeStructure|() [4]" style="filled" fillcolor=yellow]; 146 [label="Function call: R|/FlyweightCapableTreeStructure.FlyweightCapableTreeStructure|() [3]" style="filled" fillcolor=yellow];
147 [label="Function call: R|/FirLightSourceElement.FirLightSourceElement|(...) [3]" style="filled" fillcolor=yellow]; 147 [label="Function call: R|/FirLightSourceElement.FirLightSourceElement|(...) [3]" style="filled" fillcolor=yellow];
148 [label="Variable declaration: lval sourceElement: R|FirSourceElement?| [3]"]; 148 [label="Variable declaration: lval sourceElement: R|FirSourceElement?| [3]"];
149 [label="Access variable R|<local>/sourceElement| [4]"]; 149 [label="Access variable R|<local>/sourceElement| [3]"];
150 [label="Function call: (this@R|/FirModifierList.Companion|, R|<local>/sourceElement|).R|/FirModifierList.Companion.getModifierList|() [3]" style="filled" fillcolor=yellow]; 150 [label="Function call: (this@R|/FirModifierList.Companion|, R|<local>/sourceElement|).R|/FirModifierList.Companion.getModifierList|() [3]" style="filled" fillcolor=yellow];
151 [label="Variable declaration: lval result: R|FirModifierList?| [3]"]; 151 [label="Variable declaration: lval result: R|FirModifierList?| [3]"];
subgraph cluster_52 { subgraph cluster_52 {
@@ -476,32 +476,32 @@ digraph kt44814_kt {
152 [label="Enter when [3]"]; 152 [label="Enter when [3]"];
subgraph cluster_53 { subgraph cluster_53 {
color=blue color=blue
153 [label="Enter when branch condition [4]"]; 153 [label="Enter when branch condition [3]"];
154 [label="Access variable R|<local>/result| [5]"]; 154 [label="Access variable R|<local>/result| [3]"];
155 [label="Type operator: (R|<local>/result| is R|FirModifierList.FirLightModifierList|) [5]"]; 155 [label="Type operator: (R|<local>/result| is R|FirModifierList.FirLightModifierList|) [3]"];
156 [label="Exit when branch condition [4]"]; 156 [label="Exit when branch condition [3]"];
} }
subgraph cluster_54 { subgraph cluster_54 {
color=blue color=blue
157 [label="Enter when branch condition else [5]"]; 157 [label="Enter when branch condition else [3]"];
158 [label="Exit when branch condition [5]"]; 158 [label="Exit when branch condition [3]"];
} }
159 [label="Enter when branch result [6]"]; 159 [label="Enter when branch result [3]"];
subgraph cluster_55 { subgraph cluster_55 {
color=blue color=blue
160 [label="Enter block [6]"]; 160 [label="Enter block [3]"];
161 [label="Const: String(Fail) [6]"]; 161 [label="Const: String(Fail) [3]"];
162 [label="Exit block [6]"]; 162 [label="Exit block [3]"];
} }
163 [label="Exit when branch result [5]"]; 163 [label="Exit when branch result [3]"];
164 [label="Enter when branch result [5]"]; 164 [label="Enter when branch result [3]"];
subgraph cluster_56 { subgraph cluster_56 {
color=blue color=blue
165 [label="Enter block [5]"]; 165 [label="Enter block [3]"];
166 [label="Const: String(OK) [5]"]; 166 [label="Const: String(OK) [3]"];
167 [label="Exit block [5]"]; 167 [label="Exit block [3]"];
} }
168 [label="Exit when branch result [4]"]; 168 [label="Exit when branch result [3]"];
169 [label="Exit when [3]"]; 169 [label="Exit when [3]"];
} }
170 [label="Jump: ^boxImpl when () { 170 [label="Jump: ^boxImpl when () {
@@ -527,108 +527,108 @@ digraph kt44814_kt {
subgraph cluster_59 { subgraph cluster_59 {
color=blue color=blue
176 [label="Enter when [3]"]; 176 [label="Enter when [3]"];
177 [label="Access variable this@R|/FirModifierList.Companion.getModifierList| [4]"]; 177 [label="Access variable this@R|/FirModifierList.Companion.getModifierList| [3]"];
subgraph cluster_60 { subgraph cluster_60 {
color=blue color=blue
178 [label="Enter when branch condition [4]"]; 178 [label="Enter when branch condition [3]"];
179 [label="Exit $subj [5]"]; 179 [label="Exit $subj [3]"];
180 [label="Const: Null(null) [5]"]; 180 [label="Const: Null(null) [3]"];
181 [label="Equality operator == [5]"]; 181 [label="Equality operator == [3]"];
182 [label="Exit when branch condition [4]"]; 182 [label="Exit when branch condition [3]"];
} }
subgraph cluster_61 { subgraph cluster_61 {
color=blue color=blue
183 [label="Enter when branch condition [5]"]; 183 [label="Enter when branch condition [3]"];
184 [label="Exit $subj [6]"]; 184 [label="Exit $subj [3]"];
185 [label="Type operator: ($subj$ is R|FirPsiSourceElement|) [6]"]; 185 [label="Type operator: ($subj$ is R|FirPsiSourceElement|) [3]"];
186 [label="Exit when branch condition [5]"]; 186 [label="Exit when branch condition [3]"];
} }
subgraph cluster_62 { subgraph cluster_62 {
color=blue color=blue
187 [label="Enter when branch condition [6]"]; 187 [label="Enter when branch condition [3]"];
188 [label="Exit $subj [7]"]; 188 [label="Exit $subj [3]"];
189 [label="Type operator: ($subj$ is R|FirLightSourceElement|) [7]"]; 189 [label="Type operator: ($subj$ is R|FirLightSourceElement|) [3]"];
190 [label="Exit when branch condition [6]"]; 190 [label="Exit when branch condition [3]"];
} }
191 [label="Enter when branch result [7]"]; 191 [label="Enter when branch result [3]"];
subgraph cluster_63 { subgraph cluster_63 {
color=blue color=blue
192 [label="Enter block [7]"]; 192 [label="Enter block [3]"];
193 [label="Access variable R|/FirLightSourceElement.lighterASTNode| [9]"]; 193 [label="Access variable R|/FirLightSourceElement.lighterASTNode| [3]"];
194 [label="Access variable R|/FirLightSourceElement.treeStructure| [9]"]; 194 [label="Access variable R|/FirLightSourceElement.treeStructure| [3]"];
195 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...) [8]" style="filled" fillcolor=yellow]; 195 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...) [3]" style="filled" fillcolor=yellow];
196 [label="Postponed enter to lambda [8]"]; 196 [label="Postponed enter to lambda [3]"];
subgraph cluster_64 { subgraph cluster_64 {
color=blue color=blue
197 [label="Enter function anonymousFunction [9]" style="filled" fillcolor=red]; 197 [label="Enter function anonymousFunction [4]" style="filled" fillcolor=red];
subgraph cluster_65 { subgraph cluster_65 {
color=blue color=blue
198 [label="Enter block [9]"]; 198 [label="Enter block [4]"];
199 [label="Access variable R|<local>/it| [9]"]; 199 [label="Access variable R|<local>/it| [4]"];
200 [label="Enter safe call [9]"]; 200 [label="Enter safe call [4]"];
201 [label="Access variable R|/LighterASTNode.tokenType| [9]"]; 201 [label="Access variable R|/LighterASTNode.tokenType| [4]"];
202 [label="Exit safe call [9]"]; 202 [label="Exit safe call [4]"];
203 [label="Access qualifier /TokenType [9]"]; 203 [label="Access qualifier /TokenType [4]"];
204 [label="Access variable R|/TokenType.Companion.MODIFIER_LIST| [9]"]; 204 [label="Access variable R|/TokenType.Companion.MODIFIER_LIST| [4]"];
205 [label="Equality operator == [9]"]; 205 [label="Equality operator == [4]"];
206 [label="Exit block [9]"]; 206 [label="Exit block [4]"];
} }
207 [label="Exit function anonymousFunction [9]" style="filled" fillcolor=red]; 207 [label="Exit function anonymousFunction [4]" style="filled" fillcolor=red];
} }
208 [label="Postponed exit from lambda [8]"]; 208 [label="Postponed exit from lambda [3]"];
209 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...).R|kotlin/collections/find|<R|LighterASTNode?|>(...) [7]" style="filled" fillcolor=yellow]; 209 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...).R|kotlin/collections/find|<R|LighterASTNode?|>(...) [3]" style="filled" fillcolor=yellow];
210 [label="Exit lhs of ?: [7]"]; 210 [label="Exit lhs of ?: [3]"];
211 [label="Enter rhs of ?: [7]"]; 211 [label="Enter rhs of ?: [3]"];
212 [label="Const: Null(null) [7]"]; 212 [label="Const: Null(null) [3]"];
213 [label="Jump: ^getModifierList Null(null) [7]"]; 213 [label="Jump: ^getModifierList Null(null) [3]"];
214 [label="Stub [7]" style="filled" fillcolor=gray]; 214 [label="Stub [3]" style="filled" fillcolor=gray];
215 [label="Lhs of ?: is not null [7]"]; 215 [label="Lhs of ?: is not null [3]"];
216 [label="Exit ?: [7]"]; 216 [label="Exit ?: [3]"];
217 [label="Variable declaration: lval modifierListNode: R|LighterASTNode| [7]"]; 217 [label="Variable declaration: lval modifierListNode: R|LighterASTNode| [3]"];
218 [label="Access variable R|<local>/modifierListNode| [8]"]; 218 [label="Access variable R|<local>/modifierListNode| [3]"];
219 [label="Access variable R|/FirLightSourceElement.treeStructure| [8]"]; 219 [label="Access variable R|/FirLightSourceElement.treeStructure| [3]"];
220 [label="Function call: R|/FirModifierList.FirLightModifierList.FirLightModifierList|(...) [7]" style="filled" fillcolor=yellow]; 220 [label="Function call: R|/FirModifierList.FirLightModifierList.FirLightModifierList|(...) [3]" style="filled" fillcolor=yellow];
221 [label="Exit block [7]"]; 221 [label="Exit block [3]"];
} }
222 [label="Exit when branch result [6]"]; 222 [label="Exit when branch result [3]"];
223 [label="Enter when branch result [6]"]; 223 [label="Enter when branch result [3]"];
subgraph cluster_66 { subgraph cluster_66 {
color=blue color=blue
224 [label="Enter block [6]"]; 224 [label="Enter block [3]"];
225 [label="Access variable R|/FirPsiSourceElement.psi| [6]"]; 225 [label="Access variable R|/FirPsiSourceElement.psi| [3]"];
226 [label="Type operator: (this@R|/FirModifierList.Companion.getModifierList|.R|/FirPsiSourceElement.psi| as? R|KtModifierListOwner|) [6]"]; 226 [label="Type operator: (this@R|/FirModifierList.Companion.getModifierList|.R|/FirPsiSourceElement.psi| as? R|KtModifierListOwner|) [3]"];
227 [label="Enter safe call [6]"]; 227 [label="Enter safe call [3]"];
228 [label="Access variable R|/KtModifierListOwner.modifierList| [6]"]; 228 [label="Access variable R|/KtModifierListOwner.modifierList| [3]"];
229 [label="Enter safe call [6]"]; 229 [label="Enter safe call [3]"];
230 [label="Postponed enter to lambda [7]"]; 230 [label="Postponed enter to lambda [3]"];
subgraph cluster_67 { subgraph cluster_67 {
color=blue color=blue
231 [label="Enter function anonymousFunction [8]" style="filled" fillcolor=red]; 231 [label="Enter function anonymousFunction [4]" style="filled" fillcolor=red];
subgraph cluster_68 { subgraph cluster_68 {
color=blue color=blue
232 [label="Enter block [8]"]; 232 [label="Enter block [4]"];
233 [label="Access variable R|<local>/it| [9]"]; 233 [label="Access variable R|<local>/it| [4]"];
234 [label="Function call: R|/FirModifierList.FirPsiModifierList.FirPsiModifierList|(...) [8]" style="filled" fillcolor=yellow]; 234 [label="Function call: R|/FirModifierList.FirPsiModifierList.FirPsiModifierList|(...) [4]" style="filled" fillcolor=yellow];
235 [label="Exit block [8]"]; 235 [label="Exit block [4]"];
} }
236 [label="Exit function anonymousFunction [8]" style="filled" fillcolor=red]; 236 [label="Exit function anonymousFunction [4]" style="filled" fillcolor=red];
} }
237 [label="Postponed exit from lambda [7]"]; 237 [label="Postponed exit from lambda [3]"];
238 [label="Function call: $subj$.R|kotlin/let|<R|KtModifierList|, R|FirModifierList.FirPsiModifierList|>(...) [6]" style="filled" fillcolor=yellow]; 238 [label="Function call: $subj$.R|kotlin/let|<R|KtModifierList|, R|FirModifierList.FirPsiModifierList|>(...) [3]" style="filled" fillcolor=yellow];
239 [label="Exit safe call [6]"]; 239 [label="Exit safe call [3]"];
240 [label="Exit safe call [6]"]; 240 [label="Exit safe call [3]"];
241 [label="Exit block [6]"]; 241 [label="Exit block [3]"];
} }
242 [label="Exit when branch result [5]"]; 242 [label="Exit when branch result [3]"];
243 [label="Merge postponed lambda exits [6]"]; 243 [label="Merge postponed lambda exits [3]"];
244 [label="Enter when branch result [5]"]; 244 [label="Enter when branch result [3]"];
subgraph cluster_69 { subgraph cluster_69 {
color=blue color=blue
245 [label="Enter block [5]"]; 245 [label="Enter block [3]"];
246 [label="Const: Null(null) [5]"]; 246 [label="Const: Null(null) [3]"];
247 [label="Exit block [5]"]; 247 [label="Exit block [3]"];
} }
248 [label="Exit when branch result [4]"]; 248 [label="Exit when branch result [3]"];
249 [label="Exit when [3]"]; 249 [label="Exit when [3]"];
} }
250 [label="Jump: ^getModifierList when (this@R|/FirModifierList.Companion.getModifierList|) { 250 [label="Jump: ^getModifierList when (this@R|/FirModifierList.Companion.getModifierList|) {
@@ -861,7 +861,7 @@ digraph kt44814_kt {
subgraph cluster_78 { subgraph cluster_78 {
color=blue color=blue
274 [label="Enter block [1]"]; 274 [label="Enter block [1]"];
275 [label="Access qualifier /FirModifierList [2]"]; 275 [label="Access qualifier /FirModifierList [1]"];
276 [label="Function call: Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]" style="filled" fillcolor=yellow]; 276 [label="Function call: Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]" style="filled" fillcolor=yellow];
277 [label="Jump: ^box Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]"]; 277 [label="Jump: ^box Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]"];
278 [label="Stub [1]" style="filled" fillcolor=gray]; 278 [label="Stub [1]" style="filled" fillcolor=gray];