Skip to content

Commit 1ed11b2

Browse files
authored
Merge pull request github#5725 from hvitved/csharp/dataflow/performance
C#: Various data-flow performance tweaks
2 parents ef0ea24 + dd1bb18 commit 1ed11b2

File tree

4 files changed

+68
-60
lines changed

4 files changed

+68
-60
lines changed

csharp/ql/src/semmle/code/csharp/Caching.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ module Stages {
4949

5050
cached
5151
module DataFlowStage {
52+
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
5253
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
5354
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
5455
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
@@ -78,6 +79,8 @@ module Stages {
7879
or
7980
exists(CallContext cc)
8081
or
82+
exists(any(DataFlowCall c).getEnclosingCallable())
83+
or
8184
forceCachingInSameStageRev()
8285
}
8386
}

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ private import dotnet
44
private import DataFlowPublic
55
private import DataFlowPrivate
66
private import FlowSummaryImpl as FlowSummaryImpl
7+
private import semmle.code.csharp.Caching
78
private import semmle.code.csharp.dataflow.FlowSummary
89
private import semmle.code.csharp.dispatch.Dispatch
910
private import semmle.code.csharp.frameworks.system.Collections
@@ -69,8 +70,6 @@ private predicate transitiveCapturedCallTarget(ControlFlow::Nodes::ElementNode c
6970

7071
cached
7172
private module Cached {
72-
private import semmle.code.csharp.Caching
73-
7473
cached
7574
newtype TReturnKind =
7675
TNormalReturnKind() { Stages::DataFlowStage::forceCachingInSameStage() } or
@@ -247,6 +246,7 @@ abstract class DataFlowCall extends TDataFlowCall {
247246
abstract DataFlow::Node getNode();
248247

249248
/** Gets the enclosing callable of this call. */
249+
cached
250250
abstract DataFlowCallable getEnclosingCallable();
251251

252252
/** Gets the underlying expression, if any. */
@@ -280,7 +280,10 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
280280

281281
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
282282

283-
override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
283+
override DataFlowCallable getEnclosingCallable() {
284+
Stages::DataFlowStage::forceCachingInSameStage() and
285+
result = cfn.getEnclosingCallable()
286+
}
284287

285288
override string toString() { result = cfn.toString() }
286289

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ private import semmle.code.csharp.frameworks.system.threading.Tasks
2121

2222
abstract class NodeImpl extends Node {
2323
/** Do not call: use `getEnclosingCallable()` instead. */
24+
cached
2425
abstract DataFlowCallable getEnclosingCallableImpl();
2526

2627
/** Do not call: use `getType()` instead. */
28+
cached
2729
abstract DotNet::Type getTypeImpl();
2830

2931
/** Gets the type of this node used for type pruning. */
@@ -39,27 +41,39 @@ abstract class NodeImpl extends Node {
3941
}
4042

4143
/** Do not call: use `getControlFlowNode()` instead. */
44+
cached
4245
abstract ControlFlow::Node getControlFlowNodeImpl();
4346

4447
/** Do not call: use `getLocation()` instead. */
48+
cached
4549
abstract Location getLocationImpl();
4650

4751
/** Do not call: use `toString()` instead. */
52+
cached
4853
abstract string toStringImpl();
4954
}
5055

5156
private class ExprNodeImpl extends ExprNode, NodeImpl {
5257
override DataFlowCallable getEnclosingCallableImpl() {
58+
Stages::DataFlowStage::forceCachingInSameStage() and
5359
result = this.getExpr().getEnclosingCallable()
5460
}
5561

56-
override DotNet::Type getTypeImpl() { result = this.getExpr().getType() }
62+
override DotNet::Type getTypeImpl() {
63+
Stages::DataFlowStage::forceCachingInSameStage() and
64+
result = this.getExpr().getType()
65+
}
5766

58-
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { this = TExprNode(result) }
67+
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() {
68+
Stages::DataFlowStage::forceCachingInSameStage() and this = TExprNode(result)
69+
}
5970

60-
override Location getLocationImpl() { result = this.getExpr().getLocation() }
71+
override Location getLocationImpl() {
72+
Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getLocation()
73+
}
6174

6275
override string toStringImpl() {
76+
Stages::DataFlowStage::forceCachingInSameStage() and
6377
result = this.getControlFlowNode().toString()
6478
or
6579
exists(CIL::Expr e |
@@ -967,6 +981,16 @@ private module Cached {
967981
or
968982
n.asExpr() = any(WithExpr we).getInitializer()
969983
}
984+
985+
cached
986+
predicate parameterNode(Node n, DataFlowCallable c, int i) {
987+
n.(ParameterNodeImpl).isParameterOf(c, i)
988+
}
989+
990+
cached
991+
predicate argumentNode(Node n, DataFlowCall call, int pos) {
992+
n.(ArgumentNodeImpl).argumentOf(call, pos)
993+
}
970994
}
971995

972996
import Cached
@@ -992,8 +1016,6 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
9921016
}
9931017

9941018
abstract class ParameterNodeImpl extends NodeImpl {
995-
abstract DotNet::Parameter getParameter();
996-
9971019
abstract predicate isParameterOf(DataFlowCallable c, int i);
9981020
}
9991021

@@ -1010,11 +1032,9 @@ private module ParameterNodes {
10101032
/** Gets the SSA definition corresponding to this parameter, if any. */
10111033
Ssa::ExplicitDefinition getSsaDefinition() {
10121034
result.getADefinition().(AssignableDefinitions::ImplicitParameterDefinition).getParameter() =
1013-
this.getParameter()
1035+
parameter
10141036
}
10151037

1016-
override DotNet::Parameter getParameter() { result = parameter }
1017-
10181038
override predicate isParameterOf(DataFlowCallable c, int i) { c.getParameter(i) = parameter }
10191039

10201040
override DataFlowCallable getEnclosingCallableImpl() { result = parameter.getCallable() }
@@ -1037,8 +1057,6 @@ private module ParameterNodes {
10371057
/** Gets the callable containing this implicit instance parameter. */
10381058
Callable getCallable() { result = callable }
10391059

1040-
override DotNet::Parameter getParameter() { none() }
1041-
10421060
override predicate isParameterOf(DataFlowCallable c, int pos) { callable = c and pos = -1 }
10431061

10441062
override DataFlowCallable getEnclosingCallableImpl() { result = callable }
@@ -1113,8 +1131,6 @@ private module ParameterNodes {
11131131
/** Gets the captured variable that this implicit parameter models. */
11141132
LocalScopeVariable getVariable() { result = def.getVariable() }
11151133

1116-
override DotNet::Parameter getParameter() { none() }
1117-
11181134
override predicate isParameterOf(DataFlowCallable c, int i) {
11191135
i = getParameterPosition(def) and
11201136
c = this.getEnclosingCallable()
@@ -1125,13 +1141,15 @@ private module ParameterNodes {
11251141
import ParameterNodes
11261142

11271143
/** A data-flow node that represents a call argument. */
1128-
abstract class ArgumentNode extends Node {
1144+
class ArgumentNode extends Node {
1145+
ArgumentNode() { argumentNode(this, _, _) }
1146+
11291147
/** Holds if this argument occurs at the given position in the given call. */
1130-
cached
1131-
abstract predicate argumentOf(DataFlowCall call, int pos);
1148+
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
1149+
}
11321150

1133-
/** Gets the call in which this node is an argument. */
1134-
final DataFlowCall getCall() { this.argumentOf(result, _) }
1151+
abstract private class ArgumentNodeImpl extends Node {
1152+
abstract predicate argumentOf(DataFlowCall call, int pos);
11351153
}
11361154

11371155
private module ArgumentNodes {
@@ -1149,15 +1167,14 @@ private module ArgumentNodes {
11491167
}
11501168

11511169
/** A data-flow node that represents an explicit call argument. */
1152-
class ExplicitArgumentNode extends ArgumentNode {
1170+
class ExplicitArgumentNode extends ArgumentNodeImpl {
11531171
ExplicitArgumentNode() {
11541172
this.asExpr() instanceof Argument
11551173
or
11561174
this.asExpr() = any(CIL::Call call).getAnArgument()
11571175
}
11581176

11591177
override predicate argumentOf(DataFlowCall call, int pos) {
1160-
Stages::DataFlowStage::forceCachingInSameStage() and
11611178
exists(ArgumentConfiguration x, Expr c, Argument arg |
11621179
arg = this.asExpr() and
11631180
c = call.getExpr() and
@@ -1189,7 +1206,8 @@ private module ArgumentNodes {
11891206
* } }
11901207
* ```
11911208
*/
1192-
class ImplicitCapturedArgumentNode extends ArgumentNode, NodeImpl, TImplicitCapturedArgumentNode {
1209+
class ImplicitCapturedArgumentNode extends ArgumentNodeImpl, NodeImpl,
1210+
TImplicitCapturedArgumentNode {
11931211
private LocalScopeVariable v;
11941212
private ControlFlow::Nodes::ElementNode cfn;
11951213

@@ -1231,7 +1249,7 @@ private module ArgumentNodes {
12311249
* A node that corresponds to the value of an object creation (`new C()`) before
12321250
* the constructor has run.
12331251
*/
1234-
class MallocNode extends ArgumentNode, NodeImpl, TMallocNode {
1252+
class MallocNode extends ArgumentNodeImpl, NodeImpl, TMallocNode {
12351253
private ControlFlow::Nodes::ElementNode cfn;
12361254

12371255
MallocNode() { this = TMallocNode(cfn) }
@@ -1266,7 +1284,7 @@ private module ArgumentNodes {
12661284
* and that argument is itself a compatible array, for example
12671285
* `Foo(new[] { "a", "b", "c" })`.
12681286
*/
1269-
class ParamsArgumentNode extends ArgumentNode, NodeImpl, TParamsArgumentNode {
1287+
class ParamsArgumentNode extends ArgumentNodeImpl, NodeImpl, TParamsArgumentNode {
12701288
private ControlFlow::Node callCfn;
12711289

12721290
ParamsArgumentNode() { this = TParamsArgumentNode(callCfn) }
@@ -1291,7 +1309,7 @@ private module ArgumentNodes {
12911309
override string toStringImpl() { result = "[implicit array creation] " + callCfn }
12921310
}
12931311

1294-
private class SummaryArgumentNode extends SummaryNode, ArgumentNode {
1312+
private class SummaryArgumentNode extends SummaryNode, ArgumentNodeImpl {
12951313
private DataFlowCall c;
12961314
private int i;
12971315

@@ -1324,10 +1342,7 @@ private module ReturnNodes {
13241342
)
13251343
}
13261344

1327-
override NormalReturnKind getKind() {
1328-
any(DotNet::Callable c).canReturn(this.getExpr()) and
1329-
exists(result)
1330-
}
1345+
override NormalReturnKind getKind() { exists(result) }
13311346
}
13321347

13331348
/**
@@ -1744,7 +1759,10 @@ class DataFlowType extends Gvn::GvnType {
17441759
}
17451760

17461761
/** Gets the type of `n` used for type pruning. */
1747-
DataFlowType getNodeType(NodeImpl n) { result = n.getDataFlowType() }
1762+
pragma[inline]
1763+
Gvn::GvnType getNodeType(NodeImpl n) {
1764+
pragma[only_bind_into](result) = pragma[only_bind_out](n).getDataFlowType()
1765+
}
17481766

17491767
/** Gets a string representation of a `DataFlowType`. */
17501768
string ppReprType(DataFlowType t) { result = t.toString() }
@@ -1819,7 +1837,8 @@ private module PostUpdateNodes {
18191837
* Such a node acts as both a post-update node for the `MallocNode`, as well as
18201838
* a pre-update node for the `ObjectCreationNode`.
18211839
*/
1822-
class ObjectInitializerNode extends PostUpdateNode, NodeImpl, ArgumentNode, TObjectInitializerNode {
1840+
class ObjectInitializerNode extends PostUpdateNode, NodeImpl, ArgumentNodeImpl,
1841+
TObjectInitializerNode {
18231842
private ObjectCreation oc;
18241843
private ControlFlow::Nodes::ElementNode cfn;
18251844

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ private import cil
33
private import dotnet
44
private import DataFlowDispatch
55
private import DataFlowPrivate
6-
private import semmle.code.csharp.Caching
76
private import semmle.code.csharp.controlflow.Guards
87
private import semmle.code.csharp.Unification
98

@@ -38,38 +37,21 @@ class Node extends TNode {
3837
}
3938

4039
/** Gets the type of this node. */
41-
cached
42-
final DotNet::Type getType() {
43-
Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl()
44-
}
40+
final DotNet::Type getType() { result = this.(NodeImpl).getTypeImpl() }
4541

4642
/** Gets the enclosing callable of this node. */
47-
cached
4843
final DataFlowCallable getEnclosingCallable() {
49-
Stages::DataFlowStage::forceCachingInSameStage() and
5044
result = this.(NodeImpl).getEnclosingCallableImpl()
5145
}
5246

5347
/** Gets the control flow node corresponding to this node, if any. */
54-
cached
55-
final ControlFlow::Node getControlFlowNode() {
56-
Stages::DataFlowStage::forceCachingInSameStage() and
57-
result = this.(NodeImpl).getControlFlowNodeImpl()
58-
}
48+
final ControlFlow::Node getControlFlowNode() { result = this.(NodeImpl).getControlFlowNodeImpl() }
5949

6050
/** Gets a textual representation of this node. */
61-
cached
62-
final string toString() {
63-
Stages::DataFlowStage::forceCachingInSameStage() and
64-
result = this.(NodeImpl).toStringImpl()
65-
}
51+
final string toString() { result = this.(NodeImpl).toStringImpl() }
6652

6753
/** Gets the location of this node. */
68-
cached
69-
final Location getLocation() {
70-
Stages::DataFlowStage::forceCachingInSameStage() and
71-
result = this.(NodeImpl).getLocationImpl()
72-
}
54+
final Location getLocation() { result = this.(NodeImpl).getLocationImpl() }
7355

7456
/**
7557
* Holds if this element is at the specified location.
@@ -81,7 +63,7 @@ class Node extends TNode {
8163
predicate hasLocationInfo(
8264
string filepath, int startline, int startcolumn, int endline, int endcolumn
8365
) {
84-
getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
66+
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
8567
}
8668
}
8769

@@ -117,18 +99,18 @@ class ExprNode extends Node {
11799
* flow graph.
118100
*/
119101
class ParameterNode extends Node {
120-
private ParameterNodeImpl p;
121-
122-
ParameterNode() { this = p }
102+
ParameterNode() { parameterNode(this, _, _) }
123103

124104
/** Gets the parameter corresponding to this node, if any. */
125-
DotNet::Parameter getParameter() { result = p.getParameter() }
105+
DotNet::Parameter getParameter() {
106+
exists(DataFlowCallable c, int i | this.isParameterOf(c, i) and result = c.getParameter(i))
107+
}
126108

127109
/**
128110
* Holds if this node is the parameter of callable `c` at the specified
129111
* (zero-based) position.
130112
*/
131-
predicate isParameterOf(DataFlowCallable c, int i) { p.isParameterOf(c, i) }
113+
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
132114
}
133115

134116
/** A definition, viewed as a node in a data flow graph. */
@@ -166,6 +148,7 @@ predicate localFlowStep = localFlowStepImpl/2;
166148
* Holds if data flows from `source` to `sink` in zero or more local
167149
* (intra-procedural) steps.
168150
*/
151+
pragma[inline]
169152
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
170153

171154
/**

0 commit comments

Comments
 (0)