From 1c2fa52ebaa7ef7fdf20bfebb98ea272d9ceca58 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Mon, 5 Mar 2018 17:43:42 +0300 Subject: [PATCH] DFG: Moved parameter & return types from body to symbol --- .../backend/konan/optimizations/DFGBuilder.kt | 17 -- .../konan/optimizations/DFGSerializer.kt | 158 ++++++++-------- .../backend/konan/optimizations/DataFlowIR.kt | 175 ++++++++++-------- .../konan/optimizations/Devirtualization.kt | 69 ++++--- .../konan/optimizations/EscapeAnalysis.kt | 8 +- 5 files changed, 220 insertions(+), 207 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt index e1d4a201164..0cc8f25ea14 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt @@ -424,7 +424,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag .filterIsInstance().single { it.name.asString() == "doResume" }.symbol private val getContinuationSymbol = context.ir.symbols.getContinuation - private val continuationType = getContinuationSymbol.descriptor.returnType!! private val arrayGetSymbol = context.ir.symbols.arrayGet private val arraySetSymbol = context.ir.symbols.arraySet @@ -471,12 +470,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag ) } - private fun choosePrimary(erasure: List): ClassDescriptor { - if (erasure.size == 1) return erasure[0] - // A parameter with constraints - choose class if exists. - return erasure.singleOrNull { !it.isInterface } ?: context.ir.symbols.any.owner - } - fun build(): DataFlowIR.Function { val isSuspend = descriptor is IrSimpleFunction && descriptor.isSuspend @@ -506,14 +499,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag val allNodes = nodes.values + variables.values + templateParameters.values + returnsNode + throwsNode + (if (isSuspend) listOf(continuationParameter!!) else emptyList()) - val parameterTypes = (allParameters.map { it.type } + (if (isSuspend) listOf(continuationType) else emptyList())) - .map { symbolTable.mapClass(choosePrimary(it.erasure(context))) } - .toTypedArray() - val returnType = if (isSuspend) context.builtIns.anyType else returnNodeType return DataFlowIR.Function( symbol = symbolTable.mapFunction(descriptor), - parameterTypes = parameterTypes, - returnType = symbolTable.mapType(returnType), body = DataFlowIR.FunctionBody(allNodes.distinct().toList(), returnsNode, throwsNode) ) } @@ -606,7 +593,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag symbolTable.mapClass(owner), callee.functionName.localHash.value, arguments, - symbolTable.mapType(callee.returnType), value ) } else { @@ -617,7 +603,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag symbolTable.mapClass(owner), vtableIndex, arguments, - symbolTable.mapType(callee.returnType), value ) } @@ -626,7 +611,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag DataFlowIR.Node.StaticCall( symbolTable.mapFunction(actualCallee), arguments, - symbolTable.mapType(actualCallee.returnType), actualCallee.dispatchReceiverParameter?.let { symbolTable.mapType(it.type) }, value ) @@ -642,7 +626,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag DataFlowIR.Node.StaticCall( symbolTable.mapFunction(value.symbol.owner), arguments.map { expressionToEdge(it) }, - symbolTable.mapClass(context.ir.symbols.unit.owner), symbolTable.mapType(thiz.type), value ) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt index f4d29e7e726..0249c5bbf94 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt @@ -300,56 +300,59 @@ internal object DFGSerializer { } } - class ExternalFunctionSymbol(val hash: Long, val numberOfParameters: Int, val isGlobalInitializer: Boolean, - val escapes: Int?, val pointsTo: IntArray?, val name: String?) { + class FunctionSymbolBase(val parameterTypes: IntArray, val returnType: Int, val isGlobalInitializer: Boolean) { - constructor(data: ArraySlice) : this(data.readLong(), data.readInt(), data.readBoolean(), data.readNullableInt(), + constructor(data: ArraySlice) : this(data.readIntArray(), data.readInt(), data.readBoolean()) + + fun write(result: ArraySlice) { + result.writeIntArray(parameterTypes) + result.writeInt(returnType) + result.writeBoolean(isGlobalInitializer) + } + } + + class ExternalFunctionSymbol(val hash: Long, val escapes: Int?, val pointsTo: IntArray?, val name: String?) { + + constructor(data: ArraySlice) : this(data.readLong(), data.readNullableInt(), data.readNullable { readIntArray() }, data.readNullableString()) fun write(result: ArraySlice) { result.writeLong(hash) - result.writeInt(numberOfParameters) - result.writeBoolean(isGlobalInitializer) result.writeNullableInt(escapes) result.writeNullable(pointsTo) { writeIntArray(it) } result.writeNullableString(name) } } - class PublicFunctionSymbol(val hash: Long, val numberOfParameters: Int, val isGlobalInitializer: Boolean, - val index: Int, val bridgeTarget: Int?, val name: String?) { + class PublicFunctionSymbol(val hash: Long, val index: Int, val bridgeTarget: Int?, val name: String?) { - constructor(data: ArraySlice) : this(data.readLong(), data.readInt(), data.readBoolean(), data.readInt(), + constructor(data: ArraySlice) : this(data.readLong(), data.readInt(), data.readNullableInt(), data.readNullableString()) fun write(result: ArraySlice) { result.writeLong(hash) - result.writeInt(numberOfParameters) - result.writeBoolean(isGlobalInitializer) result.writeInt(index) result.writeNullableInt(bridgeTarget) result.writeNullableString(name) } } - class PrivateFunctionSymbol(val index: Int, val numberOfParameters: Int, val isGlobalInitializer: Boolean, - val bridgeTarget: Int?, val name: String?) { + class PrivateFunctionSymbol(val index: Int, val bridgeTarget: Int?, val name: String?) { - constructor(data: ArraySlice) : this(data.readInt(), data.readInt(), data.readBoolean(), - data.readNullableInt(), data.readNullableString()) + constructor(data: ArraySlice) : this(data.readInt(), data.readNullableInt(), data.readNullableString()) fun write(result: ArraySlice) { result.writeInt(index) - result.writeInt(numberOfParameters) - result.writeBoolean(isGlobalInitializer) result.writeNullableInt(bridgeTarget) result.writeNullableString(name) } } - class FunctionSymbol(val external: ExternalFunctionSymbol?, val public: PublicFunctionSymbol?, val private: PrivateFunctionSymbol?) { + class FunctionSymbol(val base: FunctionSymbolBase, val external: ExternalFunctionSymbol?, + val public: PublicFunctionSymbol?, val private: PrivateFunctionSymbol?) { fun write(result: ArraySlice) { + base.write(result) result.writeByte( when { external != null -> 1 @@ -364,22 +367,23 @@ internal object DFGSerializer { } companion object { - fun external(hash: Long, numberOfParameters: Int, isGlobalInitializer: Boolean, escapes: Int?, pointsTo: IntArray?, name: String?) = - FunctionSymbol(ExternalFunctionSymbol(hash, numberOfParameters, isGlobalInitializer, escapes, pointsTo, name), null, null) + fun external(base: FunctionSymbolBase, hash: Long, escapes: Int?, pointsTo: IntArray?, name: String?) = + FunctionSymbol(base, ExternalFunctionSymbol(hash, escapes, pointsTo, name), null, null) - fun public(hash: Long, numberOfParameters: Int, isGlobalInitializer: Boolean, index: Int, bridgeTarget: Int?, name: String?) = - FunctionSymbol(null, PublicFunctionSymbol(hash, numberOfParameters, isGlobalInitializer, index, bridgeTarget, name), null) + fun public(base: FunctionSymbolBase, hash: Long, index: Int, bridgeTarget: Int?, name: String?) = + FunctionSymbol(base, null, PublicFunctionSymbol(hash, index, bridgeTarget, name), null) - fun private(index: Int, numberOfParameters: Int, isGlobalInitializer: Boolean, bridgeTarget: Int?, name: String?) = - FunctionSymbol(null, null, PrivateFunctionSymbol(index, numberOfParameters, isGlobalInitializer, bridgeTarget, name)) + fun private(base: FunctionSymbolBase, index: Int, bridgeTarget: Int?, name: String?) = + FunctionSymbol(base, null, null, PrivateFunctionSymbol(index, bridgeTarget, name)) fun read(data: ArraySlice): FunctionSymbol { + val base = FunctionSymbolBase(data) val tag = data.readByte().toInt() return when (tag) { - 1 -> FunctionSymbol(ExternalFunctionSymbol(data), null, null) - 2 -> FunctionSymbol(null, PublicFunctionSymbol(data), null) - 3 -> FunctionSymbol(null, null, PrivateFunctionSymbol(data)) - else -> FunctionSymbol(null, null, null) + 1 -> FunctionSymbol(base, ExternalFunctionSymbol(data), null, null) + 2 -> FunctionSymbol(base, null, PublicFunctionSymbol(data), null) + 3 -> FunctionSymbol(base, null, null, PrivateFunctionSymbol(data)) + else -> FunctionSymbol(base, null, null, null) } } } @@ -434,14 +438,13 @@ internal object DFGSerializer { } } - class Call(val callee: Int, val arguments: Array, val returnType: Int) { + class Call(val callee: Int, val arguments: Array) { - constructor(data: ArraySlice) : this(data.readInt(), data.readArray { Edge(this) }, data.readInt()) + constructor(data: ArraySlice) : this(data.readInt(), data.readArray { Edge(this) }) fun write(result: ArraySlice) { result.writeInt(callee) result.writeArray(arguments) { it.write(this) } - result.writeInt(returnType) } } @@ -455,12 +458,13 @@ internal object DFGSerializer { } } - class NewObject(val call: Call) { + class NewObject(val call: Call, val constructedType: Int) { - constructor(data: ArraySlice) : this(Call(data)) + constructor(data: ArraySlice) : this(Call(data), data.readInt()) fun write(result: ArraySlice) { call.write(result) + result.writeInt(constructedType) } } @@ -629,8 +633,8 @@ internal object DFGSerializer { fun staticCall(call: Call, receiverType: Int?) = Node().also { it.staticCall = StaticCall(call, receiverType) } - fun newObject(call: Call) = - Node().also { it.newObject = NewObject(call) } + fun newObject(call: Call, constructedType: Int) = + Node().also { it.newObject = NewObject(call, constructedType) } fun vtableCall(virtualCall: VirtualCall, calleeVtableIndex: Int) = Node().also { it.vtableCall = VtableCall(virtualCall, calleeVtableIndex) } @@ -690,14 +694,12 @@ internal object DFGSerializer { } } - class Function(val symbol: Int, val parameterTypes: IntArray, val returnType: Int, val body: FunctionBody) { + class Function(val symbol: Int, val body: FunctionBody) { - constructor(data: ArraySlice) : this(data.readInt(), data.readIntArray(), data.readInt(), FunctionBody(data)) + constructor(data: ArraySlice) : this(data.readInt(), FunctionBody(data)) fun write(result: ArraySlice) { result.writeInt(symbol) - result.writeIntArray(parameterTypes) - result.writeInt(returnType) body.write(result) } } @@ -790,25 +792,30 @@ internal object DFGSerializer { val functionSymbols = functionSymbolMap.entries .sortedBy { it.value } .map { - val functionSymbol = it.key - val numberOfParameters = functionSymbol.numberOfParameters - val isGlobalInitializer = functionSymbol.isGlobalInitializer - val name = functionSymbol.name - val bridgeTarget = (functionSymbol as? DataFlowIR.FunctionSymbol.Declared)?.let { functionSymbolMap[it] } - when (functionSymbol) { + + fun buildFunctionSymbolBase(symbol: DataFlowIR.FunctionSymbol) = + FunctionSymbolBase( + symbol.parameterTypes.map { typeMap[it]!! }.toIntArray(), + typeMap[symbol.returnType]!!, + symbol.isGlobalInitializer + ) + + val symbol = it.key + val bridgeTarget = (symbol as? DataFlowIR.FunctionSymbol.Declared)?.let { functionSymbolMap[it] } + when (symbol) { is DataFlowIR.FunctionSymbol.External -> - FunctionSymbol.external(functionSymbol.hash, numberOfParameters, isGlobalInitializer, - functionSymbol.escapes, functionSymbol.pointsTo, name) + FunctionSymbol.external(buildFunctionSymbolBase(symbol), symbol.hash, + symbol.escapes, symbol.pointsTo, symbol.name) is DataFlowIR.FunctionSymbol.Public -> - FunctionSymbol.public(functionSymbol.hash, numberOfParameters, - isGlobalInitializer, functionSymbol.symbolTableIndex, bridgeTarget, name) + FunctionSymbol.public(buildFunctionSymbolBase(symbol), symbol.hash, + symbol.symbolTableIndex, bridgeTarget, symbol.name) is DataFlowIR.FunctionSymbol.Private -> - FunctionSymbol.private(functionSymbol.symbolTableIndex, numberOfParameters, - isGlobalInitializer, bridgeTarget, name) + FunctionSymbol.private(buildFunctionSymbolBase(symbol), symbol.symbolTableIndex, + bridgeTarget, symbol.name) - else -> error("Unknown function symbol $functionSymbol") + else -> error("Unknown function symbol $symbol") } } .toTypedArray() @@ -827,8 +834,7 @@ internal object DFGSerializer { fun buildCall(call: DataFlowIR.Node.Call) = Call( functionSymbolMap[call.callee]!!, - call.arguments.map { buildEdge(it) }.toTypedArray(), - typeMap[call.returnType]!! + call.arguments.map { buildEdge(it) }.toTypedArray() ) fun buildVirtualCall(virtualCall: DataFlowIR.Node.VirtualCall) = @@ -845,7 +851,8 @@ internal object DFGSerializer { is DataFlowIR.Node.StaticCall -> Node.staticCall(buildCall(node), node.receiverType?.let { typeMap[it]!! }) - is DataFlowIR.Node.NewObject -> Node.newObject(buildCall(node)) + is DataFlowIR.Node.NewObject -> + Node.newObject(buildCall(node), typeMap[node.constructedType]!!) is DataFlowIR.Node.VtableCall -> Node.vtableCall(buildVirtualCall(node), node.calleeVtableIndex) @@ -876,10 +883,8 @@ internal object DFGSerializer { } .toTypedArray() Function( - functionSymbolMap[function.symbol]!!, - function.parameterTypes.map { typeMap[it]!! }.toIntArray(), - typeMap[function.returnType]!!, - FunctionBody(nodes, nodeMap[body.returns]!!, nodeMap[body.throws]!!) + symbol = functionSymbolMap[function.symbol]!!, + body = FunctionBody(nodes, nodeMap[body.returns]!!, nodeMap[body.throws]!!) ) } .toTypedArray() @@ -953,20 +958,21 @@ internal object DFGSerializer { } val functionSymbols = symbolTable.functionSymbols.map { + val isGlobalInitializer = it.base.isGlobalInitializer val external = it.external val public = it.public val private = it.private when { external != null -> - DataFlowIR.FunctionSymbol.External(external.hash, external.numberOfParameters, - external.isGlobalInitializer, external.escapes, external.pointsTo, external.name) + DataFlowIR.FunctionSymbol.External(external.hash, + isGlobalInitializer, external.escapes, external.pointsTo, external.name) public != null -> { val symbolTableIndex = public.index if (symbolTableIndex >= 0) ++module.numberOfFunctions - DataFlowIR.FunctionSymbol.Public(public.hash, public.numberOfParameters, module, - symbolTableIndex, public.isGlobalInitializer, null, public.name).also { + DataFlowIR.FunctionSymbol.Public(public.hash, + module, symbolTableIndex, isGlobalInitializer, null, public.name).also { publicFunctionsMap.put(it.hash, it) } } @@ -975,9 +981,12 @@ internal object DFGSerializer { val symbolTableIndex = private!!.index if (symbolTableIndex >= 0) ++module.numberOfFunctions - DataFlowIR.FunctionSymbol.Private(privateFunIndex++, private.numberOfParameters, module, - symbolTableIndex, private.isGlobalInitializer, null, private.name) + DataFlowIR.FunctionSymbol.Private(privateFunIndex++, + module, symbolTableIndex, isGlobalInitializer, null, private.name) } + }.apply { + parameterTypes = it.base.parameterTypes.map { types[it] }.toTypedArray() + returnType = types[it.base.returnType] } } @@ -1018,8 +1027,7 @@ internal object DFGSerializer { DataFlowIR.Node.Call( functionSymbols[call.callee], call.arguments.map { deserializeEdge(it) }, - types[call.returnType], - null + irCallSite = null ) fun deserializeVirtualCall(virtualCall: VirtualCall): DataFlowIR.Node.VirtualCall { @@ -1027,9 +1035,8 @@ internal object DFGSerializer { return DataFlowIR.Node.VirtualCall( call.callee, call.arguments, - call.returnType, types[virtualCall.receiverType], - null + irCallSite = null ) } @@ -1049,12 +1056,13 @@ internal object DFGSerializer { val staticCall = it.staticCall!! val call = deserializeCall(staticCall.call) val receiverType = staticCall.receiverType?.let { types[it] } - DataFlowIR.Node.StaticCall(call.callee, call.arguments, call.returnType, receiverType, null) + DataFlowIR.Node.StaticCall(call.callee, call.arguments, receiverType, irCallSite = null) } NodeType.NEW_OBJECT -> { - val call = deserializeCall(it.newObject!!.call) - DataFlowIR.Node.NewObject(call.callee, call.arguments, call.returnType, null) + val newObject = it.newObject!! + val call = deserializeCall(newObject.call) + DataFlowIR.Node.NewObject(call.callee, call.arguments, types[newObject.constructedType], irCallSite = null) } NodeType.VTABLE_CALL -> { @@ -1065,8 +1073,7 @@ internal object DFGSerializer { virtualCall.receiverType, vtableCall.calleeVtableIndex, virtualCall.arguments, - virtualCall.returnType, - virtualCall.callSite + virtualCall.irCallSite ) } @@ -1078,8 +1085,7 @@ internal object DFGSerializer { virtualCall.receiverType, itableCall.calleeHash, virtualCall.arguments, - virtualCall.returnType, - virtualCall.callSite + virtualCall.irCallSite ) } @@ -1185,8 +1191,6 @@ internal object DFGSerializer { val symbol = functionSymbols[it.symbol] val function = DataFlowIR.Function( symbol = symbol, - parameterTypes = it.parameterTypes.map { types[it] }.toTypedArray(), - returnType = types[it.returnType], body = deserializeBody(it.body) ) functions.put(symbol, function) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt index 33af70dcfcf..2f200da5235 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.konan.optimizations import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract import org.jetbrains.kotlin.backend.konan.descriptors.isInterface +import org.jetbrains.kotlin.backend.konan.descriptors.target import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.backend.konan.llvm.isExported @@ -117,10 +118,13 @@ internal object DataFlowIR { var numberOfClasses = 0 } - abstract class FunctionSymbol(val numberOfParameters: Int, val isGlobalInitializer: Boolean, val name: String?) { - class External(val hash: Long, numberOfParameters: Int, isGlobalInitializer: Boolean, + abstract class FunctionSymbol(val isGlobalInitializer: Boolean, val name: String?) { + lateinit var parameterTypes: Array + lateinit var returnType: Type + + class External(val hash: Long, isGlobalInitializer: Boolean, val escapes: Int?, val pointsTo: IntArray?, name: String? = null) - : FunctionSymbol(numberOfParameters, isGlobalInitializer, name) { + : FunctionSymbol(isGlobalInitializer, name) { override fun equals(other: Any?): Boolean { if (this === other) return true @@ -138,15 +142,16 @@ internal object DataFlowIR { } } - abstract class Declared(numberOfParameters: Int, val module: Module, val symbolTableIndex: Int, + abstract class Declared(val module: Module, val symbolTableIndex: Int, isGlobalInitializer: Boolean, var bridgeTarget: FunctionSymbol?, name: String?) - : FunctionSymbol(numberOfParameters, isGlobalInitializer, name) { + : FunctionSymbol(isGlobalInitializer, name) { } - class Public(val hash: Long, numberOfParameters: Int, module: Module, symbolTableIndex: Int, + class Public(val hash: Long, module: Module, symbolTableIndex: Int, isGlobalInitializer: Boolean, bridgeTarget: FunctionSymbol?, name: String? = null) - : Declared(numberOfParameters, module, symbolTableIndex, isGlobalInitializer, bridgeTarget, name) { + : Declared(module, symbolTableIndex, isGlobalInitializer, bridgeTarget, name) { + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Public) return false @@ -163,9 +168,10 @@ internal object DataFlowIR { } } - class Private(val index: Int, numberOfParameters: Int, module: Module, symbolTableIndex: Int, + class Private(val index: Int, module: Module, symbolTableIndex: Int, isGlobalInitializer: Boolean, bridgeTarget: FunctionSymbol?, name: String? = null) - : Declared(numberOfParameters, module, symbolTableIndex, isGlobalInitializer, bridgeTarget, name) { + : Declared(module, symbolTableIndex, isGlobalInitializer, bridgeTarget, name) { + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Private) return false @@ -205,27 +211,27 @@ internal object DataFlowIR { class Const(val type: Type) : Node() - open class Call(val callee: FunctionSymbol, val arguments: List, val returnType: Type, - open val callSite: IrFunctionAccessExpression?) : Node() + open class Call(val callee: FunctionSymbol, val arguments: List, + open val irCallSite: IrFunctionAccessExpression?) : Node() - class StaticCall(callee: FunctionSymbol, arguments: List, returnType: Type, - val receiverType: Type?, callSite: IrFunctionAccessExpression?) - : Call(callee, arguments, returnType, callSite) + class StaticCall(callee: FunctionSymbol, arguments: List, + val receiverType: Type?, irCallSite: IrFunctionAccessExpression?) + : Call(callee, arguments, irCallSite) - class NewObject(constructor: FunctionSymbol, arguments: List, type: Type, override val callSite: IrCall?) - : Call(constructor, arguments, type, callSite) + class NewObject(constructor: FunctionSymbol, arguments: List, val constructedType: Type, override val irCallSite: IrCall?) + : Call(constructor, arguments, irCallSite) - open class VirtualCall(callee: FunctionSymbol, arguments: List, returnType: Type, - val receiverType: Type, override val callSite: IrCall?) - : Call(callee, arguments, returnType, callSite) + open class VirtualCall(callee: FunctionSymbol, arguments: List, + val receiverType: Type, override val irCallSite: IrCall?) + : Call(callee, arguments, irCallSite) class VtableCall(callee: FunctionSymbol, receiverType: Type, val calleeVtableIndex: Int, - arguments: List, returnType: Type, callSite: IrCall?) - : VirtualCall(callee, arguments, returnType, receiverType, callSite) + arguments: List, irCallSite: IrCall?) + : VirtualCall(callee, arguments, receiverType, irCallSite) class ItableCall(callee: FunctionSymbol, receiverType: Type, val calleeHash: Long, - arguments: List, returnType: Type, callSite: IrCall?) - : VirtualCall(callee, arguments, returnType, receiverType, callSite) + arguments: List, irCallSite: IrCall?) + : VirtualCall(callee, arguments, receiverType, irCallSite) class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node() @@ -233,7 +239,7 @@ internal object DataFlowIR { class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge) : Node() - class ArrayRead(val array: Edge, val index: Edge, val callSite: IrCall?) : Node() + class ArrayRead(val array: Edge, val index: Edge, val irCallSite: IrCall?) : Node() class ArrayWrite(val array: Edge, val index: Edge, val value: Edge) : Node() @@ -244,14 +250,11 @@ internal object DataFlowIR { class FunctionBody(val nodes: List, val returns: Node.Variable, val throws: Node.Variable) - class Function(val symbol: FunctionSymbol, - val parameterTypes: Array, - val returnType: Type, - val body: FunctionBody) { + class Function(val symbol: FunctionSymbol, val body: FunctionBody) { fun debugOutput() { println("FUNCTION $symbol") - println("Params: ${parameterTypes.contentToString()}") + println("Params: ${symbol.parameterTypes.contentToString()}") val ids = body.nodes.withIndex().associateBy({ it.value }, { it.index }) body.nodes.forEach { println(" NODE #${ids[it]!!}") @@ -320,7 +323,7 @@ internal object DataFlowIR { is Node.NewObject -> { val result = StringBuilder() result.appendln(" NEW OBJECT ${node.callee}") - result.appendln(" TYPE ${node.returnType}") + result.appendln(" CONSTRUCTED TYPE ${node.constructedType}") node.arguments.forEach { result.append(" ARG #${ids[it.node]!!}") if (it.castToType == null) @@ -439,6 +442,9 @@ internal object DataFlowIR { NAME_POINTS_TO, NoLookupLocation.FROM_BACKEND) as org.jetbrains.kotlin.descriptors.ClassDescriptor private val pointsToOnWhomDescriptor = pointsToAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single() + private val getContinuationSymbol = context.ir.symbols.getContinuation + private val continuationType = getContinuationSymbol.descriptor.returnType!! + var privateTypeIndex = 0 var privateFunIndex = 0 @@ -486,6 +492,10 @@ internal object DataFlowIR { Type.Public(name.localHash.value, isFinal, isAbstract, correspondingValueType, module, symbolTableIndex, takeName { name }) else Type.Private(privateTypeIndex++, isFinal, isAbstract, correspondingValueType, module, symbolTableIndex, takeName { name }) + + classMap[descriptor] = type + + type.superTypes += descriptor.defaultType.immediateSupertypes().map { mapType(it) } if (!isAbstract) { val vtableBuilder = context.getVtableBuilder(descriptor) type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)!!) } @@ -493,8 +503,6 @@ internal object DataFlowIR { type.itable[it.overriddenDescriptor.functionName.localHash.value] = mapFunction(it.getImplementation(context)!!) } } - classMap.put(descriptor, type) - type.superTypes += descriptor.defaultType.immediateSupertypes().map { mapType(it) } return type } @@ -512,50 +520,71 @@ internal object DataFlowIR { private val FunctionDescriptor.internalName get() = getFqName(this).asString() + "#internal" - fun mapFunction(descriptor: DeclarationDescriptor): FunctionSymbol = descriptor.original.let { - functionMap.getOrPut(it) { - when (it) { - is IrField -> { - // A global property initializer. - assert (it.parent !is IrClass) { "All local properties initializers should've been lowered" } - FunctionSymbol.Private(privateFunIndex++, 0, module, -1, true, null, takeName { "${it.symbolName}_init" }) + fun mapFunction(descriptor: DeclarationDescriptor): FunctionSymbol = when (descriptor) { + is FunctionDescriptor -> mapFunction(descriptor) + is IrField -> mapPropertyInitializer(descriptor) + else -> error("Unknown descriptor: $descriptor") + } + + private fun mapFunction(descriptor: FunctionDescriptor): FunctionSymbol = descriptor.target.let { + functionMap[it]?.let { return it } + + val name = if (it.isExported()) it.symbolName else it.internalName + val symbol = when { + it.module != irModule.descriptor || it.isExternal || (it.origin == IrDeclarationOrigin.IR_BUILTINS_STUB) -> { + val escapesAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_ESCAPES) + val pointsToAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_POINTS_TO) + @Suppress("UNCHECKED_CAST") + val escapesBitMask = (escapesAnnotation?.allValueArguments?.get(escapesWhoDescriptor.name) as? ConstantValue)?.value + @Suppress("UNCHECKED_CAST") + val pointsToBitMask = (pointsToAnnotation?.allValueArguments?.get(pointsToOnWhomDescriptor.name) as? ConstantValue>)?.value + FunctionSymbol.External(name.localHash.value, false, escapesBitMask, + pointsToBitMask?.let { it.map { it.value }.toIntArray() }, takeName { name }) + } + + else -> { + val isAbstract = it is SimpleFunctionDescriptor && it.modality == Modality.ABSTRACT + val classDescriptor = it.containingDeclaration as? ClassDescriptor + val bridgeTarget = it.bridgeTarget + val isSpecialBridge = bridgeTarget.let { + it != null && BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(it.descriptor) != null } - - is FunctionDescriptor -> { - val name = if (it.isExported()) it.symbolName else it.internalName - val numberOfParameters = it.allParameters.size + if (it.isSuspend) 1 else 0 - if (it.module != irModule.descriptor || it.isExternal || (it.origin == IrDeclarationOrigin.IR_BUILTINS_STUB)) { - val escapesAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_ESCAPES) - val pointsToAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_POINTS_TO) - @Suppress("UNCHECKED_CAST") - val escapesBitMask = (escapesAnnotation?.allValueArguments?.get(escapesWhoDescriptor.name) as? ConstantValue)?.value - @Suppress("UNCHECKED_CAST") - val pointsToBitMask = (pointsToAnnotation?.allValueArguments?.get(pointsToOnWhomDescriptor.name) as? ConstantValue>)?.value - FunctionSymbol.External(name.localHash.value, numberOfParameters, false, escapesBitMask, - pointsToBitMask?.let { it.map { it.value }.toIntArray() }, takeName { name }) - } else { - val isAbstract = it is SimpleFunctionDescriptor && it.modality == Modality.ABSTRACT - val classDescriptor = it.containingDeclaration as? ClassDescriptor - val bridgeTarget = it.bridgeTarget - val isSpecialBridge = bridgeTarget.let { - it != null && BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(it.descriptor) != null - } - val bridgeTargetSymbol = if (isSpecialBridge || bridgeTarget == null) null else mapFunction(bridgeTarget) - - val placeToFunctionsTable = !isAbstract && it !is ConstructorDescriptor && classDescriptor != null - && classDescriptor.kind != ClassKind.ANNOTATION_CLASS - && (it.isOverridableOrOverrides || bridgeTarget != null || !classDescriptor.isFinal()) - val symbolTableIndex = if (placeToFunctionsTable) module.numberOfFunctions++ else -1 - if (it.isExported()) - FunctionSymbol.Public(name.localHash.value, numberOfParameters, module, symbolTableIndex, false, bridgeTargetSymbol, takeName { name }) - else - FunctionSymbol.Private(privateFunIndex++, numberOfParameters, module, symbolTableIndex, false, bridgeTargetSymbol, takeName { name }) - } - } - - else -> error("Unknown descriptor: $it") + val bridgeTargetSymbol = if (isSpecialBridge || bridgeTarget == null) null else mapFunction(bridgeTarget) + val placeToFunctionsTable = !isAbstract && it !is ConstructorDescriptor && classDescriptor != null + && classDescriptor.kind != ClassKind.ANNOTATION_CLASS + && (it.isOverridableOrOverrides || bridgeTarget != null || !classDescriptor.isFinal()) + val symbolTableIndex = if (placeToFunctionsTable) module.numberOfFunctions++ else -1 + if (it.isExported()) + FunctionSymbol.Public(name.localHash.value, module, symbolTableIndex, false, bridgeTargetSymbol, takeName { name }) + else + FunctionSymbol.Private(privateFunIndex++, module, symbolTableIndex, false, bridgeTargetSymbol, takeName { name }) } } + functionMap[it] = symbol + + symbol.parameterTypes = + (descriptor.allParameters.map { it.type } + (if (descriptor.isSuspend) listOf(continuationType) else emptyList())) + .map { mapClass(choosePrimary(it.erasure(context))) } + .toTypedArray() + symbol.returnType = mapType(if (descriptor.isSuspend) + context.builtIns.anyType + else + descriptor.returnType) + + return symbol + } + + private fun mapPropertyInitializer(descriptor: IrField): FunctionSymbol = descriptor.original.let { + functionMap[it]?.let { return it } + + assert(it.parent !is IrClass) { "All local properties initializers should've been lowered" } + val symbol = FunctionSymbol.Private(privateFunIndex++, module, -1, true, null, takeName { "${it.symbolName}_init" }) + + functionMap[it] = symbol + + symbol.parameterTypes = emptyArray() + symbol.returnType = mapClass(context.ir.symbols.unit.owner) + return symbol } fun getPrivateFunctionsTableForExport() = 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 07d5221df24..467226d4ff3 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 @@ -226,8 +226,7 @@ internal object Devirtualization { } } - private inner class InstantiationsSearcher(val functions: Map, - val rootSet: List, + private inner class InstantiationsSearcher(val rootSet: List, val typeHierarchy: TypeHierarchy) { private val visited = mutableSetOf() private val typesVirtualCallSites = mutableMapOf>() @@ -236,13 +235,12 @@ internal object Devirtualization { fun search(): Set { // Rapid Type Analysis: find all instantiations and conservatively estimate call graph. // Add all final parameters of the roots. - rootSet.map { functions[it]!! } - .forEach { - it.parameterTypes - .map { it.resolved() } - .filter { it.isFinal } - .forEach { addInstantiatingClass(it) } - } + rootSet.forEach { + it.parameterTypes + .map { it.resolved() } + .filter { it.isFinal } + .forEach { addInstantiatingClass(it) } + } if (entryPoint == null) { // For library assume all public non-abstract classes could be instantiated. moduleDFG.symbolTable.classMap.values @@ -252,7 +250,7 @@ internal object Devirtualization { .forEach { addInstantiatingClass(it) } } // Traverse call graph from the roots. - rootSet.forEach { dfs(it, functions[it]!!.returnType) } + rootSet.forEach { dfs(it) } return instantiatingClasses } @@ -281,7 +279,7 @@ internal object Devirtualization { else -> error("Unreachable") } - dfs(callee, virtualCall.returnType) + dfs(callee) } private fun checkSupertypes(type: DataFlowIR.Type.Declared, @@ -316,13 +314,13 @@ internal object Devirtualization { .forEach { checkSupertypes(it, inheritor, seenTypes) } } - private fun dfs(symbol: DataFlowIR.FunctionSymbol, returnType: DataFlowIR.Type) { + private fun dfs(symbol: DataFlowIR.FunctionSymbol) { val resolvedFunctionSymbol = symbol.resolved() if (resolvedFunctionSymbol is DataFlowIR.FunctionSymbol.External) { DEBUG_OUTPUT(1) { println("Function $resolvedFunctionSymbol is external") } - val resolvedReturnType = returnType.resolved() + val resolvedReturnType = symbol.returnType.resolved() if (resolvedReturnType.isFinal) { DEBUG_OUTPUT(1) { println("Adding return type as it is final") } @@ -342,25 +340,25 @@ internal object Devirtualization { nodeLoop@for (node in function.body.nodes) { when (node) { is DataFlowIR.Node.NewObject -> { - addInstantiatingClass(node.returnType) - dfs(node.callee, node.returnType) + addInstantiatingClass(node.constructedType) + dfs(node.callee) } is DataFlowIR.Node.Singleton -> { addInstantiatingClass(node.type) - node.constructor?.let { dfs(it, node.type) } + node.constructor?.let { dfs(it) } } is DataFlowIR.Node.Const -> addInstantiatingClass(node.type) is DataFlowIR.Node.StaticCall -> - dfs(node.callee, node.returnType) + dfs(node.callee) is DataFlowIR.Node.VirtualCall -> { if (node.receiverType == DataFlowIR.Type.Virtual) continue@nodeLoop val receiverType = node.receiverType.resolved() - val vCallReturnType = node.returnType.resolved() + val vCallReturnType = node.callee.returnType.resolved() DEBUG_OUTPUT(1) { println("Adding virtual callsite:") @@ -399,7 +397,7 @@ internal object Devirtualization { val rootSet = computeRootSet(context, moduleDFG, externalModulesDFG) val instantiatingClasses = - InstantiationsSearcher(functions, rootSet, typeHierarchy).search() + InstantiationsSearcher(rootSet, typeHierarchy).search() .withIndex() .associate { it.value to (it.index + 1 /* 0 is reserved for [DataFlowIR.Type.Virtual] */) } val allTypes = listOf(DataFlowIR.Type.Virtual) + instantiatingClasses.asSequence().sortedBy { it.value }.map { it.key } @@ -531,7 +529,7 @@ internal object Devirtualization { if (virtualCallSiteReceivers == null || virtualCallSiteReceivers.receiver.types[VIRTUAL_TYPE_ID]) { DEBUG_OUTPUT(0) { - println("Unable to devirtualize callsite ${virtualCall.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString() }") + println("Unable to devirtualize callsite ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString() }") println(" receiver is Virtual") } @@ -542,16 +540,16 @@ internal object Devirtualization { .map { it.value } .filter { it != nothing } val map = virtualCallSiteReceivers.devirtualizedCallees.associateBy({ it.receiverType }, { it }) - result[virtualCall] = DevirtualizedCallSite(possibleReceivers.map { receiverType -> + result[virtualCall] = DevirtualizedCallSite(virtualCall.callee.resolved(), possibleReceivers.map { receiverType -> assert (map[receiverType] != null) { "Non-expected receiver type $receiverType at call site: " + - (virtualCall.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString()) + (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.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString() }") + " but actually is at call site: ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString() }") devirtualizedCallee }) to virtualCallSiteReceivers.caller } @@ -559,10 +557,10 @@ internal object Devirtualization { DEBUG_OUTPUT(0) { println("Devirtualized from current module:") result.forEach { virtualCall, devirtualizedCallSite -> - if (virtualCall.callSite != null) { + if (virtualCall.irCallSite != null) { println("DEVIRTUALIZED") println("FUNCTION: ${devirtualizedCallSite.second}") - println("CALL SITE: ${virtualCall.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString()}") + println("CALL SITE: ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString()}") println("POSSIBLE RECEIVERS:") devirtualizedCallSite.first.possibleCallees.forEach { println(" TYPE: ${it.receiverType}") } devirtualizedCallSite.first.possibleCallees.forEach { println(" FUN: ${it.callee}") } @@ -571,10 +569,10 @@ internal object Devirtualization { } println("Devirtualized from external modules:") result.forEach { virtualCall, devirtualizedCallSite -> - if (virtualCall.callSite == null) { + if (virtualCall.irCallSite == null) { println("DEVIRTUALIZED") println("FUNCTION: ${devirtualizedCallSite.second}") - println("CALL SITE: ${virtualCall.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString()}") + println("CALL SITE: ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString()}") println("POSSIBLE RECEIVERS:") devirtualizedCallSite.first.possibleCallees.forEach { println(" TYPE: ${it.receiverType}") } devirtualizedCallSite.first.possibleCallees.forEach { println(" FUN: ${it.callee}") } @@ -647,11 +645,10 @@ internal object Devirtualization { if (symbol is DataFlowIR.FunctionSymbol.External) return null constraintGraph.functions[symbol]?.let { return it } - val function = functions[symbol] ?: error("Unknown function: $symbol") - val parameters = Array(symbol.numberOfParameters) { ordinaryNode { "Param#$it\$$symbol" } } + val parameters = Array(symbol.parameterTypes.size) { ordinaryNode { "Param#$it\$$symbol" } } if (isRoot) { // Exported function from the current module. - function.parameterTypes.forEachIndexed { index, type -> + symbol.parameterTypes.forEachIndexed { index, type -> val resolvedType = type.resolved() val node = if (!resolvedType.isFinal) constraintGraph.virtualNode @@ -769,10 +766,10 @@ internal object Devirtualization { function.parameters[node.index] is DataFlowIR.Node.StaticCall -> - doCall(node.callee, node.arguments, node.returnType.resolved(), node.receiverType?.resolved()) + doCall(node.callee, node.arguments, node.callee.returnType.resolved(), node.receiverType?.resolved()) is DataFlowIR.Node.NewObject -> { - val returnType = node.returnType.resolved() + val returnType = node.constructedType.resolved() val instanceNode = concreteClass(returnType) doCall(node.callee, listOf(instanceNode) + node.arguments, returnType, null) instanceNode @@ -812,7 +809,7 @@ internal object Devirtualization { println() } - val returnType = node.returnType.resolved() + val returnType = node.callee.returnType.resolved() val receiverNode = edgeToConstraintNode(node.arguments[0]) if (receiverType == DataFlowIR.Type.Virtual) constraintGraph.virtualNode.addEdge(receiverNode) @@ -891,7 +888,7 @@ internal object Devirtualization { class DevirtualizedCallee(val receiverType: DataFlowIR.Type, val callee: DataFlowIR.FunctionSymbol) - class DevirtualizedCallSite(val possibleCallees: List) + class DevirtualizedCallSite(val callee: DataFlowIR.FunctionSymbol, val possibleCallees: List) class AnalysisResult(val devirtualizedCallSites: Map) @@ -901,8 +898,8 @@ internal object Devirtualization { val devirtualizedCallSites = devirtualizationAnalysisResult .asSequence() - .filter { it.key.callSite != null } - .associate { it.key.callSite!! to it.value } + .filter { it.key.irCallSite != null } + .associate { it.key.irCallSite!! to it.value } Devirtualization.devirtualize(irModule, context, devirtualizedCallSites) return AnalysisResult(devirtualizationAnalysisResult) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt index ca46d51f4ba..4c1312c086c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt @@ -266,7 +266,7 @@ internal object EscapeAnalysis { } for (functionSymbol in callGraph.directEdges.keys) { - val numberOfParameters = intraproceduralAnalysisResult[functionSymbol]!!.function.parameterTypes.size + val numberOfParameters = functionSymbol.parameterTypes.size escapeAnalysisResults[functionSymbol] = FunctionEscapeAnalysisResult( // Assume no edges at the beginning. // Then iteratively add needed. @@ -321,7 +321,7 @@ internal object EscapeAnalysis { for (graph in pointsToGraphs.values) { graph.nodes.keys .filterIsInstance() - .forEach { call -> call.callSite?.let { lifetimes.put(it, graph.lifetimeOf(call)) } } + .forEach { call -> call.irCallSite?.let { lifetimes.put(it, graph.lifetimeOf(call)) } } } } @@ -355,7 +355,7 @@ internal object EscapeAnalysis { } private fun getConservativeFunctionEAResult(symbol: DataFlowIR.FunctionSymbol): FunctionEscapeAnalysisResult { - val numberOfParameters = symbol.numberOfParameters + val numberOfParameters = symbol.parameterTypes.size return FunctionEscapeAnalysisResult((0..numberOfParameters).map { ParameterEscapeAnalysisResult( escapes = true, @@ -378,7 +378,7 @@ internal object EscapeAnalysis { FunctionEscapeAnalysisResult.fromBits( callee.escapes ?: 0, - (0..callee.numberOfParameters).map { callee.pointsTo?.elementAtOrNull(it) ?: 0 } + (0..callee.parameterTypes.size).map { callee.pointsTo?.elementAtOrNull(it) ?: 0 } ) }