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 99ef3a845a3..f4933fdad69 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 @@ -355,7 +355,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag val thrownValues = mutableListOf() val catchParameters = mutableSetOf() - private val returnableBlocks = mutableMapOf() private val suspendableExpressionStack = mutableListOf() override fun visitElement(element: IrElement) { @@ -453,6 +452,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag private val arrayGetSymbol = context.ir.symbols.arrayGet private val arraySetSymbol = context.ir.symbols.arraySet + private val createUninitializedInstanceSymbol = context.ir.symbols.createUninitializedInstance + private val initInstanceSymbol = context.ir.symbols.initInstance private val scheduleImplSymbol = context.ir.symbols.scheduleImpl private val scheduleImplProducerClassSymbol = context.ir.symbols.functions[0] private val scheduleImplProducerParam = scheduleImplSymbol.descriptor.valueParameters[2].also { @@ -473,14 +474,15 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag private val allParameters = (descriptor as? FunctionDescriptor)?.allParameters ?: emptyList() private val templateParameters = allParameters.withIndex().associateBy({ it.value }, { DataFlowIR.Node.Parameter(it.index) }) - private val continuationParameter = if (descriptor !is IrSimpleFunction) { - null - } else if (descriptor.isSuspend) { - DataFlowIR.Node.Parameter(allParameters.size) - } else if (doResumeFunctionSymbol in descriptor.overriddenSymbols) { // is a CoroutineImpl inheritor. - templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation. - } else { - null + private val continuationParameter = when { + descriptor !is IrSimpleFunction -> null + + descriptor.isSuspend -> DataFlowIR.Node.Parameter(allParameters.size) + + doResumeFunctionSymbol in descriptor.overriddenSymbols -> // is a CoroutineImpl inheritor. + templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation. + + else -> null } private fun getContinuation() = continuationParameter ?: error("Function $descriptor has no continuation parameter") @@ -592,6 +594,23 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag arraySetSymbol -> DataFlowIR.Node.ArrayWrite(expressionToEdge(value.dispatchReceiver!!), expressionToEdge(value.getValueArgument(0)!!), expressionToEdge(value.getValueArgument(1)!!)) + createUninitializedInstanceSymbol -> + DataFlowIR.Node.AllocInstance(symbolTable.mapType(value.getTypeArgument(0)!!)) + + initInstanceSymbol -> { + val thiz = expressionToEdge(value.getValueArgument(0)!!) + val initializer = value.getValueArgument(1) as IrCall + val arguments = listOf(thiz) + initializer.getArguments().map { expressionToEdge(it.second) } + val callee = initializer.symbol.owner as IrConstructor + DataFlowIR.Node.StaticCall( + symbolTable.mapFunction(callee), + arguments, + symbolTable.mapClass(context.ir.symbols.unit.owner), + symbolTable.mapClass(callee.constructedClass), + null + ) + } + else -> { val callee = value.symbol.owner val arguments = value.getArguments() 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 2b69a5fa362..166c1019ec9 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 @@ -516,6 +516,15 @@ internal object DFGSerializer { } } + class AllocInstance(val type: Int) { + + constructor(data: ArraySlice) : this(data.readInt()) + + fun write(result: ArraySlice) { + result.writeInt(type) + } + } + class FieldRead(val receiver: Edge?, val field: Field) { constructor(data: ArraySlice) : this(data.readNullable { Edge(this) }, Field(data)) @@ -578,6 +587,7 @@ internal object DFGSerializer { VTABLE_CALL, ITABLE_CALL, SINGLETON, + ALLOC_INSTANCE, FIELD_READ, FIELD_WRITE, ARRAY_READ, @@ -586,49 +596,52 @@ internal object DFGSerializer { } class Node { - var parameter : Parameter? = null - var const : Const? = null - var staticCall : StaticCall? = null - var newObject : NewObject? = null - var vtableCall : VtableCall? = null - var itableCall : ItableCall? = null - var singleton : Singleton? = null - var fieldRead : FieldRead? = null - var fieldWrite : FieldWrite? = null - var arrayRead : ArrayRead? = null - var arrayWrite : ArrayWrite? = null - var variable : Variable? = null + var parameter : Parameter? = null + var const : Const? = null + var staticCall : StaticCall? = null + var newObject : NewObject? = null + var vtableCall : VtableCall? = null + var itableCall : ItableCall? = null + var singleton : Singleton? = null + var allocInstance: AllocInstance? = null + var fieldRead : FieldRead? = null + var fieldWrite : FieldWrite? = null + var arrayRead : ArrayRead? = null + var arrayWrite : ArrayWrite? = null + var variable : Variable? = null val type get() = when { - parameter != null -> NodeType.PARAMETER - const != null -> NodeType.CONST - staticCall != null -> NodeType.STATIC_CALL - newObject != null -> NodeType.NEW_OBJECT - vtableCall != null -> NodeType.VTABLE_CALL - itableCall != null -> NodeType.ITABLE_CALL - singleton != null -> NodeType.SINGLETON - fieldRead != null -> NodeType.FIELD_READ - fieldWrite != null -> NodeType.FIELD_WRITE - arrayRead != null -> NodeType.ARRAY_READ - arrayWrite != null -> NodeType.ARRAY_WRITE - variable != null -> NodeType.VARIABLE - else -> NodeType.UNKNOWN + parameter != null -> NodeType.PARAMETER + const != null -> NodeType.CONST + staticCall != null -> NodeType.STATIC_CALL + newObject != null -> NodeType.NEW_OBJECT + vtableCall != null -> NodeType.VTABLE_CALL + itableCall != null -> NodeType.ITABLE_CALL + singleton != null -> NodeType.SINGLETON + allocInstance != null -> NodeType.ALLOC_INSTANCE + fieldRead != null -> NodeType.FIELD_READ + fieldWrite != null -> NodeType.FIELD_WRITE + arrayRead != null -> NodeType.ARRAY_READ + arrayWrite != null -> NodeType.ARRAY_WRITE + variable != null -> NodeType.VARIABLE + else -> NodeType.UNKNOWN } fun write(result: ArraySlice) { result.writeByte(type.ordinal.toByte()) - parameter ?.write(result) - const ?.write(result) - staticCall?.write(result) - newObject ?.write(result) - vtableCall?.write(result) - itableCall?.write(result) - singleton ?.write(result) - fieldRead ?.write(result) - fieldWrite?.write(result) - arrayRead ?.write(result) - arrayWrite?.write(result) - variable ?.write(result) + parameter ?.write(result) + const ?.write(result) + staticCall ?.write(result) + newObject ?.write(result) + vtableCall ?.write(result) + itableCall ?.write(result) + singleton ?.write(result) + allocInstance?.write(result) + fieldRead ?.write(result) + fieldWrite ?.write(result) + arrayRead ?.write(result) + arrayWrite ?.write(result) + variable ?.write(result) } companion object { @@ -653,6 +666,9 @@ internal object DFGSerializer { fun singleton(type: Int, constructor: Int?) = Node().also { it.singleton = Singleton(type, constructor) } + fun allocInst(type: Int) = + Node().also { it.allocInstance = AllocInstance(type) } + fun fieldRead(receiver: Edge?, field: Field) = Node().also { it.fieldRead = FieldRead(receiver, field) } @@ -672,19 +688,20 @@ internal object DFGSerializer { val type = enumValues()[data.readByte().toInt()] val result = Node() when (type) { - NodeType.PARAMETER -> result.parameter = Parameter (data) - NodeType.CONST -> result.const = Const (data) - NodeType.STATIC_CALL -> result.staticCall = StaticCall(data) - NodeType.NEW_OBJECT -> result.newObject = NewObject (data) - NodeType.VTABLE_CALL -> result.vtableCall = VtableCall(data) - NodeType.ITABLE_CALL -> result.itableCall = ItableCall(data) - NodeType.SINGLETON -> result.singleton = Singleton (data) - NodeType.FIELD_READ -> result.fieldRead = FieldRead (data) - NodeType.FIELD_WRITE -> result.fieldWrite = FieldWrite(data) - NodeType.ARRAY_READ -> result.arrayRead = ArrayRead (data) - NodeType.ARRAY_WRITE -> result.arrayWrite = ArrayWrite(data) - NodeType.VARIABLE -> result.variable = Variable (data) - else -> { } + NodeType.PARAMETER -> result.parameter = Parameter (data) + NodeType.CONST -> result.const = Const (data) + NodeType.STATIC_CALL -> result.staticCall = StaticCall (data) + NodeType.NEW_OBJECT -> result.newObject = NewObject (data) + NodeType.VTABLE_CALL -> result.vtableCall = VtableCall (data) + NodeType.ITABLE_CALL -> result.itableCall = ItableCall (data) + NodeType.SINGLETON -> result.singleton = Singleton (data) + NodeType.ALLOC_INSTANCE -> result.allocInstance = AllocInstance(data) + NodeType.FIELD_READ -> result.fieldRead = FieldRead (data) + NodeType.FIELD_WRITE -> result.fieldWrite = FieldWrite (data) + NodeType.ARRAY_READ -> result.arrayRead = ArrayRead (data) + NodeType.ARRAY_WRITE -> result.arrayWrite = ArrayWrite (data) + NodeType.VARIABLE -> result.variable = Variable (data) + else -> { } } return result } @@ -873,6 +890,9 @@ internal object DFGSerializer { is DataFlowIR.Node.Singleton -> Node.singleton(typeMap[node.type]!!, node.constructor?.let { functionSymbolMap[it]!! }) + is DataFlowIR.Node.AllocInstance -> + Node.allocInst(typeMap[node.type]!!) + is DataFlowIR.Node.FieldRead -> Node.fieldRead(node.receiver?.let { buildEdge(it) }, buildField(node.field)) @@ -1108,6 +1128,10 @@ internal object DFGSerializer { DataFlowIR.Node.Singleton(types[singleton.type], singleton.constructor?.let { functionSymbols[it] }) } + NodeType.ALLOC_INSTANCE -> { + DataFlowIR.Node.AllocInstance(types[it.allocInstance!!.type]) + } + NodeType.FIELD_READ -> { val fieldRead = it.fieldRead!! val receiver = fieldRead.receiver?.let { deserializeEdge(it) } 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 21b40efbf9f..c7fb22da369 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 @@ -237,6 +237,7 @@ internal object DataFlowIR { val receiverType: Type?, irCallSite: IrFunctionAccessExpression?) : Call(callee, arguments, irCallSite) + // TODO: It can be replaced with a pair(AllocInstance, constructor Call), remove. class NewObject(constructor: FunctionSymbol, arguments: List, val constructedType: Type, override val irCallSite: IrCall?) : Call(constructor, arguments, irCallSite) @@ -254,6 +255,8 @@ internal object DataFlowIR { class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node() + class AllocInstance(val type: Type) : Node() + class FieldRead(val receiver: Edge?, val field: Field, val ir: IrGetField?) : Node() class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge) : Node() @@ -296,6 +299,9 @@ internal object DataFlowIR { is Node.Singleton -> " SINGLETON ${node.type}\n" + is Node.AllocInstance -> + " ALLOC INSTANCE ${node.type}\n" + is Node.StaticCall -> { val result = StringBuilder() result.appendln(" STATIC CALL ${node.callee}") 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 a56f025b232..2bd8692dc97 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 @@ -355,6 +355,10 @@ internal object Devirtualization { node.constructor?.let { dfs(it) } } + is DataFlowIR.Node.AllocInstance -> { + addInstantiatingClass(node.type) + } + is DataFlowIR.Node.Const -> addInstantiatingClass(node.type) is DataFlowIR.Node.StaticCall -> @@ -918,6 +922,10 @@ internal object Devirtualization { instanceNode } + is DataFlowIR.Node.AllocInstance -> { + concreteClass(node.type.resolved()) + } + is DataFlowIR.Node.FieldRead -> fieldNode(node.field)