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 bcb0735bfd9..1ba318a3d8f 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 @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.util.IntArrayList import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.builders.* @@ -119,10 +120,9 @@ internal object Devirtualization { private val symbolTable = moduleDFG.symbolTable - sealed class Node(val id: Int) : DirectedGraphNode { - override var directEdges: MutableList? = null - override var reversedEdges : MutableList? = null - override val key get() = this + sealed class Node(val id: Int) { + var directEdges: IntArrayList? = null + var reversedEdges: IntArrayList? = null var directCastEdges: MutableList? = null var reversedCastEdges: MutableList? = null @@ -137,10 +137,10 @@ internal object Devirtualization { val multiNodeSize get() = multiNodeEnd - multiNodeStart fun addEdge(node: Node) { - if (directEdges == null) directEdges = ArrayList(1) - directEdges!!.add(node) - if (node.reversedEdges == null) node.reversedEdges = ArrayList(1) - node.reversedEdges!!.add(this) + if (directEdges == null) directEdges = IntArrayList() + node.directEdges!!.add(node.id) + if (node.reversedEdges == null) node.reversedEdges = IntArrayList() + node.reversedEdges!!.add(id) } fun addCastEdge(edge: CastEdge) { @@ -177,12 +177,11 @@ internal object Devirtualization { class Function(val symbol: DataFlowIR.FunctionSymbol, val parameters: Array, val returns: Node, val throws: Node) - inner class ConstraintGraph : DirectedGraph { + inner class ConstraintGraph { private var nodesCount = 0 - override val nodes = mutableListOf() - override fun get(key: Node) = key + val nodes = mutableListOf() val voidNode = addNode { Node.Ordinary(it, { "Void" }) } val virtualNode = addNode { Node.Source(it, VIRTUAL_TYPE_ID, { "Virtual" }) } @@ -449,11 +448,12 @@ internal object Devirtualization { fun BitSet.copy() = BitSet(this.size()).apply { this.or(this@copy) } fun printPathToType(node: Node, type: Int) { - val visited = mutableSetOf() + val nodes = constraintGraph.nodes + val visited = BitSet() val prev = mutableMapOf() var front = mutableListOf() front.add(node) - visited.add(node) + visited.set(node.id) lateinit var source: Node.Source bfs@while (front.isNotEmpty()) { val prevFront = front @@ -461,9 +461,10 @@ internal object Devirtualization { 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) + for (toId in reversedEdges) { + val to = nodes[toId] + if (!visited[toId] && to.types[type]) { + visited.set(toId) prev[to] = from front.add(to) if (to is Node.Source) { @@ -476,8 +477,8 @@ internal object Devirtualization { if (reversedCastEdges != null) for (castEdge in reversedCastEdges) { val to = castEdge.node - if (!visited.contains(to) && castEdge.suitableTypes[type] && to.types[type]) { - visited.add(to) + if (!visited[to.id] && castEdge.suitableTypes[type] && to.types[type]) { + visited.set(to.id) prev[to] = from front.add(to) if (to is Node.Source) { @@ -552,8 +553,8 @@ internal object Devirtualization { private fun findOrder(node: Node, order: IntArray) { visited.set(node.id) node.directEdges?.forEach { - if (!visited[it.id]) - findOrder(it, order) + if (!visited[it]) + findOrder(nodes[it], order) } order[index++] = node.id } @@ -562,8 +563,8 @@ internal object Devirtualization { visited.set(node.id) multiNodes[index++] = node.id node.reversedEdges?.forEach { - if (!visited[it.id]) - paint(it) + if (!visited[it]) + paint(nodes[it]) } } @@ -572,7 +573,7 @@ internal object Devirtualization { for (v in multiNode.multiNodeStart until multiNode.multiNodeEnd) { val node = nodes[multiNodes[v]] node.directEdges?.forEach { - val nextMultiNode = multiNodes[it.multiNodeStart] + val nextMultiNode = multiNodes[nodes[it].multiNodeStart] if (!visited[nextMultiNode]) findMultiNodesOrder(nodes[nextMultiNode], order) } @@ -605,7 +606,7 @@ internal object Devirtualization { constraintGraph.nodes.forEach { println(" NODE #${it.id}") it.directEdges?.forEach { - println(" EDGE: #${it.id}z") + println(" EDGE: #${it}z") } it.directCastEdges?.forEach { println(" CAST EDGE: #${it.node.id}z casted to ${it.suitableTypes.format(allTypes)}") @@ -666,7 +667,7 @@ internal object Devirtualization { continue // A source has no incoming edges. val types = BitSet() condensation.forEachNode(multiNode) { node -> - node.reversedEdges?.forEach { types.or(it.types) } + node.reversedEdges?.forEach { types.or(constraintGraph.nodes[it].types) } node.reversedCastEdges ?.filter { it.node.priority < node.priority } // Doesn't contradict topological order. ?.forEach { @@ -720,7 +721,8 @@ internal object Devirtualization { for (i in 0 until prevFrontSize) { marked[prevFront[i]] = false val node = constraintGraph.nodes[prevFront[i]] - node.directEdges?.forEach { distNode -> + node.directEdges?.forEach { distNodeId -> + val distNode = constraintGraph.nodes[distNodeId] if (marked[distNode.id]) distNode.types.or(node.types) else { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/util/PrimitiveLists.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/util/PrimitiveLists.kt new file mode 100644 index 00000000000..f49bf6fae8c --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/util/PrimitiveLists.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package org.jetbrains.kotlin.backend.konan.util + +class IntArrayList : Iterable { + private var array = IntArray(3) + private var length = 0 + + val size get() = length + + fun isEmpty() = size == 0 + + fun add(x: Int) { + length++ + ensureCapacity(length) + set(length - 1, x) + } + + fun reserve(minSize: Int) { + if (length >= minSize) return + length = minSize + ensureCapacity(minSize) + } + + operator fun get(index: Int): Int = when { + index < 0 || index >= length -> throw IndexOutOfBoundsException("Index out of range: $index") + + else -> array[index] + } + + operator fun set(index: Int, x: Int) = when { + index < 0 || index >= length -> throw IndexOutOfBoundsException("Index out of range: $index") + + else -> array[index] = x + } + + override operator fun iterator(): Iterator = Itr() + + private fun ensureCapacity(minCapacity: Int) { + val oldArray = array + if (minCapacity > oldArray.size) { + var newSize = oldArray.size * 3 / 2 + if (minCapacity > newSize) + newSize = minCapacity + array = oldArray.copyOf(newSize) + } + } + + private inner class Itr : Iterator { + private var index = 0 + + override fun hasNext() = index < size + + override fun next() = get(index++) + } +} \ No newline at end of file