From 19240d21eea30ee1a86c03951776bc410ef6b707 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Thu, 20 Feb 2020 18:36:02 +0300 Subject: [PATCH] [devirtualization] Removed some redundant data structures --- .../konan/optimizations/Devirtualization.kt | 157 ++++++++---------- 1 file changed, 70 insertions(+), 87 deletions(-) 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 b579de14aff..bcb0735bfd9 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 @@ -177,9 +177,6 @@ internal object Devirtualization { class Function(val symbol: DataFlowIR.FunctionSymbol, val parameters: Array, val returns: Node, val throws: Node) - class VirtualCallSiteReceivers(val receiver: Node, val caller: DataFlowIR.FunctionSymbol, - val devirtualizedCallees: List) - inner class ConstraintGraph : DirectedGraph { private var nodesCount = 0 @@ -195,7 +192,7 @@ internal object Devirtualization { val concreteClasses = mutableMapOf() val externalFunctions = mutableMapOf, Node>() val fields = mutableMapOf() // Do not distinguish receivers. - val virtualCallSiteReceivers = mutableMapOf() + val virtualCallSiteReceivers = mutableMapOf() private fun nextId(): Int = nodesCount++ @@ -249,6 +246,16 @@ internal object Devirtualization { } } + private fun DataFlowIR.Type.Declared.calleeAt(callSite: DataFlowIR.Node.VirtualCall) = when (callSite) { + is DataFlowIR.Node.VtableCall -> + vtable[callSite.calleeVtableIndex] + + is DataFlowIR.Node.ItableCall -> + itable[callSite.calleeHash]!! + + else -> error("Unreachable") + } + private inner class InstantiationsSearcher(val rootSet: List, val typeHierarchy: TypeHierarchy) { private val visited = mutableSetOf() @@ -312,15 +319,7 @@ internal object Devirtualization { println("Receiver type: $receiverType") } - val callee = when (virtualCall) { - is DataFlowIR.Node.VtableCall -> - receiverType.vtable[virtualCall.calleeVtableIndex] - - is DataFlowIR.Node.ItableCall -> - receiverType.itable[virtualCall.calleeHash]!! - - else -> error("Unreachable") - } + val callee = receiverType.calleeAt(virtualCall) dfs(callee, virtualCall.returnType) } @@ -765,63 +764,64 @@ internal object Devirtualization { val result = mutableMapOf>() val nothing = symbolTable.classMap[context.ir.symbols.nothing.owner] - functions.values - .asSequence() - .filter { constraintGraph.functions.containsKey(it.symbol) } - .flatMap { it.body.nodes.asSequence() } - .filterIsInstance() - .forEach { virtualCall -> - assert (nodesMap[virtualCall] != null) { "Node for virtual call $virtualCall has not been built" } - val virtualCallSiteReceivers = constraintGraph.virtualCallSiteReceivers[virtualCall] - ?: error("virtualCallSiteReceivers were not built for virtual call $virtualCall") - if (virtualCallSiteReceivers.receiver.types[VIRTUAL_TYPE_ID]) { + for (function in functions.values) { + if (!constraintGraph.functions.containsKey(function.symbol)) continue + for (node in function.body.nodes) { + val virtualCall = node as? DataFlowIR.Node.VirtualCall ?: continue + assert(nodesMap[virtualCall] != null) { "Node for virtual call $virtualCall has not been built" } + val receiverNode = constraintGraph.virtualCallSiteReceivers[virtualCall] + ?: error("virtualCallSiteReceivers were not built for virtual call $virtualCall") + if (receiverNode.types[VIRTUAL_TYPE_ID]) { - DEBUG_OUTPUT(0) { - 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())) + println("Unable to devirtualize callsite " + + (virtualCall.irCallSite?.let { ir2stringWhole(it) } + ?: virtualCall.callee.toString())) + println(" receiver is Virtual") + printPathToType(receiverNode, VIRTUAL_TYPE_ID) } - val inheritorsOfReceiverType = virtualCallSiteReceivers.devirtualizedCallees.map { it.receiverType }.toSet() - val possibleReceivers = allTypes.asSequence() - .withIndex() - .filter { virtualCallSiteReceivers.receiver.types[it.index] } - .filter { inheritorsOfReceiverType.contains(it.value) } - .filterNot { it.value == nothing } - .map { - DEBUG_OUTPUT(0) { - println("Path to type ${it.value}") - printPathToType(virtualCallSiteReceivers.receiver, it.index) - } - it.value - }.toList() - val map = virtualCallSiteReceivers.devirtualizedCallees.associateBy({ it.receiverType }, { it }) - result[virtualCall] = DevirtualizedCallSite(virtualCall.callee.resolved(), - possibleReceivers.map { receiverType -> - assert(map[receiverType] != null) { - "Non-expected receiver type $receiverType at call site: " + - (virtualCall.irCallSite?.let { ir2stringWhole(it) } - ?: virtualCall.toString()) - } - val devirtualizedCallee = map[receiverType]!! - val callee = devirtualizedCallee.callee - if (callee is DataFlowIR.FunctionSymbol.Declared && callee.symbolTableIndex < 0) - error("Function ${devirtualizedCallee.receiverType}.$callee cannot be called virtually," + - " but actually is at call site: " + - (virtualCall.irCallSite?.let { ir2stringWhole(it) } - ?: virtualCall.toString())) - devirtualizedCallee - }) to virtualCallSiteReceivers.caller + continue } + DEBUG_OUTPUT(0) { + println("Devirtualized callsite " + + (virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.callee.toString())) + } + + val receiverType = virtualCall.receiverType.resolved() + val inheritorsOfReceiverType = typeHierarchy.inheritorsOf(receiverType).filter { + instantiatingClasses.containsKey(it) + } + val possibleReceivers = allTypes.asSequence() + .withIndex() + .filter { receiverNode.types[it.index] } + .filter { inheritorsOfReceiverType.contains(it.value) } + .filterNot { it.value == nothing } + .map { + + DEBUG_OUTPUT(0) { + println("Path to type ${it.value}") + printPathToType(receiverNode, it.index) + } + + it.value + }.toList() + + result[virtualCall] = DevirtualizedCallSite(virtualCall.callee.resolved(), + possibleReceivers.map { possibleReceiverType -> + val callee = possibleReceiverType.calleeAt(virtualCall) + if (callee is DataFlowIR.FunctionSymbol.Declared && callee.symbolTableIndex < 0) + error("Function ${possibleReceiverType}.$callee cannot be called virtually," + + " but actually is at call site: " + + (virtualCall.irCallSite?.let { ir2stringWhole(it) } + ?: virtualCall.toString())) + DevirtualizedCallee(possibleReceiverType, callee) + }) to function.symbol + + } + } + DEBUG_OUTPUT(0) { println("Devirtualized from current module:") result.forEach { virtualCall, devirtualizedCallSite -> @@ -1104,23 +1104,12 @@ internal object Devirtualization { println("Receiver type: $receiverType") } - val possibleReceiverTypes = - if (receiverType == DataFlowIR.Type.Virtual) - emptyList() - else - typeHierarchy.inheritorsOf(receiverType).filter { instantiatingClasses.containsKey(it) } - val callees = possibleReceiverTypes.map { - when (node) { - is DataFlowIR.Node.VtableCall -> - it.vtable[node.calleeVtableIndex] - - is DataFlowIR.Node.ItableCall -> - it.itable[node.calleeHash]!! - - else -> error("Unreachable") - } + val possibleReceiverTypes = typeHierarchy.inheritorsOf(receiverType).filter { + instantiatingClasses.containsKey(it) } + val callees = possibleReceiverTypes.map { it.calleeAt(node) } + DEBUG_OUTPUT(0) { println("Possible callees:") callees.forEach { println("$it") } @@ -1131,9 +1120,7 @@ internal object Devirtualization { val receiverNode = edgeToConstraintNode(node.arguments[0]) if (receiverType == DataFlowIR.Type.Virtual) constraintGraph.virtualNode.addEdge(receiverNode) - val castedReceiver = ordinaryNode { "CastedReceiver\$${function.symbol}" } - receiverNode.addEdge(castedReceiver) - val arguments = listOf(castedReceiver) + node.arguments.drop(1) + val arguments = listOf(receiverNode) + node.arguments.drop(1) val returnsNode = ordinaryNode { "VirtualCallReturns\$${function.symbol}" } callees.forEachIndexed { index, actualCallee -> @@ -1154,11 +1141,7 @@ internal object Devirtualization { concreteClass(returnType).addEdge(returnsNode) } - val devirtualizedCallees = possibleReceiverTypes.mapIndexed { index, possibleReceiverType -> - DevirtualizedCallee(possibleReceiverType, callees[index]) - } - constraintGraph.virtualCallSiteReceivers[node] = - VirtualCallSiteReceivers(castedReceiver, function.symbol, devirtualizedCallees) + constraintGraph.virtualCallSiteReceivers[node] = receiverNode returnsNode }