diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt index b2589b8ef70..071f1f6c19c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt @@ -124,6 +124,13 @@ internal class CallGraphBuilder(val context: Context, } } } + body.nodes.filterIsInstance() + .forEach { + val callee = it.symbol.resolved() + if (callee is DataFlowIR.FunctionSymbol.Declared + && !directEdges.containsKey(callee)) + dfs(callee) + } } else { var function = moduleDFG.functions[symbol] var local = true @@ -160,6 +167,16 @@ internal class CallGraphBuilder(val context: Context, } } } + body.nodes.filterIsInstance() + .forEach { + val callee = it.symbol.resolved() + if (moduleDFG.functions.containsKey(callee)) + addNode(callee) + if (callee is DataFlowIR.FunctionSymbol.Declared + && !visitedFunctions.contains(callee)) + dfs(callee) + } + } } } \ No newline at end of file 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 77fc20f4d5f..94460949b09 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 @@ -545,8 +545,12 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag when (value) { is IrGetValue -> getNode(value) - is IrVararg, - is IrFunctionReference -> DataFlowIR.Node.Const(symbolTable.mapType(value.type)) + is IrVararg -> DataFlowIR.Node.Const(symbolTable.mapType(value.type)) + + is IrFunctionReference -> { + val callee = value.symbol.owner + DataFlowIR.Node.FunctionReference(symbolTable.mapFunction(callee), symbolTable.mapType(value.type)) + } is IrConst<*> -> if (value.value == null) 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 d7f58475f20..5c1e38762a5 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 @@ -530,6 +530,16 @@ internal object DFGSerializer { } } + class FunctionReference(val symbol: Int, val type: Int) { + + constructor(data: ArraySlice) : this(data.readInt(), data.readInt()) + + fun write(result: ArraySlice) { + result.writeInt(symbol) + result.writeInt(type) + } + } + class FieldRead(val receiver: Edge?, val field: Field) { constructor(data: ArraySlice) : this(data.readNullable { Edge(this) }, Field(data)) @@ -594,6 +604,7 @@ internal object DFGSerializer { ITABLE_CALL, SINGLETON, ALLOC_INSTANCE, + FUNCTION_REFERENCE, FIELD_READ, FIELD_WRITE, ARRAY_READ, @@ -611,21 +622,23 @@ internal object DFGSerializer { 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 + var functionReference: FunctionReference? = 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 - allocInstance != null -> NodeType.ALLOC_INSTANCE + 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 + functionReference != null -> NodeType.FUNCTION_REFERENCE fieldRead != null -> NodeType.FIELD_READ fieldWrite != null -> NodeType.FIELD_WRITE arrayRead != null -> NodeType.ARRAY_READ @@ -637,19 +650,20 @@ internal object DFGSerializer { 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) - allocInstance?.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) + functionReference?.write(result) + fieldRead ?.write(result) + fieldWrite ?.write(result) + arrayRead ?.write(result) + arrayWrite ?.write(result) + variable ?.write(result) } companion object { @@ -679,6 +693,9 @@ internal object DFGSerializer { fun allocInst(type: Int) = Node().also { it.allocInstance = AllocInstance(type) } + fun functionReference(symbol: Int, type: Int) = + Node().also { it.functionReference = FunctionReference(symbol, type) } + fun fieldRead(receiver: Edge?, field: Field) = Node().also { it.fieldRead = FieldRead(receiver, field) } @@ -707,12 +724,13 @@ internal object DFGSerializer { 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 -> { } + NodeType.FUNCTION_REFERENCE -> result.functionReference = FunctionReference(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 } @@ -913,6 +931,9 @@ internal object DFGSerializer { is DataFlowIR.Node.AllocInstance -> Node.allocInst(typeMap[node.type]!!) + is DataFlowIR.Node.FunctionReference -> + Node.functionReference(functionSymbolMap[node.symbol]!!, typeMap[node.type]!!) + is DataFlowIR.Node.FieldRead -> Node.fieldRead(node.receiver?.let { buildEdge(it) }, buildField(node.field)) @@ -1162,6 +1183,11 @@ internal object DFGSerializer { DataFlowIR.Node.AllocInstance(types[it.allocInstance!!.type]) } + NodeType.FUNCTION_REFERENCE -> { + val functionReference = it.functionReference!! + DataFlowIR.Node.FunctionReference(functionSymbols[functionReference.symbol], types[functionReference.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 33ceb602151..29f42bdb90c 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 @@ -254,6 +254,8 @@ internal object DataFlowIR { class AllocInstance(val type: Type) : Node() + class FunctionReference(val symbol: FunctionSymbol, 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() @@ -302,6 +304,9 @@ internal object DataFlowIR { is Node.AllocInstance -> " ALLOC INSTANCE ${node.type}\n" + is Node.FunctionReference -> + " FUNCTION REFERENCE ${node.symbol}\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 0888bf8f981..d9166bdb333 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 @@ -358,6 +358,9 @@ internal object Devirtualization { is DataFlowIR.Node.StaticCall -> dfs(node.callee) + is DataFlowIR.Node.FunctionReference -> + dfs(node.symbol) + is DataFlowIR.Node.FieldRead -> if (entryPoint == null && node.field.type.isFinal) addInstantiatingClass(node.field.type) @@ -963,6 +966,10 @@ internal object Devirtualization { concreteClass(node.type.resolved()) } + is DataFlowIR.Node.FunctionReference -> { + concreteClass(node.type.resolved()) + } + is DataFlowIR.Node.FieldRead -> fieldNode(node.field)