FIR DFA: attach PersistentFlow directly to nodes

This commit is contained in:
pyos
2022-11-19 20:23:17 +01:00
committed by teamcity
parent 8d2ac141c3
commit e79b595639
4 changed files with 22 additions and 21 deletions
@@ -87,7 +87,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
} }
} }
var flow = dataFlowInfo.flowOnNodes.getValue(node) var flow = node.flow
val operation = effect.value.toOperation() val operation = effect.value.toOperation()
if (operation != null) { if (operation != null) {
if (resultExpression is FirConstExpression<*>) { if (resultExpression is FirConstExpression<*>) {
@@ -39,12 +39,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
class DataFlowAnalyzerContext( class DataFlowAnalyzerContext(
val graphBuilder: ControlFlowGraphBuilder, val graphBuilder: ControlFlowGraphBuilder,
variableStorage: VariableStorageImpl, variableStorage: VariableStorageImpl,
flowOnNodes: MutableMap<CFGNode<*>, PersistentFlow>,
val preliminaryLoopVisitor: PreliminaryLoopVisitor, val preliminaryLoopVisitor: PreliminaryLoopVisitor,
val variablesClearedBeforeLoop: Stack<List<RealVariable>>, val variablesClearedBeforeLoop: Stack<List<RealVariable>>,
) { ) {
var flowOnNodes = flowOnNodes
private set
var variableStorage = variableStorage var variableStorage = variableStorage
private set private set
@@ -58,10 +55,7 @@ class DataFlowAnalyzerContext(
fun reset() { fun reset() {
graphBuilder.reset() graphBuilder.reset()
variableStorage = variableStorage.clear() variableStorage = variableStorage.clear()
flowOnNodes = mutableMapOf()
preliminaryLoopVisitor.resetState() preliminaryLoopVisitor.resetState()
variablesClearedBeforeLoop.reset() variablesClearedBeforeLoop.reset()
firLocalVariableAssignmentAnalyzer = null firLocalVariableAssignmentAnalyzer = null
@@ -71,7 +65,7 @@ class DataFlowAnalyzerContext(
fun empty(session: FirSession): DataFlowAnalyzerContext = fun empty(session: FirSession): DataFlowAnalyzerContext =
DataFlowAnalyzerContext( DataFlowAnalyzerContext(
ControlFlowGraphBuilder(), VariableStorageImpl(session), ControlFlowGraphBuilder(), VariableStorageImpl(session),
mutableMapOf(), PreliminaryLoopVisitor(), stackOf() PreliminaryLoopVisitor(), stackOf()
) )
} }
} }
@@ -210,15 +204,13 @@ abstract class FirDataFlowAnalyzer(
variableStorage.removeRealVariable(valueParameter.symbol) variableStorage.removeRealVariable(valueParameter.symbol)
} }
} }
val variableStorage = variableStorage val info = DataFlowInfo(variableStorage)
val flowOnNodes = context.flowOnNodes
if (graphBuilder.isTopLevel()) { if (graphBuilder.isTopLevel()) {
context.reset() context.reset()
} else { } else {
resetReceivers() resetReceivers()
} }
return FirControlFlowGraphReferenceImpl(graph, DataFlowInfo(variableStorage, flowOnNodes)) return FirControlFlowGraphReferenceImpl(graph, info)
} }
// ----------------------------------- Anonymous function ----------------------------------- // ----------------------------------- Anonymous function -----------------------------------
@@ -253,6 +245,7 @@ abstract class FirDataFlowAnalyzer(
} }
functionExitNode.mergeIncomingFlow() functionExitNode.mergeIncomingFlow()
if (postponedLambdaExitNode != null) { if (postponedLambdaExitNode != null) {
// Data flow changed, need to recompute. TODO: this violates the "flow computed only once" principle.
postponedLambdaExitNode.mergeIncomingFlow() postponedLambdaExitNode.mergeIncomingFlow()
} else { } else {
resetReceivers() resetReceivers()
@@ -1208,11 +1201,6 @@ abstract class FirDataFlowAnalyzer(
} }
} }
private val CFGNode<*>.flow: PersistentFlow
get() = context.flowOnNodes.getValue(this.origin)
private val CFGNode<*>.origin: CFGNode<*> get() = if (this is StubNode) firstPreviousNode else this
private val CFGNode<*>.livePreviousFlows: List<PersistentFlow> private val CFGNode<*>.livePreviousFlows: List<PersistentFlow>
get() = previousNodes.mapNotNull { it.takeIf { this.isDead || !it.isDead }?.flow } get() = previousNodes.mapNotNull { it.takeIf { this.isDead || !it.isDead }?.flow }
@@ -1242,13 +1230,14 @@ abstract class FirDataFlowAnalyzer(
return result return result
} }
@OptIn(CfgInternals::class)
private fun UnionFunctionCallArgumentsNode.unionFlowFromArguments() { private fun UnionFunctionCallArgumentsNode.unionFlowFromArguments() {
context.flowOnNodes[this] = logicSystem.joinFlow(previousNodes.map { it.flow }, union = true).freeze() flow = logicSystem.joinFlow(previousNodes.map { it.flow }, union = true).freeze()
} }
@OptIn(CfgInternals::class)
private fun CFGNode<*>.setFlow(builder: MutableFlow): PersistentFlow { private fun CFGNode<*>.setFlow(builder: MutableFlow): PersistentFlow {
val flow = builder.freeze() val flow = builder.freeze().also { this.flow = it }
context.flowOnNodes[this] = flow
if (currentReceiverState === builder) { if (currentReceiverState === builder) {
currentReceiverState = flow currentReceiverState = flow
} }
@@ -25,7 +25,7 @@ class FirControlFlowGraphReferenceImpl(
} }
} }
class DataFlowInfo(val variableStorage: VariableStorage, val flowOnNodes: Map<CFGNode<*>, PersistentFlow>) class DataFlowInfo(val variableStorage: VariableStorage)
val FirControlFlowGraphReference.controlFlowGraph: ControlFlowGraph? val FirControlFlowGraphReference.controlFlowGraph: ControlFlowGraph?
get() = (this as? FirControlFlowGraphReferenceImpl)?.controlFlowGraph get() = (this as? FirControlFlowGraphReferenceImpl)?.controlFlowGraph
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.dfa.PersistentFlow
import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph
import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.fir.visitors.FirVisitor
@@ -125,6 +126,12 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
var isDead: Boolean = false var isDead: Boolean = false
protected set protected set
private var _flow: PersistentFlow? = null
open var flow: PersistentFlow
get() = _flow ?: throw IllegalStateException("flow for $this not initialized - traversing nodes in wrong order?")
@CfgInternals
set(value) { _flow = value } // TODO: forbid reassignment
@CfgInternals @CfgInternals
fun updateDeadStatus() { fun updateDeadStatus() {
isDead = incomingEdges.size == previousNodes.size && incomingEdges.values.all { isDead = incomingEdges.size == previousNodes.size && incomingEdges.values.all {
@@ -747,6 +754,11 @@ class StubNode(owner: ControlFlowGraph, level: Int, id: Int) : CFGNode<FirStub>(
override val fir: FirStub get() = FirStub override val fir: FirStub get() = FirStub
override var flow: PersistentFlow
get() = firstPreviousNode.flow
@CfgInternals
set(_) = throw IllegalStateException("can't set flow for stub node")
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R { override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitStubNode(this, data) return visitor.visitStubNode(this, data)
} }