Python: Fix bad join order in py/ineffectual-statement.

This used to take 30s on `cpython`.
```
Tuple counts for StatementNoEffect::side_effecting_binary#f:
46522     ~0%     {2} r1 = ClassObject::ClassObject::hasAttribute_dispred#fb AS L AND NOT StatementNoEffect::side_effecting_binary#f#antijoin_rhs AS R(L.<0>, L.<1>)
46522     ~2%     {2} r2 = SCAN r1 OUTPUT r1.<1>, r1.<0>
950960    ~2%     {2} r3 = JOIN r2 WITH Operations::Operator::getSpecialMethodName_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, r2.<1>
950960    ~2%     {2} r4 = JOIN r3 WITH py_operators AS R ON FIRST 1 OUTPUT R.<2>, r3.<1>
950960    ~0%     {3} r5 = JOIN r4 WITH AstGenerated::BinaryExpr_::getLeft_dispred#ff AS R ON FIRST 1 OUTPUT R.<1>, r4.<1>, r4.<0>
122934382 ~0%     {2} r6 = JOIN r2 WITH Operations::Cmpop::getSpecialMethodName_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, r2.<1>
122934382 ~3%     {3} r7 = JOIN r6 WITH project#Operations::Compare::compares_dispred#ffff#3_201#join_rhs AS R ON FIRST 1 OUTPUT R.<2>, r6.<1>, R.<1>
123885342 ~3%     {3} r8 = r5 \/ r7
300       ~8%     {1} r9 = JOIN r8 WITH project#Exprs::Expr::refersTo_dispred#ffff AS R ON FIRST 2 OUTPUT r8.<2>
                  return r9
```
With this commit, it takes a few milliseconds.
This commit is contained in:
Taus Brock-Nannestad
2019-12-11 11:13:08 +01:00
parent 3049bf2c85
commit d5cc42e34c

View File

@@ -49,28 +49,45 @@ predicate side_effecting_descriptor_type(ClassObject descriptor) {
* side-effecting unless we know otherwise.
*/
predicate side_effecting_binary(Expr b) {
exists(Expr sub, string method_name |
sub = b.(BinaryExpr).getLeft() and
method_name = b.(BinaryExpr).getOp().getSpecialMethodName()
exists(Expr sub, ClassObject cls, string method_name |
binary_operator_special_method(b, sub, cls, method_name)
or
exists(Cmpop op |
b.(Compare).compares(sub, op, _) and
method_name = op.getSpecialMethodName()
)
comparison_special_method(b, sub, cls, method_name)
|
exists(ClassObject cls |
sub.refersTo(_, cls, _) and
cls.hasAttribute(method_name)
and
not exists(ClassObject declaring |
declaring.declaresAttribute(method_name)
and declaring = cls.getAnImproperSuperType() and
declaring.isBuiltin() and not declaring = theObjectType()
)
method_name = special_method() and
cls.hasAttribute(method_name)
and
not exists(ClassObject declaring |
declaring.declaresAttribute(method_name)
and declaring = cls.getAnImproperSuperType() and
declaring.isBuiltin() and not declaring = theObjectType()
)
)
}
pragma[nomagic]
private predicate binary_operator_special_method(BinaryExpr b, Expr sub, ClassObject cls, string method_name) {
method_name = special_method() and
sub = b.getLeft() and
method_name = b.getOp().getSpecialMethodName() and
sub.refersTo(_, cls, _)
}
pragma[nomagic]
private predicate comparison_special_method(Compare b, Expr sub, ClassObject cls, string method_name) {
exists(Cmpop op |
b.compares(sub, op, _) and
method_name = op.getSpecialMethodName()
) and
sub.refersTo(_, cls, _)
}
private string special_method() {
result = any(Cmpop c).getSpecialMethodName()
or
result = any(BinaryExpr b).getOp().getSpecialMethodName()
}
predicate is_notebook(File f) {
exists(Comment c |
c.getLocation().getFile() = f |