[K/N][optmz] Fixed a bug in the escape analysis algorithm

Because of the problem, some edges in the points-to graph
might be lost (related to singletons and arrays).
This commit is contained in:
Igor Chevdar
2022-10-31 12:14:43 +02:00
committed by Space Team
parent 4fd64fad2f
commit df371e8f17
2 changed files with 32 additions and 24 deletions
@@ -28,7 +28,7 @@ internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.Functi
graph.reversedEdges[symbol]!!
}
class CallSite(val call: DataFlowIR.Node.Call, val isVirtual: Boolean, val actualCallee: DataFlowIR.FunctionSymbol)
class CallSite(val call: DataFlowIR.Node.Call, val node: DataFlowIR.Node, val isVirtual: Boolean, val actualCallee: DataFlowIR.FunctionSymbol)
val callSites = mutableListOf<CallSite>()
}
@@ -105,20 +105,21 @@ internal class CallGraphBuilder(
reversedEdges[symbol] = mutableListOf()
}
private inline fun DataFlowIR.FunctionBody.forEachCallSite(block: (DataFlowIR.Node.Call) -> Unit): Unit =
private inline fun DataFlowIR.FunctionBody.forEachCallSite(block: (DataFlowIR.Node.Call, DataFlowIR.Node) -> Unit): Unit =
forEachNonScopeNode { node ->
when (node) {
is DataFlowIR.Node.Call -> block(node)
is DataFlowIR.Node.Call -> block(node, node)
is DataFlowIR.Node.Singleton ->
node.constructor?.let { block(DataFlowIR.Node.Call(it, node.arguments ?: emptyList(), node.type, null)) }
node.constructor?.let { block(DataFlowIR.Node.Call(it, node.arguments ?: emptyList(), node.type, null), node) }
is DataFlowIR.Node.ArrayRead ->
block(DataFlowIR.Node.Call(
callee = node.callee,
arguments = listOf(node.array, node.index),
returnType = node.type,
irCallSite = null)
irCallSite = null),
node
)
is DataFlowIR.Node.ArrayWrite ->
@@ -126,7 +127,8 @@ internal class CallGraphBuilder(
callee = node.callee,
arguments = listOf(node.array, node.index, node.value),
returnType = moduleDFG.symbolTable.mapType(context.irBuiltIns.unitType),
irCallSite = null)
irCallSite = null),
node
)
is DataFlowIR.Node.FunctionReference ->
@@ -134,16 +136,17 @@ internal class CallGraphBuilder(
callee = node.symbol,
arguments = emptyList(),
returnType = node.symbol.returnParameter.type,
irCallSite = null
))
irCallSite = null),
node
)
else -> { }
}
}
private fun staticCall(caller: DataFlowIR.FunctionSymbol.Declared, call: DataFlowIR.Node.Call, callee: DataFlowIR.FunctionSymbol) {
private fun staticCall(caller: DataFlowIR.FunctionSymbol.Declared, call: DataFlowIR.Node.Call, node: DataFlowIR.Node, callee: DataFlowIR.FunctionSymbol) {
val resolvedCallee = callee.resolved()
val callSite = CallGraphNode.CallSite(call, false, resolvedCallee)
val callSite = CallGraphNode.CallSite(call, node, false, resolvedCallee)
val function = moduleDFG.functions[resolvedCallee]
callGraph.addEdge(caller, callSite)
if (function != null)
@@ -152,14 +155,14 @@ internal class CallGraphBuilder(
private fun handleFunction(symbol: DataFlowIR.FunctionSymbol.Declared, function: DataFlowIR.Function) {
val body = function.body
body.forEachCallSite { call ->
body.forEachCallSite { call, node ->
val devirtualizedCallSite = (call as? DataFlowIR.Node.VirtualCall)?.let { devirtualizedCallSites[it] }
when {
call !is DataFlowIR.Node.VirtualCall -> staticCall(symbol, call, call.callee)
call !is DataFlowIR.Node.VirtualCall -> staticCall(symbol, call, node, call.callee)
devirtualizedCallSite != null -> {
devirtualizedCallSite.possibleCallees.forEach {
staticCall(symbol, call, it.callee)
staticCall(symbol, call, node, it.callee)
}
}
@@ -189,9 +192,9 @@ internal class CallGraphBuilder(
allPossibleCallees.add(actualCallee)
}
if (allPossibleCallees.size <= nonDevirtualizedCallSitesUnfoldFactor)
allPossibleCallees.forEach { staticCall(symbol, call, it) }
allPossibleCallees.forEach { staticCall(symbol, call, node, it) }
else {
val callSite = CallGraphNode.CallSite(call, true, call.callee)
val callSite = CallGraphNode.CallSite(call, node, true, call.callee)
callGraph.addEdge(symbol, callSite)
allPossibleCallees.forEach {
@@ -29,6 +29,19 @@ private val DataFlowIR.Node.ir
else -> null
}
private val CallGraphNode.CallSite.arguments: List<DataFlowIR.Node>
get() {
return if (call is DataFlowIR.Node.NewObject) {
(0..call.arguments.size).map {
if (it == 0) node else call.arguments[it - 1].node
}
} else {
(0..call.arguments.size).map {
if (it < call.arguments.size) call.arguments[it].node else node
}
}
}
internal object EscapeAnalysis {
/*
@@ -991,15 +1004,7 @@ internal object EscapeAnalysis {
+calleeEscapeAnalysisResult.toString()
}
val arguments = if (call is DataFlowIR.Node.NewObject) {
(0..call.arguments.size).map {
if (it == 0) call else call.arguments[it - 1].node
}
} else {
(0..call.arguments.size).map {
if (it < call.arguments.size) call.arguments[it].node else call
}
}
val arguments = callSite.arguments
val calleeDrains = Array(calleeEscapeAnalysisResult.numberOfDrains) { newNode() }