Python points-to: Improve performance.

This commit is contained in:
Mark Shannon
2019-05-13 17:15:01 +01:00
parent 972ac0fdbd
commit a03e101e4f
2 changed files with 67 additions and 62 deletions

View File

@@ -1014,6 +1014,18 @@ class BasicBlock extends @py_flow_node {
result = this.getLastNode().getAFalseSuccessor().getBasicBlock()
}
/** Gets an exceptional successor to this basic block */
BasicBlock getAnUnconditionalSuccessor() {
result = this.getASuccessor() and
not result = this.getATrueSuccessor() and
not result = this.getAFalseSuccessor()
}
/** Gets an exceptional successor to this basic block */
BasicBlock getAnExceptionalSuccessor() {
result = this.getLastNode().getAnExceptionalSuccessor().getBasicBlock()
}
/** Gets the scope of this block */
pragma [nomagic] Scope getScope() {
exists(ControlFlowNode n |

View File

@@ -214,46 +214,31 @@ cached module PointsToInternal {
/* Holds if BasicBlock `b` is reachable, given the context `context`. */
cached predicate reachableBlock(BasicBlock b, PointsToContext context) {
context.appliesToScope(b.getScope()) and not exists(ConditionBlock guard | guard.controls(b, _))
exists(Scope scope |
context.appliesToScope(scope) and
scope.getEntryNode().getBasicBlock() = b
)
or
exists(ConditionBlock guard |
guard = b.getImmediatelyControllingBlock() and
reachableBlock(guard, context)
|
allowsFlow(guard, b, context)
reachableEdge(_, b, context)
}
private predicate reachableEdge(BasicBlock pred, BasicBlock succ, PointsToContext context) {
reachableBlock(pred, context) and
(
pred.getAnUnconditionalSuccessor() = succ
or
/* Assume the true edge of an assert is reachable (except for assert 0/False) */
guard.controls(b, true) and
exists(Assert a, Expr test |
a.getTest() = test and
guard.getLastNode().getNode() = test and
not test instanceof ImmutableLiteral
exists(ObjectInternal value, boolean sense, ControlFlowNode test |
test = pred.getLastNode() and
pointsTo(test, context, value, _) and
sense = value.booleanValue()
|
sense = true and succ = pred.getATrueSuccessor()
or
sense = false and succ = pred.getAFalseSuccessor()
)
)
}
pragma [noopt]
private predicate allowsFlow(ConditionBlock guard, BasicBlock b, PointsToContext context) {
exists(ObjectInternal value, boolean sense, ControlFlowNode test |
test = guard.getLastNode() and
pointsTo(test, context, value, _) and
sense = value.booleanValue() and
guard.controls(b, sense)
)
}
/* Holds if the edge `pred` -> `succ` is reachable, given the context `context`.
*/
pragma [noopt]
cached predicate controlledReachableEdge(BasicBlock pred, BasicBlock succ, PointsToContext context) {
exists(ConditionBlock guard, ObjectInternal value, boolean sense, ControlFlowNode test |
test = guard.getLastNode() and
pointsTo(test, context, value, _) and
sense = value.booleanValue() and
guard.controlsEdge(pred, succ, sense)
)
}
/** Gets an object pointed to by a use (of a variable). */
pragma [noinline]
private predicate use_points_to(NameNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
@@ -519,13 +504,18 @@ cached module PointsToInternal {
/** Holds if the phi-function `phi` refers to `(value, origin)` given the context `context`. */
pragma [nomagic]
private predicate ssa_phi_points_to(PhiFunction phi, PointsToContext context, ObjectInternal value, CfgOrigin origin) {
exists(EssaVariable input, BasicBlock pred |
input = phi.getInput(pred) and
exists(EssaVariable input |
ssa_phi_reachable_from_input(phi, context, input) and
variablePointsTo(input, context, value, origin)
|
controlledReachableEdge(pred, phi.getBasicBlock(), context)
or
not exists(ConditionBlock guard | guard.controlsEdge(pred, phi.getBasicBlock(), _))
)
}
/* Helper for ssa_phi_points_to */
pragma [noinline]
private predicate ssa_phi_reachable_from_input(PhiFunction phi, PointsToContext context, EssaVariable input) {
exists(BasicBlock pred |
input = phi.getInput(pred) and
reachableEdge(pred, phi.getBasicBlock(), context)
)
}
@@ -839,9 +829,7 @@ module InterProceduralPointsTo {
predicate parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
self_parameter_points_to(def, context, value, origin)
or
positional_parameter_points_to(def, context, value, origin)
or
named_parameter_points_to(def, context, value, origin)
normal_parameter_points_to(def, context, value, origin)
or
default_parameter_points_to(def, context, value, origin)
or
@@ -850,7 +838,7 @@ module InterProceduralPointsTo {
/** Helper for `parameter_points_to` */
pragma [noinline]
private predicate positional_parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
private predicate normal_parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
exists(PointsToContext caller, ControlFlowNode arg |
PointsToInternal::pointsTo(arg, caller, value, origin) and
callsite_argument_transfer(arg, caller, def, context)
@@ -882,16 +870,6 @@ module InterProceduralPointsTo {
)
}
/** Helper for `parameter_points_to` */
pragma [noinline]
private predicate named_parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
exists(CallNode call, PointsToContext caller, PythonFunctionObjectInternal func, string name |
context.fromCall(call, func, caller) and
def.getParameter() = func.getScope().getArgByName(name) and
PointsToInternal::pointsTo(call.getArgByName(name), caller, value, origin)
)
}
/** Helper for parameter_points_to */
pragma [noinline]
private predicate default_parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
@@ -939,10 +917,18 @@ module InterProceduralPointsTo {
/** Holds if the `(argument, caller)` pair matches up with `(param, callee)` pair across call. */
cached predicate callsite_argument_transfer(ControlFlowNode argument, PointsToContext caller, ParameterDefinition param, PointsToContext callee) {
exists(CallNode call, Function func, int n, int offset |
callsite_calls_function(call, caller, func, callee, offset) and
argument = call.getArg(n) and
param.getParameter() = func.getArg(n+offset)
exists(CallNode call, Function func, int offset |
callsite_calls_function(call, caller, func, callee, offset)
|
exists(int n |
argument = call.getArg(n) and
param.getParameter() = func.getArg(n+offset)
)
or
exists(string name |
argument = call.getArgByName(name) and
param.getParameter() = func.getArgByName(name)
)
)
}
@@ -1334,6 +1320,7 @@ module Expressions {
val.strValue() = other.strValue() and result = 1
}
pragma [nomagic]
private int compare_sequence(SequenceObjectInternal val, SequenceObjectInternal other, int n) {
inequalityTest(_, _, _, val, other, _, _) and
(
@@ -1342,11 +1329,17 @@ module Expressions {
n = other.length() and val.length() > n and result = 1
or
n = other.length() and n = val.length() and result = 0
or
result != 0 and result = compare_unbound(val.getItem(n), other.getItem(n))
or
compare_unbound(val.getItem(n), other.getItem(n)) = 0 and result = compare_sequence(val, other, n+1)
)
or
result != 0 and result = compare_item(val, other, n)
or
compare_item(val, other, n) = 0 and result = compare_sequence(val, other, n+1)
}
pragma [noinline]
private int compare_item(SequenceObjectInternal val, SequenceObjectInternal other, int n) {
inequalityTest(_, _, _, val, other, _, _) and
result = compare_unbound(val.getItem(n), other.getItem(n))
}
pragma [noinline]