diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/GraphAlgorithms.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/GraphAlgorithms.kt index 472c80ca98d..b9f44975dc7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/GraphAlgorithms.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/GraphAlgorithms.kt @@ -18,8 +18,8 @@ package org.jetbrains.kotlin.backend.konan internal interface DirectedGraphNode { val key: K - val directEdges: List - val reversedEdges: List + val directEdges: List? + val reversedEdges: List? } internal interface DirectedGraph> { @@ -70,7 +70,7 @@ internal class DirectedGraphCondensationBuilder>( private fun findOrder(node: N) { visited += node.key - node.directEdges.forEach { + node.directEdges?.forEach { if (!visited.contains(it)) findOrder(graph.get(it)) } @@ -80,7 +80,7 @@ internal class DirectedGraphCondensationBuilder>( private fun paint(node: N, multiNode: MutableSet) { visited += node.key multiNode += node.key - node.reversedEdges.forEach { + node.reversedEdges?.forEach { if (!visited.contains(it)) paint(graph.get(it), multiNode) } @@ -89,7 +89,7 @@ internal class DirectedGraphCondensationBuilder>( private fun findMultiNodesOrder(node: DirectedGraphMultiNode) { visited.addAll(node.nodes) node.nodes.forEach { - graph.get(it).directEdges.forEach { + graph.get(it).directEdges?.forEach { if (!visited.contains(it)) findMultiNodesOrder(nodeToMultiNodeMap[graph.get(it)]!!) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt index 97c1fa34436..870074e7dda 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt @@ -43,6 +43,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.types.KotlinType import java.util.* +import kotlin.collections.ArrayList // 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. @@ -103,25 +104,29 @@ internal object Devirtualization { private val symbolTable = moduleDFG.symbolTable sealed class Node(val id: Int) : DirectedGraphNode { - override val directEdges = mutableListOf() - override val reversedEdges = mutableListOf() + override var directEdges: MutableList? = null + override var reversedEdges : MutableList? = null override val key get() = this - val directCastEdges = mutableListOf() - val reversedCastEdges = mutableListOf() + var directCastEdges: MutableList? = null + var reversedCastEdges: MutableList? = null val types = BitSet() var priority = -1 fun addEdge(node: Node) { - directEdges += node - node.reversedEdges += this + if (directEdges == null) directEdges = ArrayList(1) + directEdges!!.add(node) + if (node.reversedEdges == null) node.reversedEdges = ArrayList(1) + node.reversedEdges!!.add(this) } fun addCastEdge(edge: CastEdge) { - directCastEdges += edge - edge.node.reversedCastEdges += CastEdge(this, edge.suitableTypes) + if (directCastEdges == null) directCastEdges = ArrayList(1) + 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): String @@ -407,10 +412,10 @@ internal object Devirtualization { println("FULL CONSTRAINT GRAPH") constraintGraph.nodes.forEach { println(" NODE #${it.id}") - it.directEdges.forEach { + it.directEdges?.forEach { println(" EDGE: #${it.id}z") } - it.directCastEdges.forEach { + it.directCastEdges?.forEach { println(" CAST EDGE: #${it.node.id}z casted to ${it.suitableTypes.format(allTypes)}") } allTypes.forEachIndexed { index, type -> @@ -422,14 +427,14 @@ internal object Devirtualization { constraintGraph.nodes.forEach { if (it is Node.Source) { - assert(it.reversedEdges.isEmpty(), { "A source node #${it.id} has incoming edges" }) - assert(it.reversedCastEdges.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() ?: true, { "A source node #${it.id} has incoming edges" }) } } DEBUG_OUTPUT(0) { 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 @@ -453,10 +458,10 @@ internal object Devirtualization { continue // A source has no incoming edges. val types = BitSet() for (node in multiNode.nodes) { - node.reversedEdges.forEach { types.or(it.types) } + node.reversedEdges?.forEach { types.or(it.types) } node.reversedCastEdges - .filter { it.node.priority < node.priority } // Doesn't contradict topological order. - .forEach { + ?.filter { it.node.priority < node.priority } // Doesn't contradict topological order. + ?.forEach { val sourceTypes = it.node.types.copy() sourceTypes.and(it.suitableTypes) types.or(sourceTypes) @@ -468,20 +473,20 @@ internal object Devirtualization { val badEdges = mutableListOf>() for (node in constraintGraph.nodes) { node.directCastEdges - .filter { it.node.priority < node.priority } // Contradicts topological order. - .forEach { badEdges += node to it } + ?.filter { it.node.priority < node.priority } // Contradicts topological order. + ?.forEach { badEdges += node to it } } badEdges.sortBy { it.second.node.priority } // Heuristic. do { fun propagateTypes(node: Node, types: BitSet) { node.types.or(types) - for (edge in node.directEdges) { + node.directEdges?.forEach { edge -> val missingTypes = types.copy().apply { andNot(edge.types) } if (!missingTypes.isEmpty) propagateTypes(edge, missingTypes) } - for (castEdge in node.directCastEdges) { + node.directCastEdges?.forEach { castEdge -> val missingTypes = types.copy().apply { andNot(castEdge.node.types) } missingTypes.and(castEdge.suitableTypes) if (!missingTypes.isEmpty)