Skip to content

Commit b2419d6

Browse files
authored
Merge pull request #7090 from hvitved/ruby/perf
Ruby: Cache more predicates
2 parents 143d64c + 3b5267e commit b2419d6

File tree

6 files changed

+43
-30
lines changed

6 files changed

+43
-30
lines changed

ruby/ql/lib/codeql/ruby/ast/Erb.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ class ErbDirective extends TDirectiveNode, ErbAstNode {
157157
* Gets a statement that starts in directive that is not a child of any other
158158
* statement starting in this directive.
159159
*/
160+
cached
160161
Stmt getAChildStmt() {
161162
this.containsAstNodeStart(result) and
162163
not this.containsAstNodeStart(result.getParent())

ruby/ql/lib/codeql/ruby/controlflow/BasicBlocks.qll

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,17 @@ private module Cached {
309309
jbp order by JoinBlockPredecessors::getId(jbp), JoinBlockPredecessors::getSplitString(jbp)
310310
)
311311
}
312+
313+
cached
314+
predicate immediatelyControls(ConditionBlock cb, BasicBlock succ, BooleanSuccessor s) {
315+
succ = cb.getASuccessor(s) and
316+
forall(BasicBlock pred | pred = succ.getAPredecessor() and pred != cb | succ.dominates(pred))
317+
}
318+
319+
cached
320+
predicate controls(ConditionBlock cb, BasicBlock controlled, BooleanSuccessor s) {
321+
exists(BasicBlock succ | cb.immediatelyControls(succ, s) | succ.dominates(controlled))
322+
}
312323
}
313324

314325
private import Cached
@@ -395,18 +406,14 @@ class ConditionBlock extends BasicBlock {
395406
* successor of this block, and `succ` can only be reached from
396407
* the callable entry point by going via the `s` edge out of this basic block.
397408
*/
398-
pragma[nomagic]
399409
predicate immediatelyControls(BasicBlock succ, BooleanSuccessor s) {
400-
succ = this.getASuccessor(s) and
401-
forall(BasicBlock pred | pred = succ.getAPredecessor() and pred != this | succ.dominates(pred))
410+
immediatelyControls(this, succ, s)
402411
}
403412

404413
/**
405414
* Holds if basic block `controlled` is controlled by this basic block with
406415
* conditional value `s`. That is, `controlled` can only be reached from
407416
* the callable entry point by going via the `s` edge out of this basic block.
408417
*/
409-
predicate controls(BasicBlock controlled, BooleanSuccessor s) {
410-
exists(BasicBlock succ | this.immediatelyControls(succ, s) | succ.dominates(controlled))
411-
}
418+
predicate controls(BasicBlock controlled, BooleanSuccessor s) { controls(this, controlled, s) }
412419
}

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -463,18 +463,7 @@ predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) { non
463463
*/
464464
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() }
465465

466-
/**
467-
* Holds if `e` is an `ExprNode` that may be returned by a call to `c`.
468-
*/
469-
predicate exprNodeReturnedFrom(DataFlow::ExprNode e, Callable c) {
470-
exists(ReturningNode r |
471-
nodeGetEnclosingCallable(r).asCallable() = c and
472-
(
473-
r.(ExplicitReturnNode).getReturningNode().getReturnedValueNode() = e.asExpr() or
474-
r.(ExprReturnNode) = e
475-
)
476-
)
477-
}
466+
predicate exprNodeReturnedFrom = exprNodeReturnedFromCached/2;
478467

479468
/** A parameter position. */
480469
class ParameterPosition extends TParameterPosition {

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,20 @@ private module Cached {
297297
TKnownArrayElementContent(int i) { i in [0 .. 10] } or
298298
TUnknownArrayElementContent() or
299299
TAnyArrayElementContent()
300+
301+
/**
302+
* Holds if `e` is an `ExprNode` that may be returned by a call to `c`.
303+
*/
304+
cached
305+
predicate exprNodeReturnedFromCached(ExprNode e, Callable c) {
306+
exists(ReturningNode r |
307+
nodeGetEnclosingCallable(r).asCallable() = c and
308+
(
309+
r.(ExplicitReturnNode).getReturningNode().getReturnedValueNode() = e.asExpr() or
310+
r.(ExprReturnNode) = e
311+
)
312+
)
313+
}
300314
}
301315

302316
class TArrayElementContent = TKnownArrayElementContent or TUnknownArrayElementContent;

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ class Node extends TNode {
1818
Parameter asParameter() { result = this.(ParameterNode).getParameter() }
1919

2020
/** Gets a textual representation of this node. */
21-
// TODO: cache
21+
cached
2222
final string toString() { result = this.(NodeImpl).toStringImpl() }
2323

2424
/** Gets the location of this node. */
25-
// TODO: cache
25+
cached
2626
final Location getLocation() { result = this.(NodeImpl).getLocationImpl() }
2727

2828
/**
@@ -121,7 +121,8 @@ class LocalSourceNode extends Node {
121121
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) }
122122
}
123123

124-
predicate hasLocalSource(Node sink, Node source) {
124+
cached
125+
private predicate hasLocalSource(Node sink, Node source) {
125126
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
126127
// recursive case, so instead we check it explicitly here.
127128
source = sink and

ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,6 @@ private predicate hasCapturedVariableRead(BasicBlock bb, LocalVariable v) {
2020
)
2121
}
2222

23-
/**
24-
* Holds if an entry definition is needed for captured variable `v` at index
25-
* `i` in entry block `bb`.
26-
*/
27-
predicate capturedEntryWrite(EntryBasicBlock bb, int i, LocalVariable v) {
28-
hasCapturedVariableRead(bb.getASuccessor*(), v) and
29-
i = -1
30-
}
31-
3223
/** Holds if `bb` contains a caputured write to variable `v`. */
3324
pragma[noinline]
3425
private predicate writesCapturedVariable(BasicBlock bb, LocalVariable v) {
@@ -132,6 +123,16 @@ private predicate hasVariableReadWithCapturedWrite(BasicBlock bb, LocalVariable
132123

133124
cached
134125
private module Cached {
126+
/**
127+
* Holds if an entry definition is needed for captured variable `v` at index
128+
* `i` in entry block `bb`.
129+
*/
130+
cached
131+
predicate capturedEntryWrite(EntryBasicBlock bb, int i, LocalVariable v) {
132+
hasCapturedVariableRead(bb.getASuccessor*(), v) and
133+
i = -1
134+
}
135+
135136
/**
136137
* Holds if the call at index `i` in basic block `bb` may reach a callable
137138
* that writes captured variable `v`.

0 commit comments

Comments
 (0)