Merge pull request #16010 from RasmusWL/perf

Python: Two small join-order fixes
This commit is contained in:
Rasmus Wriedt Larsen
2024-03-22 11:36:17 +01:00
committed by GitHub
2 changed files with 29 additions and 13 deletions

View File

@@ -876,7 +876,7 @@ private module TrackAttrReadInput implements CallGraphConstruction::Simple::Inpu
predicate start(Node start, AttrRead attr) {
start = attr and
attr.getObject() in [
pragma[only_bind_into](attr.getObject()) in [
classTracker(_), classInstanceTracker(_), selfTracker(_), clsArgumentTracker(_),
superCallNoArgumentTracker(_), superCallTwoArgumentTracker(_, _)
]
@@ -1302,9 +1302,7 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar
//
// call_func(my_obj.some_method)
// ```
exists(CfgNode cfgNode | cfgNode.getNode() = call |
cfgNode.getEnclosingCallable() = arg.getEnclosingCallable()
)
exists(CfgNode cfgNode | cfgNode.getNode() = call | sameEnclosingCallable(cfgNode, arg))
or
// cls argument for classmethod calls -- see note above about bound methods
type instanceof CallTypeClassMethod and
@@ -1312,9 +1310,7 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar
resolveMethodCall(call, target, type, arg) and
(arg = classTracker(_) or arg = clsArgumentTracker(_)) and
// dataflow lib has requirement that arguments and calls are in same enclosing callable.
exists(CfgNode cfgNode | cfgNode.getNode() = call |
cfgNode.getEnclosingCallable() = arg.getEnclosingCallable()
)
exists(CfgNode cfgNode | cfgNode.getNode() = call | sameEnclosingCallable(cfgNode, arg))
or
// normal arguments for method calls
(
@@ -1365,6 +1361,16 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar
)
}
/**
* join-order helper for getCallArg, since otherwise we would do cartesian product of
* the enclosing callables
*/
bindingset[node1, node2]
pragma[inline_late]
private predicate sameEnclosingCallable(Node node1, Node node2) {
node1.getEnclosingCallable() = node2.getEnclosingCallable()
}
// =============================================================================
// DataFlowCall
// =============================================================================

View File

@@ -113,15 +113,25 @@ module SqlAlchemy {
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
/**
* join-ordering helper for ConnectionConstruction char-pred -- without this would
* start with _all_ `CallCfgNode` and join those with `MethodCallNode` .. which is
* silly
*/
pragma[noinline]
private DataFlow::MethodCallNode connectionConstruction_helper() {
result.calls(Engine::instance(), ["begin", "connect"])
or
result.calls(instance(), ["connect", "execution_options"])
}
private class ConnectionConstruction extends InstanceSource, DataFlow::CallCfgNode {
ConnectionConstruction() {
this = classRef().getACall()
// without the `pragma[only_bind_out]` we would start with joining
// `API::Node.getACall` with `CallCfgNode` which is not optimal
this = pragma[only_bind_out](classRef()).getACall()
or
this.(DataFlow::MethodCallNode).calls(Engine::instance(), ["begin", "connect"])
or
this.(DataFlow::MethodCallNode).calls(instance(), "connect")
or
this.(DataFlow::MethodCallNode).calls(instance(), "execution_options")
this = connectionConstruction_helper()
}
}