Devritualization analysis enhancement

This commit is contained in:
Igor Chevdar
2019-06-03 16:25:20 +03:00
parent 61c18ff586
commit e7f721bc63
2 changed files with 33 additions and 12 deletions
@@ -231,7 +231,8 @@ internal object DataFlowIR {
: Call(callee, arguments, returnType, 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, override val irCallSite: IrConstructorCall?) class NewObject(constructor: FunctionSymbol, arguments: List<Edge>,
val constructedType: Type, override val irCallSite: IrConstructorCall?)
: Call(constructor, arguments, constructedType, irCallSite) : Call(constructor, arguments, constructedType, irCallSite)
open class VirtualCall(callee: FunctionSymbol, arguments: List<Edge>, open class VirtualCall(callee: FunctionSymbol, arguments: List<Edge>,
@@ -252,7 +253,6 @@ internal object DataFlowIR {
class FunctionReference(val symbol: FunctionSymbol, val type: Type, val returnType: Type) : Node() class FunctionReference(val symbol: FunctionSymbol, val type: Type, val returnType: Type) : Node()
// TODO: Add type (similar to arrays)?
class FieldRead(val receiver: Edge?, val field: Field, val type: Type, val ir: IrGetField?) : Node() 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, val type: Type) : Node() class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge, val type: Type) : Node()
@@ -472,7 +472,7 @@ internal object Devirtualization {
val nodesMap = mutableMapOf<DataFlowIR.Node, Node>() val nodesMap = mutableMapOf<DataFlowIR.Node, Node>()
val constraintGraphBuilder = val constraintGraphBuilder =
ConstraintGraphBuilder(nodesMap, functions, typeHierarchy, instantiatingClasses, allTypes, rootSet) ConstraintGraphBuilder(nodesMap, functions, typeHierarchy, instantiatingClasses, allTypes, rootSet, true)
constraintGraphBuilder.build() constraintGraphBuilder.build()
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
@@ -678,7 +678,8 @@ internal object Devirtualization {
val typeHierarchy: TypeHierarchy, val typeHierarchy: TypeHierarchy,
val instantiatingClasses: Map<DataFlowIR.Type.Declared, Int>, val instantiatingClasses: Map<DataFlowIR.Type.Declared, Int>,
val allTypes: List<DataFlowIR.Type.Declared>, val allTypes: List<DataFlowIR.Type.Declared>,
val rootSet: List<DataFlowIR.FunctionSymbol>) { val rootSet: List<DataFlowIR.FunctionSymbol>,
val useTypes: Boolean) {
private val variables = mutableMapOf<DataFlowIR.Node.Variable, Node>() private val variables = mutableMapOf<DataFlowIR.Node.Variable, Node>()
@@ -827,7 +828,10 @@ internal object Devirtualization {
val argument = argumentToConstraintNode(arguments[index]) val argument = argumentToConstraintNode(arguments[index])
argument.addEdge(parameter) argument.addEdge(parameter)
} }
return callee.returns return if (!useTypes || returnType == callee.symbol.returnParameter.type.resolved())
callee.returns
else
doCast(function, callee.returns, returnType)
} }
fun doCall(callee: DataFlowIR.FunctionSymbol, fun doCall(callee: DataFlowIR.FunctionSymbol,
@@ -853,7 +857,7 @@ internal object Devirtualization {
} }
} else { } else {
calleeConstraintGraph.throws.addEdge(function.throws) calleeConstraintGraph.throws.addEdge(function.throws)
if (receiverType == null) if (!useTypes || receiverType == null || receiverType == callee.parameters[0].type.resolved())
doCall(calleeConstraintGraph, arguments, returnType) doCall(calleeConstraintGraph, arguments, returnType)
else { else {
val receiverNode = argumentToConstraintNode(arguments[0]) val receiverNode = argumentToConstraintNode(arguments[0])
@@ -864,6 +868,25 @@ internal object Devirtualization {
} }
} }
fun readField(field: DataFlowIR.Field, actualType: DataFlowIR.Type.Declared): Node {
val fieldNode = fieldNode(field)
val expectedType = field.type.resolved()
return if (!useTypes || actualType == expectedType)
fieldNode
else
doCast(function, fieldNode, actualType)
}
fun writeField(field: DataFlowIR.Field, actualType: DataFlowIR.Type.Declared, value: Node) {
val fieldNode = fieldNode(field)
val expectedType = field.type.resolved()
val castedValue = if (!useTypes || actualType == expectedType)
value
else
doCast(function, value, actualType)
castedValue.addEdge(fieldNode)
}
if (node is DataFlowIR.Node.Variable && node.kind != DataFlowIR.VariableKind.Temporary) { if (node is DataFlowIR.Node.Variable && node.kind != DataFlowIR.VariableKind.Temporary) {
var variableNode = variables[node] var variableNode = variables[node]
if (variableNode == null) { if (variableNode == null) {
@@ -983,20 +1006,18 @@ internal object Devirtualization {
} }
is DataFlowIR.Node.FieldRead -> is DataFlowIR.Node.FieldRead ->
doCast(function, fieldNode(node.field), node.type.resolved()) readField(node.field, node.field.type.resolved())
is DataFlowIR.Node.FieldWrite -> { is DataFlowIR.Node.FieldWrite -> {
val fieldNode = fieldNode(node.field) writeField(node.field, node.field.type.resolved(), edgeToConstraintNode(node.value))
doCast(function, edgeToConstraintNode(node.value), node.type.resolved()).addEdge(fieldNode)
constraintGraph.voidNode constraintGraph.voidNode
} }
is DataFlowIR.Node.ArrayRead -> is DataFlowIR.Node.ArrayRead ->
doCast(function, fieldNode(constraintGraph.arrayItemField), node.type.resolved()) readField(constraintGraph.arrayItemField, node.type.resolved())
is DataFlowIR.Node.ArrayWrite -> { is DataFlowIR.Node.ArrayWrite -> {
val fieldNode = fieldNode(constraintGraph.arrayItemField) writeField(constraintGraph.arrayItemField, node.type.resolved(), edgeToConstraintNode(node.value))
doCast(function, edgeToConstraintNode(node.value), node.type.resolved()).addEdge(fieldNode)
constraintGraph.voidNode constraintGraph.voidNode
} }