FIR DFA: attach PersistentFlow directly to nodes
This commit is contained in:
+1
-1
@@ -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<*>) {
|
||||||
|
|||||||
+8
-19
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user