Make Node's edges be nullable and point to null instead of empty list
This commit is contained in:
committed by
Pavel Punegov
parent
67385f3096
commit
f517d5b4a3
+5
-5
@@ -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)]!!)
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-20
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user