Make Node's edges be nullable and point to null instead of empty list

This commit is contained in:
Pavel Punegov
2018-04-26 16:44:06 +03:00
committed by Pavel Punegov
parent 67385f3096
commit f517d5b4a3
2 changed files with 30 additions and 25 deletions
@@ -18,8 +18,8 @@ package org.jetbrains.kotlin.backend.konan
internal interface DirectedGraphNode<out K> { internal interface DirectedGraphNode<out K> {
val key: K val key: K
val directEdges: List<K> val directEdges: List<K>?
val reversedEdges: List<K> val reversedEdges: List<K>?
} }
internal interface DirectedGraph<K, out N: DirectedGraphNode<K>> { internal interface DirectedGraph<K, out N: DirectedGraphNode<K>> {
@@ -70,7 +70,7 @@ internal class DirectedGraphCondensationBuilder<K, out N: DirectedGraphNode<K>>(
private fun findOrder(node: N) { private fun findOrder(node: N) {
visited += node.key visited += node.key
node.directEdges.forEach { node.directEdges?.forEach {
if (!visited.contains(it)) if (!visited.contains(it))
findOrder(graph.get(it)) findOrder(graph.get(it))
} }
@@ -80,7 +80,7 @@ internal class DirectedGraphCondensationBuilder<K, out N: DirectedGraphNode<K>>(
private fun paint(node: N, multiNode: MutableSet<K>) { private fun paint(node: N, multiNode: MutableSet<K>) {
visited += node.key visited += node.key
multiNode += node.key multiNode += node.key
node.reversedEdges.forEach { node.reversedEdges?.forEach {
if (!visited.contains(it)) if (!visited.contains(it))
paint(graph.get(it), multiNode) paint(graph.get(it), multiNode)
} }
@@ -89,7 +89,7 @@ internal class DirectedGraphCondensationBuilder<K, out N: DirectedGraphNode<K>>(
private fun findMultiNodesOrder(node: DirectedGraphMultiNode<K>) { private fun findMultiNodesOrder(node: DirectedGraphMultiNode<K>) {
visited.addAll(node.nodes) visited.addAll(node.nodes)
node.nodes.forEach { node.nodes.forEach {
graph.get(it).directEdges.forEach { graph.get(it).directEdges?.forEach {
if (!visited.contains(it)) if (!visited.contains(it))
findMultiNodesOrder(nodeToMultiNodeMap[graph.get(it)]!!) findMultiNodesOrder(nodeToMultiNodeMap[graph.get(it)]!!)
} }
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import java.util.* import java.util.*
import kotlin.collections.ArrayList
// Devirtualization analysis is performed using Variable Type Analysis algorithm. // Devirtualization analysis is performed using Variable Type Analysis algorithm.
// See http://web.cs.ucla.edu/~palsberg/tba/papers/sundaresan-et-al-oopsla00.pdf for details. // See http://web.cs.ucla.edu/~palsberg/tba/papers/sundaresan-et-al-oopsla00.pdf for details.
@@ -103,25 +104,29 @@ internal object Devirtualization {
private val symbolTable = moduleDFG.symbolTable private val symbolTable = moduleDFG.symbolTable
sealed class Node(val id: Int) : DirectedGraphNode<Node> { sealed class Node(val id: Int) : DirectedGraphNode<Node> {
override val directEdges = mutableListOf<Node>() override var directEdges: MutableList<Node>? = null
override val reversedEdges = mutableListOf<Node>() override var reversedEdges : MutableList<Node>? = null
override val key get() = this override val key get() = this
val directCastEdges = mutableListOf<CastEdge>() var directCastEdges: MutableList<CastEdge>? = null
val reversedCastEdges = mutableListOf<CastEdge>() var reversedCastEdges: MutableList<CastEdge>? = null
val types = BitSet() val types = BitSet()
var priority = -1 var priority = -1
fun addEdge(node: Node) { fun addEdge(node: Node) {
directEdges += node if (directEdges == null) directEdges = ArrayList(1)
node.reversedEdges += this directEdges!!.add(node)
if (node.reversedEdges == null) node.reversedEdges = ArrayList(1)
node.reversedEdges!!.add(this)
} }
fun addCastEdge(edge: CastEdge) { fun addCastEdge(edge: CastEdge) {
directCastEdges += edge if (directCastEdges == null) directCastEdges = ArrayList(1)
edge.node.reversedCastEdges += CastEdge(this, edge.suitableTypes) directCastEdges!!.add(edge)
if (edge.node.reversedCastEdges == null) edge.node.reversedCastEdges = ArrayList(1)
edge.node.reversedCastEdges!!.add(CastEdge(this, edge.suitableTypes))
} }
abstract fun toString(allTypes: List<DataFlowIR.Type.Declared>): String abstract fun toString(allTypes: List<DataFlowIR.Type.Declared>): String
@@ -407,10 +412,10 @@ internal object Devirtualization {
println("FULL CONSTRAINT GRAPH") println("FULL CONSTRAINT GRAPH")
constraintGraph.nodes.forEach { constraintGraph.nodes.forEach {
println(" NODE #${it.id}") println(" NODE #${it.id}")
it.directEdges.forEach { it.directEdges?.forEach {
println(" EDGE: #${it.id}z") println(" EDGE: #${it.id}z")
} }
it.directCastEdges.forEach { it.directCastEdges?.forEach {
println(" CAST EDGE: #${it.node.id}z casted to ${it.suitableTypes.format(allTypes)}") println(" CAST EDGE: #${it.node.id}z casted to ${it.suitableTypes.format(allTypes)}")
} }
allTypes.forEachIndexed { index, type -> allTypes.forEachIndexed { index, type ->
@@ -422,14 +427,14 @@ internal object Devirtualization {
constraintGraph.nodes.forEach { constraintGraph.nodes.forEach {
if (it is Node.Source) { if (it is Node.Source) {
assert(it.reversedEdges.isEmpty(), { "A source node #${it.id} has incoming edges" }) assert(it.reversedEdges?.isEmpty() ?: true, { "A source node #${it.id} has incoming edges" })
assert(it.reversedCastEdges.isEmpty(), { "A source node #${it.id} has incoming edges" }) assert(it.reversedCastEdges?.isEmpty() ?: true, { "A source node #${it.id} has incoming edges" })
} }
} }
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
println("CONSTRAINT GRAPH: ${constraintGraph.nodes.size} nodes, " + println("CONSTRAINT GRAPH: ${constraintGraph.nodes.size} nodes, " +
"${constraintGraph.nodes.sumBy { it.directEdges.size + it.directCastEdges.size } } edges") "${constraintGraph.nodes.sumBy { (it.directEdges?.size ?: 0) + (it.directCastEdges?.size ?: 0) } } edges")
} }
val topologicalOrder = DirectedGraphCondensationBuilder(constraintGraph).build().topologicalOrder val topologicalOrder = DirectedGraphCondensationBuilder(constraintGraph).build().topologicalOrder
@@ -453,10 +458,10 @@ internal object Devirtualization {
continue // A source has no incoming edges. continue // A source has no incoming edges.
val types = BitSet() val types = BitSet()
for (node in multiNode.nodes) { for (node in multiNode.nodes) {
node.reversedEdges.forEach { types.or(it.types) } node.reversedEdges?.forEach { types.or(it.types) }
node.reversedCastEdges node.reversedCastEdges
.filter { it.node.priority < node.priority } // Doesn't contradict topological order. ?.filter { it.node.priority < node.priority } // Doesn't contradict topological order.
.forEach { ?.forEach {
val sourceTypes = it.node.types.copy() val sourceTypes = it.node.types.copy()
sourceTypes.and(it.suitableTypes) sourceTypes.and(it.suitableTypes)
types.or(sourceTypes) types.or(sourceTypes)
@@ -468,20 +473,20 @@ internal object Devirtualization {
val badEdges = mutableListOf<Pair<Node, Node.CastEdge>>() val badEdges = mutableListOf<Pair<Node, Node.CastEdge>>()
for (node in constraintGraph.nodes) { for (node in constraintGraph.nodes) {
node.directCastEdges node.directCastEdges
.filter { it.node.priority < node.priority } // Contradicts topological order. ?.filter { it.node.priority < node.priority } // Contradicts topological order.
.forEach { badEdges += node to it } ?.forEach { badEdges += node to it }
} }
badEdges.sortBy { it.second.node.priority } // Heuristic. badEdges.sortBy { it.second.node.priority } // Heuristic.
do { do {
fun propagateTypes(node: Node, types: BitSet) { fun propagateTypes(node: Node, types: BitSet) {
node.types.or(types) node.types.or(types)
for (edge in node.directEdges) { node.directEdges?.forEach { edge ->
val missingTypes = types.copy().apply { andNot(edge.types) } val missingTypes = types.copy().apply { andNot(edge.types) }
if (!missingTypes.isEmpty) if (!missingTypes.isEmpty)
propagateTypes(edge, missingTypes) propagateTypes(edge, missingTypes)
} }
for (castEdge in node.directCastEdges) { node.directCastEdges?.forEach { castEdge ->
val missingTypes = types.copy().apply { andNot(castEdge.node.types) } val missingTypes = types.copy().apply { andNot(castEdge.node.types) }
missingTypes.and(castEdge.suitableTypes) missingTypes.and(castEdge.suitableTypes)
if (!missingTypes.isEmpty) if (!missingTypes.isEmpty)