Added some debug output to devirtualization
This commit is contained in:
+63
-4
@@ -396,6 +396,53 @@ internal object Devirtualization {
|
||||
|
||||
fun BitSet.copy() = BitSet(this.size()).apply { this.or(this@copy) }
|
||||
|
||||
fun printPathToType(node: Node, type: Int) {
|
||||
val visited = mutableSetOf<Node>()
|
||||
val prev = mutableMapOf<Node, Node>()
|
||||
var front = mutableListOf<Node>()
|
||||
front.add(node)
|
||||
visited.add(node)
|
||||
lateinit var source: Node.Source
|
||||
bfs@while (front.isNotEmpty()) {
|
||||
val prevFront = front
|
||||
front = mutableListOf()
|
||||
for (from in prevFront) {
|
||||
val reversedEdges = from.reversedEdges
|
||||
if (reversedEdges != null)
|
||||
for (to in reversedEdges) {
|
||||
if (!visited.contains(to) && to.types[type]) {
|
||||
visited.add(to)
|
||||
prev[to] = from
|
||||
front.add(to)
|
||||
if (to is Node.Source) {
|
||||
source = to
|
||||
break@bfs
|
||||
}
|
||||
}
|
||||
}
|
||||
val reversedCastEdges = from.reversedCastEdges
|
||||
if (reversedCastEdges != null)
|
||||
for (castEdge in reversedCastEdges) {
|
||||
val to = castEdge.node
|
||||
if (!visited.contains(to) && castEdge.suitableTypes[type] && to.types[type]) {
|
||||
visited.add(to)
|
||||
prev[to] = from
|
||||
front.add(to)
|
||||
if (to is Node.Source) {
|
||||
source = to
|
||||
break@bfs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var cur: Node = source
|
||||
do {
|
||||
println(" #${cur.id}")
|
||||
cur = prev[cur]!!
|
||||
} while (cur != node)
|
||||
}
|
||||
|
||||
fun analyze(): Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite> {
|
||||
val functions = moduleDFG.functions + externalModulesDFG.functionDFGs
|
||||
val typeHierarchy = TypeHierarchy(symbolTable.classMap.values.filterIsInstance<DataFlowIR.Type.Declared>() +
|
||||
@@ -532,19 +579,31 @@ internal object Devirtualization {
|
||||
.forEach { virtualCall ->
|
||||
assert (nodesMap[virtualCall] != null, { "Node for virtual call $virtualCall has not been built" })
|
||||
val virtualCallSiteReceivers = constraintGraph.virtualCallSiteReceivers[virtualCall]
|
||||
if (virtualCallSiteReceivers == null || virtualCallSiteReceivers.receiver.types[VIRTUAL_TYPE_ID]) {
|
||||
?: error("virtualCallSiteReceivers were not built for virtual call $virtualCall")
|
||||
if (virtualCallSiteReceivers.receiver.types[VIRTUAL_TYPE_ID]) {
|
||||
|
||||
DEBUG_OUTPUT(0) {
|
||||
println("Unable to devirtualize callsite ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString() }")
|
||||
println("Unable to devirtualize callsite ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.callee.toString() }")
|
||||
println(" receiver is Virtual")
|
||||
printPathToType(virtualCallSiteReceivers.receiver, VIRTUAL_TYPE_ID)
|
||||
}
|
||||
|
||||
return@forEach
|
||||
}
|
||||
DEBUG_OUTPUT(0) {
|
||||
println("Devirtualized callsite ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.callee.toString() }")
|
||||
}
|
||||
val possibleReceivers = allTypes.withIndex()
|
||||
.filter { virtualCallSiteReceivers.receiver.types[it.index] }
|
||||
.map { it.value }
|
||||
.filterNot { it == nothing }
|
||||
.filterNot { it.value == nothing }
|
||||
.map {
|
||||
DEBUG_OUTPUT(0) {
|
||||
println("Path to type ${it.value}")
|
||||
printPathToType(virtualCallSiteReceivers.receiver, it.index)
|
||||
}
|
||||
it.value
|
||||
}
|
||||
|
||||
val map = virtualCallSiteReceivers.devirtualizedCallees.associateBy({ it.receiverType }, { it })
|
||||
result[virtualCall] = DevirtualizedCallSite(virtualCall.callee.resolved(), possibleReceivers.map { receiverType ->
|
||||
assert (map[receiverType] != null) {
|
||||
|
||||
Reference in New Issue
Block a user