From 61c18ff58683665539480dcec8216c811fc34546 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Tue, 14 May 2019 16:34:31 +0300 Subject: [PATCH] [DFG] Added type to some operations * Array read/write * Fields read/write * Calls --- .../konan/optimizations/CallGraphBuilder.kt | 5 +- .../backend/konan/optimizations/DFGBuilder.kt | 39 +++++++-- .../konan/optimizations/DFGSerializer.kt | 79 +++++++++++-------- .../backend/konan/optimizations/DataFlowIR.kt | 37 ++++----- .../konan/optimizations/Devirtualization.kt | 28 +++---- 5 files changed, 115 insertions(+), 73 deletions(-) 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 a885686e0ef..1c8c6bab232 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 @@ -98,12 +98,13 @@ internal class CallGraphBuilder(val context: Context, is DataFlowIR.Node.Call -> block(node) is DataFlowIR.Node.Singleton -> - node.constructor?.let { block(DataFlowIR.Node.Call(it, emptyList(), null)) } + node.constructor?.let { block(DataFlowIR.Node.Call(it, emptyList(), node.type, null)) } is DataFlowIR.Node.ArrayRead -> block(DataFlowIR.Node.Call( callee = moduleDFG.symbolTable.mapFunction(arrayGet), arguments = listOf(node.array, node.index), + returnType = node.type, irCallSite = null) ) @@ -111,6 +112,7 @@ internal class CallGraphBuilder(val context: Context, block(DataFlowIR.Node.Call( callee = moduleDFG.symbolTable.mapFunction(arraySet), arguments = listOf(node.array, node.index, node.value), + returnType = moduleDFG.symbolTable.mapType(context.irBuiltIns.unitType), irCallSite = null) ) @@ -118,6 +120,7 @@ internal class CallGraphBuilder(val context: Context, block(DataFlowIR.Node.Call( callee = node.symbol, arguments = emptyList(), + returnType = node.symbol.returnParameter.type, irCallSite = null )) } 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 160cb42926a..36dc863f1c9 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 @@ -514,6 +514,17 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag ) else DataFlowIR.Edge(getNode(expression), null) + private fun mapReturnType(actualType: IrType, returnType: IrType): DataFlowIR.Type { + val returnedInlinedClass = returnType.getInlinedClassNative() + val actualInlinedClass = actualType.getInlinedClassNative() + + return if (returnedInlinedClass == null) { + if (actualInlinedClass == null) symbolTable.mapType(actualType) else symbolTable.mapClassReferenceType(actualInlinedClass) + } else { + symbolTable.mapType(returnType) + } + } + private fun getNode(expression: IrExpression): DataFlowIR.Node { if (expression is IrGetValue) { val valueDeclaration = expression.symbol.owner @@ -554,7 +565,10 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag is IrFunctionReference -> { val callee = value.symbol.owner - DataFlowIR.Node.FunctionReference(symbolTable.mapFunction(callee), symbolTable.mapType(value.type)) + DataFlowIR.Node.FunctionReference( + symbolTable.mapFunction(callee), + symbolTable.mapType(value.type), + /*TODO: substitute*/symbolTable.mapType(callee.returnType)) } is IrConst<*> -> @@ -584,11 +598,17 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag is IrCall -> when (value.symbol) { getContinuationSymbol -> getContinuation() - arrayGetSymbol -> DataFlowIR.Node.ArrayRead(expressionToEdge(value.dispatchReceiver!!), - expressionToEdge(value.getValueArgument(0)!!), value) + arrayGetSymbol -> DataFlowIR.Node.ArrayRead( + array = expressionToEdge(value.dispatchReceiver!!), + index = expressionToEdge(value.getValueArgument(0)!!), + type = mapReturnType(value.type, context.irBuiltIns.anyType), + irCallSite = value) - arraySetSymbol -> DataFlowIR.Node.ArrayWrite(expressionToEdge(value.dispatchReceiver!!), - expressionToEdge(value.getValueArgument(0)!!), expressionToEdge(value.getValueArgument(1)!!)) + arraySetSymbol -> DataFlowIR.Node.ArrayWrite( + array = expressionToEdge(value.dispatchReceiver!!), + index = expressionToEdge(value.getValueArgument(0)!!), + value = expressionToEdge(value.getValueArgument(1)!!), + type = mapReturnType(value.getValueArgument(1)!!.type, context.irBuiltIns.anyType)) createUninitializedInstanceSymbol -> DataFlowIR.Node.AllocInstance(symbolTable.mapClassReferenceType( @@ -606,6 +626,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag symbolTable.mapFunction(callee), arguments, symbolTable.mapClassReferenceType(callee.constructedClass), + symbolTable.mapClassReferenceType(symbols.unit.owner), null ) } @@ -652,6 +673,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag receiverType, calleeHash, arguments, + mapReturnType(value.type, callee.target.returnType), value ) } else { @@ -661,6 +683,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag receiverType, vtableIndex, arguments, + mapReturnType(value.type, callee.target.returnType), value ) } @@ -670,6 +693,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag symbolTable.mapFunction(actualCallee), arguments, actualCallee.dispatchReceiverParameter?.let { symbolTable.mapType(it.type) }, + mapReturnType(value.type, actualCallee.returnType), value ) } @@ -686,6 +710,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag symbolTable.mapFunction(value.symbol.owner), arguments.map { expressionToEdge(it) }, symbolTable.mapType(thiz.type), + symbolTable.mapClassReferenceType(symbols.unit.owner), value ) } @@ -702,6 +727,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag name.localHash.value, takeName { name } ), + mapReturnType(value.type, value.symbol.owner.type), value ) } @@ -718,7 +744,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag name.localHash.value, takeName { name } ), - expressionToEdge(value.value) + expressionToEdge(value.value), + mapReturnType(value.value.type, value.symbol.owner.type) ) } 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 5c1e38762a5..88e1dbd37c5 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 @@ -451,13 +451,14 @@ internal object DFGSerializer { } } - class Call(val callee: Int, val arguments: Array) { + class Call(val callee: Int, val arguments: Array, val returnType: Int) { - constructor(data: ArraySlice) : this(data.readInt(), data.readArray { Edge(this) }) + constructor(data: ArraySlice) : this(data.readInt(), data.readArray { Edge(this) }, data.readInt()) fun write(result: ArraySlice) { result.writeInt(callee) result.writeArray(arguments) { it.write(this) } + result.writeInt(returnType) } } @@ -530,55 +531,60 @@ internal object DFGSerializer { } } - class FunctionReference(val symbol: Int, val type: Int) { + class FunctionReference(val symbol: Int, val type: Int, val returnType: Int) { - constructor(data: ArraySlice) : this(data.readInt(), data.readInt()) + constructor(data: ArraySlice) : this(data.readInt(), data.readInt(), data.readInt()) fun write(result: ArraySlice) { result.writeInt(symbol) result.writeInt(type) + result.writeInt(returnType) } } - class FieldRead(val receiver: Edge?, val field: Field) { + class FieldRead(val receiver: Edge?, val field: Field, val type: Int) { - constructor(data: ArraySlice) : this(data.readNullable { Edge(this) }, Field(data)) + constructor(data: ArraySlice) : this(data.readNullable { Edge(this) }, Field(data), data.readInt()) fun write(result: ArraySlice) { result.writeNullable(receiver) { it.write(this) } field.write(result) + result.writeInt(type) } } - class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge) { + class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge, val type: Int) { - constructor(data: ArraySlice) : this(data.readNullable { Edge(this) }, Field(data), Edge(data)) + constructor(data: ArraySlice) : this(data.readNullable { Edge(this) }, Field(data), Edge(data), data.readInt()) fun write(result: ArraySlice) { result.writeNullable(receiver) { it.write(this) } field.write(result) value.write(result) + result.writeInt(type) } } - class ArrayRead(val array: Edge, val index: Edge) { + class ArrayRead(val array: Edge, val index: Edge, val type: Int) { - constructor(data: ArraySlice) : this(Edge(data), Edge(data)) + constructor(data: ArraySlice) : this(Edge(data), Edge(data), data.readInt()) fun write(result: ArraySlice) { array.write(result) index.write(result) + result.writeInt(type) } } - class ArrayWrite(val array: Edge, val index: Edge, val value: Edge) { + class ArrayWrite(val array: Edge, val index: Edge, val value: Edge, val type: Int) { - constructor(data: ArraySlice) : this(Edge(data), Edge(data), Edge(data)) + constructor(data: ArraySlice) : this(Edge(data), Edge(data), Edge(data), data.readInt()) fun write(result: ArraySlice) { array.write(result) index.write(result) value.write(result) + result.writeInt(type) } } @@ -693,20 +699,20 @@ 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 functionReference(symbol: Int, type: Int, returnType: Int) = + Node().also { it.functionReference = FunctionReference(symbol, type, returnType) } - fun fieldRead(receiver: Edge?, field: Field) = - Node().also { it.fieldRead = FieldRead(receiver, field) } + fun fieldRead(receiver: Edge?, field: Field, type: Int) = + Node().also { it.fieldRead = FieldRead(receiver, field, type) } - fun fieldWrite(receiver: Edge?, field: Field, value: Edge) = - Node().also { it.fieldWrite = FieldWrite(receiver, field, value) } + fun fieldWrite(receiver: Edge?, field: Field, value: Edge, type: Int) = + Node().also { it.fieldWrite = FieldWrite(receiver, field, value, type) } - fun arrayRead(array: Edge, index: Edge) = - Node().also { it.arrayRead = ArrayRead(array, index) } + fun arrayRead(array: Edge, index: Edge, type: Int) = + Node().also { it.arrayRead = ArrayRead(array, index, type) } - fun arrayWrite(array: Edge, index: Edge, value: Edge) = - Node().also { it.arrayWrite = ArrayWrite(array, index, value) } + fun arrayWrite(array: Edge, index: Edge, value: Edge, type: Int) = + Node().also { it.arrayWrite = ArrayWrite(array, index, value, type) } fun variable(values: Array, type: Int, kind: DataFlowIR.VariableKind) = Node().also { it.variable = Variable(values, type, kind.ordinal.toByte()) } @@ -897,7 +903,8 @@ internal object DFGSerializer { fun buildCall(call: DataFlowIR.Node.Call) = Call( functionSymbolMap[call.callee]!!, - call.arguments.map { buildEdge(it) }.toTypedArray() + call.arguments.map { buildEdge(it) }.toTypedArray(), + typeMap[call.returnType]!! ) fun buildVirtualCall(virtualCall: DataFlowIR.Node.VirtualCall) = @@ -932,19 +939,19 @@ internal object DFGSerializer { Node.allocInst(typeMap[node.type]!!) is DataFlowIR.Node.FunctionReference -> - Node.functionReference(functionSymbolMap[node.symbol]!!, typeMap[node.type]!!) + Node.functionReference(functionSymbolMap[node.symbol]!!, typeMap[node.type]!!, typeMap[node.returnType]!!) is DataFlowIR.Node.FieldRead -> - Node.fieldRead(node.receiver?.let { buildEdge(it) }, buildField(node.field)) + Node.fieldRead(node.receiver?.let { buildEdge(it) }, buildField(node.field), typeMap[node.type]!!) is DataFlowIR.Node.FieldWrite -> - Node.fieldWrite(node.receiver?.let { buildEdge(it) }, buildField(node.field), buildEdge(node.value)) + Node.fieldWrite(node.receiver?.let { buildEdge(it) }, buildField(node.field), buildEdge(node.value), typeMap[node.type]!!) is DataFlowIR.Node.ArrayRead -> - Node.arrayRead(buildEdge(node.array), buildEdge(node.index)) + Node.arrayRead(buildEdge(node.array), buildEdge(node.index), typeMap[node.type]!!) is DataFlowIR.Node.ArrayWrite -> - Node.arrayWrite(buildEdge(node.array), buildEdge(node.index), buildEdge(node.value)) + Node.arrayWrite(buildEdge(node.array), buildEdge(node.index), buildEdge(node.value), typeMap[node.type]!!) is DataFlowIR.Node.Variable -> Node.variable(node.values.map { buildEdge(it) }.toTypedArray(), typeMap[node.type]!!, node.kind) @@ -1110,6 +1117,7 @@ internal object DFGSerializer { DataFlowIR.Node.Call( functionSymbols[call.callee], call.arguments.map { deserializeEdge(it) }, + types[call.returnType], irCallSite = null ) @@ -1119,6 +1127,7 @@ internal object DFGSerializer { call.callee, call.arguments, types[virtualCall.receiverType], + types[virtualCall.call.returnType], irCallSite = null ) } @@ -1141,7 +1150,7 @@ 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, receiverType, irCallSite = null) + DataFlowIR.Node.StaticCall(call.callee, call.arguments, receiverType, call.returnType, irCallSite = null) } NodeType.NEW_OBJECT -> { @@ -1158,6 +1167,7 @@ internal object DFGSerializer { virtualCall.receiverType, vtableCall.calleeVtableIndex, virtualCall.arguments, + virtualCall.returnType, virtualCall.irCallSite ) } @@ -1170,6 +1180,7 @@ internal object DFGSerializer { virtualCall.receiverType, itableCall.calleeHash, virtualCall.arguments, + virtualCall.returnType, virtualCall.irCallSite ) } @@ -1185,29 +1196,29 @@ internal object DFGSerializer { NodeType.FUNCTION_REFERENCE -> { val functionReference = it.functionReference!! - DataFlowIR.Node.FunctionReference(functionSymbols[functionReference.symbol], types[functionReference.type]) + DataFlowIR.Node.FunctionReference(functionSymbols[functionReference.symbol], types[functionReference.type], types[functionReference.returnType]) } NodeType.FIELD_READ -> { val fieldRead = it.fieldRead!! val receiver = fieldRead.receiver?.let { deserializeEdge(it) } - DataFlowIR.Node.FieldRead(receiver, deserializeField(fieldRead.field), null) + DataFlowIR.Node.FieldRead(receiver, deserializeField(fieldRead.field), types[fieldRead.type], null) } NodeType.FIELD_WRITE -> { val fieldWrite = it.fieldWrite!! val receiver = fieldWrite.receiver?.let { deserializeEdge(it) } - DataFlowIR.Node.FieldWrite(receiver, deserializeField(fieldWrite.field), deserializeEdge(fieldWrite.value)) + DataFlowIR.Node.FieldWrite(receiver, deserializeField(fieldWrite.field), deserializeEdge(fieldWrite.value), types[fieldWrite.type]) } NodeType.ARRAY_READ -> { val arrayRead = it.arrayRead!! - DataFlowIR.Node.ArrayRead(deserializeEdge(arrayRead.array), deserializeEdge(arrayRead.index), null) + DataFlowIR.Node.ArrayRead(deserializeEdge(arrayRead.array), deserializeEdge(arrayRead.index), types[arrayRead.type], null) } NodeType.ARRAY_WRITE -> { val arrayWrite = it.arrayWrite!! - DataFlowIR.Node.ArrayWrite(deserializeEdge(arrayWrite.array), deserializeEdge(arrayWrite.index), deserializeEdge(arrayWrite.value)) + DataFlowIR.Node.ArrayWrite(deserializeEdge(arrayWrite.array), deserializeEdge(arrayWrite.index), deserializeEdge(arrayWrite.value), types[arrayWrite.type]) } NodeType.VARIABLE -> { 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 7171efeaa68..fd67a6ceeca 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 @@ -223,43 +223,43 @@ internal object DataFlowIR { object Null : Node() - open class Call(val callee: FunctionSymbol, val arguments: List, + open class Call(val callee: FunctionSymbol, val arguments: List, val returnType: Type, open val irCallSite: IrFunctionAccessExpression?) : Node() class StaticCall(callee: FunctionSymbol, arguments: List, - val receiverType: Type?, irCallSite: IrFunctionAccessExpression?) - : Call(callee, arguments, irCallSite) + val receiverType: Type?, returnType: Type, irCallSite: IrFunctionAccessExpression?) + : Call(callee, arguments, returnType, 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: IrConstructorCall?) - : Call(constructor, arguments, irCallSite) + class NewObject(constructor: FunctionSymbol, arguments: List, val constructedType: Type, override val irCallSite: IrConstructorCall?) + : Call(constructor, arguments, constructedType, irCallSite) open class VirtualCall(callee: FunctionSymbol, arguments: List, - val receiverType: Type, override val irCallSite: IrCall?) - : Call(callee, arguments, irCallSite) + val receiverType: Type, returnType: Type, override val irCallSite: IrCall?) + : Call(callee, arguments, returnType, irCallSite) class VtableCall(callee: FunctionSymbol, receiverType: Type, val calleeVtableIndex: Int, - arguments: List, irCallSite: IrCall?) - : VirtualCall(callee, arguments, receiverType, irCallSite) + arguments: List, returnType: Type, irCallSite: IrCall?) + : VirtualCall(callee, arguments, receiverType, returnType, irCallSite) class ItableCall(callee: FunctionSymbol, receiverType: Type, val calleeHash: Long, - arguments: List, irCallSite: IrCall?) - : VirtualCall(callee, arguments, receiverType, irCallSite) + arguments: List, returnType: Type, irCallSite: IrCall?) + : VirtualCall(callee, arguments, receiverType, returnType, irCallSite) class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node() class AllocInstance(val type: Type) : Node() - class FunctionReference(val symbol: FunctionSymbol, val type: Type) : Node() + class FunctionReference(val symbol: FunctionSymbol, val type: Type, val returnType: Type) : Node() - class FieldRead(val receiver: Edge?, val field: Field, val ir: IrGetField?) : Node() + // TODO: Add type (similar to arrays)? + class FieldRead(val receiver: Edge?, val field: Field, val type: Type, val ir: IrGetField?) : Node() - class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge) : Node() + class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge, val type: Type) : Node() - class ArrayRead(val array: Edge, val index: Edge, val irCallSite: IrCall?) : Node() + class ArrayRead(val array: Edge, val index: Edge, val type: Type, val irCallSite: IrCall?) : Node() - class ArrayWrite(val array: Edge, val index: Edge, val value: Edge) : Node() + class ArrayWrite(val array: Edge, val index: Edge, val value: Edge, val type: Type) : Node() class Variable(values: List, val type: Type, val kind: VariableKind) : Node() { val values = mutableListOf().also { it += values } @@ -551,7 +551,8 @@ internal object DataFlowIR { primitiveBinaryType, module, -1, - null + null, + takeName { primitiveBinaryType.name } ) } 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 ec8c46d0c71..6c883309c7e 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 @@ -253,7 +253,7 @@ internal object Devirtualization { addInstantiatingClass(symbolTable.mapType(context.irBuiltIns.stringType)) } // Traverse call graph from the roots. - rootSet.forEach { dfs(it) } + rootSet.forEach { dfs(it, it.returnParameter.type) } return instantiatingClasses } @@ -282,7 +282,7 @@ internal object Devirtualization { else -> error("Unreachable") } - dfs(callee) + dfs(callee, virtualCall.returnType) } private fun checkSupertypes(type: DataFlowIR.Type.Declared, @@ -317,13 +317,13 @@ internal object Devirtualization { .forEach { checkSupertypes(it, inheritor, seenTypes) } } - private fun dfs(symbol: DataFlowIR.FunctionSymbol) { + private fun dfs(symbol: DataFlowIR.FunctionSymbol, returnType: DataFlowIR.Type) { val resolvedFunctionSymbol = symbol.resolved() if (resolvedFunctionSymbol is DataFlowIR.FunctionSymbol.External) { DEBUG_OUTPUT(1) { println("Function $resolvedFunctionSymbol is external") } - val resolvedReturnType = symbol.returnParameter.type.resolved() + val resolvedReturnType = returnType.resolved() if (resolvedReturnType.isFinal) { DEBUG_OUTPUT(1) { println("Adding return type as it is final") } @@ -346,12 +346,12 @@ internal object Devirtualization { when (node) { is DataFlowIR.Node.NewObject -> { addInstantiatingClass(node.constructedType) - dfs(node.callee) + dfs(node.callee, node.constructedType) } is DataFlowIR.Node.Singleton -> { addInstantiatingClass(node.type) - node.constructor?.let { dfs(it) } + node.constructor?.let { dfs(it, node.type) } } is DataFlowIR.Node.AllocInstance -> { @@ -361,10 +361,10 @@ internal object Devirtualization { is DataFlowIR.Node.Const -> addInstantiatingClass(node.type) is DataFlowIR.Node.StaticCall -> - dfs(node.callee) + dfs(node.callee, node.returnType) is DataFlowIR.Node.FunctionReference -> - dfs(node.symbol) + dfs(node.symbol, node.returnType) is DataFlowIR.Node.FieldRead -> if (entryPoint == null && node.field.type.isFinal) @@ -889,7 +889,7 @@ internal object Devirtualization { function.parameters[node.index] is DataFlowIR.Node.StaticCall -> - doCall(node.callee, node.arguments, node.callee.returnParameter.type.resolved(), + doCall(node.callee, node.arguments, node.returnType.resolved(), node.receiverType?.resolved()) is DataFlowIR.Node.NewObject -> { @@ -933,7 +933,7 @@ internal object Devirtualization { println() } - val returnType = node.callee.returnParameter.type.resolved() + val returnType = node.returnType.resolved() val receiverNode = edgeToConstraintNode(node.arguments[0]) if (receiverType == DataFlowIR.Type.Virtual) constraintGraph.virtualNode.addEdge(receiverNode) @@ -983,20 +983,20 @@ internal object Devirtualization { } is DataFlowIR.Node.FieldRead -> - fieldNode(node.field) + doCast(function, fieldNode(node.field), node.type.resolved()) is DataFlowIR.Node.FieldWrite -> { val fieldNode = fieldNode(node.field) - edgeToConstraintNode(node.value).addEdge(fieldNode) + doCast(function, edgeToConstraintNode(node.value), node.type.resolved()).addEdge(fieldNode) constraintGraph.voidNode } is DataFlowIR.Node.ArrayRead -> - fieldNode(constraintGraph.arrayItemField) + doCast(function, fieldNode(constraintGraph.arrayItemField), node.type.resolved()) is DataFlowIR.Node.ArrayWrite -> { val fieldNode = fieldNode(constraintGraph.arrayItemField) - edgeToConstraintNode(node.value).addEdge(fieldNode) + doCast(function, edgeToConstraintNode(node.value), node.type.resolved()).addEdge(fieldNode) constraintGraph.voidNode }