[DFG] Added type to some operations

* Array read/write
* Fields read/write
* Calls
This commit is contained in:
Igor Chevdar
2019-05-14 16:34:31 +03:00
parent 960f8048ca
commit 61c18ff586
5 changed files with 115 additions and 73 deletions
@@ -98,12 +98,13 @@ internal class CallGraphBuilder(val context: Context,
is DataFlowIR.Node.Call -> block(node) is DataFlowIR.Node.Call -> block(node)
is DataFlowIR.Node.Singleton -> 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 -> is DataFlowIR.Node.ArrayRead ->
block(DataFlowIR.Node.Call( block(DataFlowIR.Node.Call(
callee = moduleDFG.symbolTable.mapFunction(arrayGet), callee = moduleDFG.symbolTable.mapFunction(arrayGet),
arguments = listOf(node.array, node.index), arguments = listOf(node.array, node.index),
returnType = node.type,
irCallSite = null) irCallSite = null)
) )
@@ -111,6 +112,7 @@ internal class CallGraphBuilder(val context: Context,
block(DataFlowIR.Node.Call( block(DataFlowIR.Node.Call(
callee = moduleDFG.symbolTable.mapFunction(arraySet), callee = moduleDFG.symbolTable.mapFunction(arraySet),
arguments = listOf(node.array, node.index, node.value), arguments = listOf(node.array, node.index, node.value),
returnType = moduleDFG.symbolTable.mapType(context.irBuiltIns.unitType),
irCallSite = null) irCallSite = null)
) )
@@ -118,6 +120,7 @@ internal class CallGraphBuilder(val context: Context,
block(DataFlowIR.Node.Call( block(DataFlowIR.Node.Call(
callee = node.symbol, callee = node.symbol,
arguments = emptyList(), arguments = emptyList(),
returnType = node.symbol.returnParameter.type,
irCallSite = null irCallSite = null
)) ))
} }
@@ -514,6 +514,17 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
) )
else DataFlowIR.Edge(getNode(expression), null) 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 { private fun getNode(expression: IrExpression): DataFlowIR.Node {
if (expression is IrGetValue) { if (expression is IrGetValue) {
val valueDeclaration = expression.symbol.owner val valueDeclaration = expression.symbol.owner
@@ -554,7 +565,10 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrFunctionReference -> { is IrFunctionReference -> {
val callee = value.symbol.owner 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<*> -> is IrConst<*> ->
@@ -584,11 +598,17 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrCall -> when (value.symbol) { is IrCall -> when (value.symbol) {
getContinuationSymbol -> getContinuation() getContinuationSymbol -> getContinuation()
arrayGetSymbol -> DataFlowIR.Node.ArrayRead(expressionToEdge(value.dispatchReceiver!!), arrayGetSymbol -> DataFlowIR.Node.ArrayRead(
expressionToEdge(value.getValueArgument(0)!!), value) 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!!), arraySetSymbol -> DataFlowIR.Node.ArrayWrite(
expressionToEdge(value.getValueArgument(0)!!), expressionToEdge(value.getValueArgument(1)!!)) array = expressionToEdge(value.dispatchReceiver!!),
index = expressionToEdge(value.getValueArgument(0)!!),
value = expressionToEdge(value.getValueArgument(1)!!),
type = mapReturnType(value.getValueArgument(1)!!.type, context.irBuiltIns.anyType))
createUninitializedInstanceSymbol -> createUninitializedInstanceSymbol ->
DataFlowIR.Node.AllocInstance(symbolTable.mapClassReferenceType( DataFlowIR.Node.AllocInstance(symbolTable.mapClassReferenceType(
@@ -606,6 +626,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
symbolTable.mapFunction(callee), symbolTable.mapFunction(callee),
arguments, arguments,
symbolTable.mapClassReferenceType(callee.constructedClass), symbolTable.mapClassReferenceType(callee.constructedClass),
symbolTable.mapClassReferenceType(symbols.unit.owner),
null null
) )
} }
@@ -652,6 +673,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
receiverType, receiverType,
calleeHash, calleeHash,
arguments, arguments,
mapReturnType(value.type, callee.target.returnType),
value value
) )
} else { } else {
@@ -661,6 +683,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
receiverType, receiverType,
vtableIndex, vtableIndex,
arguments, arguments,
mapReturnType(value.type, callee.target.returnType),
value value
) )
} }
@@ -670,6 +693,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
symbolTable.mapFunction(actualCallee), symbolTable.mapFunction(actualCallee),
arguments, arguments,
actualCallee.dispatchReceiverParameter?.let { symbolTable.mapType(it.type) }, actualCallee.dispatchReceiverParameter?.let { symbolTable.mapType(it.type) },
mapReturnType(value.type, actualCallee.returnType),
value value
) )
} }
@@ -686,6 +710,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
symbolTable.mapFunction(value.symbol.owner), symbolTable.mapFunction(value.symbol.owner),
arguments.map { expressionToEdge(it) }, arguments.map { expressionToEdge(it) },
symbolTable.mapType(thiz.type), symbolTable.mapType(thiz.type),
symbolTable.mapClassReferenceType(symbols.unit.owner),
value value
) )
} }
@@ -702,6 +727,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
name.localHash.value, name.localHash.value,
takeName { name } takeName { name }
), ),
mapReturnType(value.type, value.symbol.owner.type),
value value
) )
} }
@@ -718,7 +744,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
name.localHash.value, name.localHash.value,
takeName { name } takeName { name }
), ),
expressionToEdge(value.value) expressionToEdge(value.value),
mapReturnType(value.value.type, value.symbol.owner.type)
) )
} }
@@ -451,13 +451,14 @@ internal object DFGSerializer {
} }
} }
class Call(val callee: Int, val arguments: Array<Edge>) { class Call(val callee: Int, val arguments: Array<Edge>, 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) { fun write(result: ArraySlice) {
result.writeInt(callee) result.writeInt(callee)
result.writeArray(arguments) { it.write(this) } 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) { fun write(result: ArraySlice) {
result.writeInt(symbol) result.writeInt(symbol)
result.writeInt(type) 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) { fun write(result: ArraySlice) {
result.writeNullable(receiver) { it.write(this) } result.writeNullable(receiver) { it.write(this) }
field.write(result) 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) { fun write(result: ArraySlice) {
result.writeNullable(receiver) { it.write(this) } result.writeNullable(receiver) { it.write(this) }
field.write(result) field.write(result)
value.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) { fun write(result: ArraySlice) {
array.write(result) array.write(result)
index.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) { fun write(result: ArraySlice) {
array.write(result) array.write(result)
index.write(result) index.write(result)
value.write(result) value.write(result)
result.writeInt(type)
} }
} }
@@ -693,20 +699,20 @@ internal object DFGSerializer {
fun allocInst(type: Int) = fun allocInst(type: Int) =
Node().also { it.allocInstance = AllocInstance(type) } Node().also { it.allocInstance = AllocInstance(type) }
fun functionReference(symbol: Int, type: Int) = fun functionReference(symbol: Int, type: Int, returnType: Int) =
Node().also { it.functionReference = FunctionReference(symbol, type) } Node().also { it.functionReference = FunctionReference(symbol, type, returnType) }
fun fieldRead(receiver: Edge?, field: Field) = fun fieldRead(receiver: Edge?, field: Field, type: Int) =
Node().also { it.fieldRead = FieldRead(receiver, field) } Node().also { it.fieldRead = FieldRead(receiver, field, type) }
fun fieldWrite(receiver: Edge?, field: Field, value: Edge) = fun fieldWrite(receiver: Edge?, field: Field, value: Edge, type: Int) =
Node().also { it.fieldWrite = FieldWrite(receiver, field, value) } Node().also { it.fieldWrite = FieldWrite(receiver, field, value, type) }
fun arrayRead(array: Edge, index: Edge) = fun arrayRead(array: Edge, index: Edge, type: Int) =
Node().also { it.arrayRead = ArrayRead(array, index) } Node().also { it.arrayRead = ArrayRead(array, index, type) }
fun arrayWrite(array: Edge, index: Edge, value: Edge) = fun arrayWrite(array: Edge, index: Edge, value: Edge, type: Int) =
Node().also { it.arrayWrite = ArrayWrite(array, index, value) } Node().also { it.arrayWrite = ArrayWrite(array, index, value, type) }
fun variable(values: Array<Edge>, type: Int, kind: DataFlowIR.VariableKind) = fun variable(values: Array<Edge>, type: Int, kind: DataFlowIR.VariableKind) =
Node().also { it.variable = Variable(values, type, kind.ordinal.toByte()) } Node().also { it.variable = Variable(values, type, kind.ordinal.toByte()) }
@@ -897,7 +903,8 @@ internal object DFGSerializer {
fun buildCall(call: DataFlowIR.Node.Call) = fun buildCall(call: DataFlowIR.Node.Call) =
Call( Call(
functionSymbolMap[call.callee]!!, functionSymbolMap[call.callee]!!,
call.arguments.map { buildEdge(it) }.toTypedArray() call.arguments.map { buildEdge(it) }.toTypedArray(),
typeMap[call.returnType]!!
) )
fun buildVirtualCall(virtualCall: DataFlowIR.Node.VirtualCall) = fun buildVirtualCall(virtualCall: DataFlowIR.Node.VirtualCall) =
@@ -932,19 +939,19 @@ internal object DFGSerializer {
Node.allocInst(typeMap[node.type]!!) Node.allocInst(typeMap[node.type]!!)
is DataFlowIR.Node.FunctionReference -> 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 -> 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 -> 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 -> 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 -> 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 -> is DataFlowIR.Node.Variable ->
Node.variable(node.values.map { buildEdge(it) }.toTypedArray(), typeMap[node.type]!!, node.kind) Node.variable(node.values.map { buildEdge(it) }.toTypedArray(), typeMap[node.type]!!, node.kind)
@@ -1110,6 +1117,7 @@ internal object DFGSerializer {
DataFlowIR.Node.Call( DataFlowIR.Node.Call(
functionSymbols[call.callee], functionSymbols[call.callee],
call.arguments.map { deserializeEdge(it) }, call.arguments.map { deserializeEdge(it) },
types[call.returnType],
irCallSite = null irCallSite = null
) )
@@ -1119,6 +1127,7 @@ internal object DFGSerializer {
call.callee, call.callee,
call.arguments, call.arguments,
types[virtualCall.receiverType], types[virtualCall.receiverType],
types[virtualCall.call.returnType],
irCallSite = null irCallSite = null
) )
} }
@@ -1141,7 +1150,7 @@ internal object DFGSerializer {
val staticCall = it.staticCall!! val staticCall = it.staticCall!!
val call = deserializeCall(staticCall.call) val call = deserializeCall(staticCall.call)
val receiverType = staticCall.receiverType?.let { types[it] } 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 -> { NodeType.NEW_OBJECT -> {
@@ -1158,6 +1167,7 @@ internal object DFGSerializer {
virtualCall.receiverType, virtualCall.receiverType,
vtableCall.calleeVtableIndex, vtableCall.calleeVtableIndex,
virtualCall.arguments, virtualCall.arguments,
virtualCall.returnType,
virtualCall.irCallSite virtualCall.irCallSite
) )
} }
@@ -1170,6 +1180,7 @@ internal object DFGSerializer {
virtualCall.receiverType, virtualCall.receiverType,
itableCall.calleeHash, itableCall.calleeHash,
virtualCall.arguments, virtualCall.arguments,
virtualCall.returnType,
virtualCall.irCallSite virtualCall.irCallSite
) )
} }
@@ -1185,29 +1196,29 @@ internal object DFGSerializer {
NodeType.FUNCTION_REFERENCE -> { NodeType.FUNCTION_REFERENCE -> {
val functionReference = it.functionReference!! 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 -> { NodeType.FIELD_READ -> {
val fieldRead = it.fieldRead!! val fieldRead = it.fieldRead!!
val receiver = fieldRead.receiver?.let { deserializeEdge(it) } 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 -> { NodeType.FIELD_WRITE -> {
val fieldWrite = it.fieldWrite!! val fieldWrite = it.fieldWrite!!
val receiver = fieldWrite.receiver?.let { deserializeEdge(it) } 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 -> { NodeType.ARRAY_READ -> {
val arrayRead = it.arrayRead!! 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 -> { NodeType.ARRAY_WRITE -> {
val arrayWrite = it.arrayWrite!! 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 -> { NodeType.VARIABLE -> {
@@ -223,43 +223,43 @@ internal object DataFlowIR {
object Null : Node() object Null : Node()
open class Call(val callee: FunctionSymbol, val arguments: List<Edge>, open class Call(val callee: FunctionSymbol, val arguments: List<Edge>, val returnType: Type,
open val irCallSite: IrFunctionAccessExpression?) : Node() open val irCallSite: IrFunctionAccessExpression?) : Node()
class StaticCall(callee: FunctionSymbol, arguments: List<Edge>, class StaticCall(callee: FunctionSymbol, arguments: List<Edge>,
val receiverType: Type?, irCallSite: IrFunctionAccessExpression?) val receiverType: Type?, returnType: Type, irCallSite: IrFunctionAccessExpression?)
: Call(callee, arguments, irCallSite) : Call(callee, arguments, returnType, irCallSite)
// TODO: It can be replaced with a pair(AllocInstance, constructor Call), remove. // TODO: It can be replaced with a pair(AllocInstance, constructor Call), remove.
class NewObject(constructor: FunctionSymbol, arguments: List<Edge>, val constructedType: Type, class NewObject(constructor: FunctionSymbol, arguments: List<Edge>, val constructedType: Type, override val irCallSite: IrConstructorCall?)
override val irCallSite: IrConstructorCall?) : Call(constructor, arguments, constructedType, irCallSite)
: Call(constructor, arguments, irCallSite)
open class VirtualCall(callee: FunctionSymbol, arguments: List<Edge>, open class VirtualCall(callee: FunctionSymbol, arguments: List<Edge>,
val receiverType: Type, override val irCallSite: IrCall?) val receiverType: Type, returnType: Type, override val irCallSite: IrCall?)
: Call(callee, arguments, irCallSite) : Call(callee, arguments, returnType, irCallSite)
class VtableCall(callee: FunctionSymbol, receiverType: Type, val calleeVtableIndex: Int, class VtableCall(callee: FunctionSymbol, receiverType: Type, val calleeVtableIndex: Int,
arguments: List<Edge>, irCallSite: IrCall?) arguments: List<Edge>, returnType: Type, irCallSite: IrCall?)
: VirtualCall(callee, arguments, receiverType, irCallSite) : VirtualCall(callee, arguments, receiverType, returnType, irCallSite)
class ItableCall(callee: FunctionSymbol, receiverType: Type, val calleeHash: Long, class ItableCall(callee: FunctionSymbol, receiverType: Type, val calleeHash: Long,
arguments: List<Edge>, irCallSite: IrCall?) arguments: List<Edge>, returnType: Type, irCallSite: IrCall?)
: VirtualCall(callee, arguments, receiverType, irCallSite) : VirtualCall(callee, arguments, receiverType, returnType, irCallSite)
class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node() class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node()
class AllocInstance(val type: Type) : 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<Edge>, val type: Type, val kind: VariableKind) : Node() { class Variable(values: List<Edge>, val type: Type, val kind: VariableKind) : Node() {
val values = mutableListOf<Edge>().also { it += values } val values = mutableListOf<Edge>().also { it += values }
@@ -551,7 +551,8 @@ internal object DataFlowIR {
primitiveBinaryType, primitiveBinaryType,
module, module,
-1, -1,
null null,
takeName { primitiveBinaryType.name }
) )
} }
@@ -253,7 +253,7 @@ internal object Devirtualization {
addInstantiatingClass(symbolTable.mapType(context.irBuiltIns.stringType)) addInstantiatingClass(symbolTable.mapType(context.irBuiltIns.stringType))
} }
// Traverse call graph from the roots. // Traverse call graph from the roots.
rootSet.forEach { dfs(it) } rootSet.forEach { dfs(it, it.returnParameter.type) }
return instantiatingClasses return instantiatingClasses
} }
@@ -282,7 +282,7 @@ internal object Devirtualization {
else -> error("Unreachable") else -> error("Unreachable")
} }
dfs(callee) dfs(callee, virtualCall.returnType)
} }
private fun checkSupertypes(type: DataFlowIR.Type.Declared, private fun checkSupertypes(type: DataFlowIR.Type.Declared,
@@ -317,13 +317,13 @@ internal object Devirtualization {
.forEach { checkSupertypes(it, inheritor, seenTypes) } .forEach { checkSupertypes(it, inheritor, seenTypes) }
} }
private fun dfs(symbol: DataFlowIR.FunctionSymbol) { private fun dfs(symbol: DataFlowIR.FunctionSymbol, returnType: DataFlowIR.Type) {
val resolvedFunctionSymbol = symbol.resolved() val resolvedFunctionSymbol = symbol.resolved()
if (resolvedFunctionSymbol is DataFlowIR.FunctionSymbol.External) { if (resolvedFunctionSymbol is DataFlowIR.FunctionSymbol.External) {
DEBUG_OUTPUT(1) { println("Function $resolvedFunctionSymbol is external") } DEBUG_OUTPUT(1) { println("Function $resolvedFunctionSymbol is external") }
val resolvedReturnType = symbol.returnParameter.type.resolved() val resolvedReturnType = returnType.resolved()
if (resolvedReturnType.isFinal) { if (resolvedReturnType.isFinal) {
DEBUG_OUTPUT(1) { println("Adding return type as it is final") } DEBUG_OUTPUT(1) { println("Adding return type as it is final") }
@@ -346,12 +346,12 @@ internal object Devirtualization {
when (node) { when (node) {
is DataFlowIR.Node.NewObject -> { is DataFlowIR.Node.NewObject -> {
addInstantiatingClass(node.constructedType) addInstantiatingClass(node.constructedType)
dfs(node.callee) dfs(node.callee, node.constructedType)
} }
is DataFlowIR.Node.Singleton -> { is DataFlowIR.Node.Singleton -> {
addInstantiatingClass(node.type) addInstantiatingClass(node.type)
node.constructor?.let { dfs(it) } node.constructor?.let { dfs(it, node.type) }
} }
is DataFlowIR.Node.AllocInstance -> { is DataFlowIR.Node.AllocInstance -> {
@@ -361,10 +361,10 @@ internal object Devirtualization {
is DataFlowIR.Node.Const -> addInstantiatingClass(node.type) is DataFlowIR.Node.Const -> addInstantiatingClass(node.type)
is DataFlowIR.Node.StaticCall -> is DataFlowIR.Node.StaticCall ->
dfs(node.callee) dfs(node.callee, node.returnType)
is DataFlowIR.Node.FunctionReference -> is DataFlowIR.Node.FunctionReference ->
dfs(node.symbol) dfs(node.symbol, node.returnType)
is DataFlowIR.Node.FieldRead -> is DataFlowIR.Node.FieldRead ->
if (entryPoint == null && node.field.type.isFinal) if (entryPoint == null && node.field.type.isFinal)
@@ -889,7 +889,7 @@ internal object Devirtualization {
function.parameters[node.index] function.parameters[node.index]
is DataFlowIR.Node.StaticCall -> 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()) node.receiverType?.resolved())
is DataFlowIR.Node.NewObject -> { is DataFlowIR.Node.NewObject -> {
@@ -933,7 +933,7 @@ internal object Devirtualization {
println() println()
} }
val returnType = node.callee.returnParameter.type.resolved() val returnType = node.returnType.resolved()
val receiverNode = edgeToConstraintNode(node.arguments[0]) val receiverNode = edgeToConstraintNode(node.arguments[0])
if (receiverType == DataFlowIR.Type.Virtual) if (receiverType == DataFlowIR.Type.Virtual)
constraintGraph.virtualNode.addEdge(receiverNode) constraintGraph.virtualNode.addEdge(receiverNode)
@@ -983,20 +983,20 @@ internal object Devirtualization {
} }
is DataFlowIR.Node.FieldRead -> is DataFlowIR.Node.FieldRead ->
fieldNode(node.field) doCast(function, fieldNode(node.field), node.type.resolved())
is DataFlowIR.Node.FieldWrite -> { is DataFlowIR.Node.FieldWrite -> {
val fieldNode = fieldNode(node.field) val fieldNode = fieldNode(node.field)
edgeToConstraintNode(node.value).addEdge(fieldNode) doCast(function, edgeToConstraintNode(node.value), node.type.resolved()).addEdge(fieldNode)
constraintGraph.voidNode constraintGraph.voidNode
} }
is DataFlowIR.Node.ArrayRead -> is DataFlowIR.Node.ArrayRead ->
fieldNode(constraintGraph.arrayItemField) doCast(function, fieldNode(constraintGraph.arrayItemField), node.type.resolved())
is DataFlowIR.Node.ArrayWrite -> { is DataFlowIR.Node.ArrayWrite -> {
val fieldNode = fieldNode(constraintGraph.arrayItemField) val fieldNode = fieldNode(constraintGraph.arrayItemField)
edgeToConstraintNode(node.value).addEdge(fieldNode) doCast(function, edgeToConstraintNode(node.value), node.type.resolved()).addEdge(fieldNode)
constraintGraph.voidNode constraintGraph.voidNode
} }