Skip to content

Commit 5771b04

Browse files
authored
Merge pull request github#5936 from hvitved/csharp/cfg/perf-tweaks
C#: Various CFG related performance tweaks
2 parents 2261085 + b55bce4 commit 5771b04

File tree

9 files changed

+80
-81
lines changed

9 files changed

+80
-81
lines changed

csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ private module JoinBlockPredecessors {
403403
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
404404

405405
int getId(JoinBlockPredecessor jbp) {
406-
exists(ControlFlowTree::Range t | ControlFlowTree::idOf(t, result) |
406+
exists(ControlFlowTree::Range_ t | ControlFlowTree::idOf(t, result) |
407407
t = jbp.getFirstNode().getElement()
408408
or
409409
t = jbp.(EntryBasicBlock).getCallable()

csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import csharp
44
private import semmle.code.csharp.ExprOrStmtParent
5+
private import semmle.code.csharp.commons.Compilation
56
private import ControlFlow
67
private import ControlFlow::BasicBlocks
78
private import SuccessorTypes
@@ -22,7 +23,12 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
2223
Callable getEnclosingCallable() { none() }
2324

2425
/** Gets the assembly that this element was compiled into. */
25-
Assembly getAssembly() { result = this.getEnclosingCallable().getDeclaringType().getALocation() }
26+
Assembly getAssembly() {
27+
exists(Compilation c |
28+
c.getAFileCompiled() = this.getFile() and
29+
result = c.getOutputAssembly()
30+
)
31+
}
2632

2733
/**
2834
* Gets a control flow node for this element. That is, a node in the

csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,8 +1466,10 @@ module Internal {
14661466
PreSsa::Definition def, AssignableRead read
14671467
) {
14681468
read = def.getAFirstRead() and
1469-
not exists(AssignableRead other | PreSsa::adjacentReadPairSameVar(other, read) |
1470-
other != read
1469+
(
1470+
not PreSsa::adjacentReadPairSameVar(_, read)
1471+
or
1472+
read = unique(AssignableRead read0 | PreSsa::adjacentReadPairSameVar(read0, read))
14711473
)
14721474
}
14731475

@@ -1651,10 +1653,14 @@ module Internal {
16511653
AssignableRead read1, AssignableRead read2
16521654
) {
16531655
PreSsa::adjacentReadPairSameVar(read1, read2) and
1654-
not exists(AssignableRead other |
1655-
PreSsa::adjacentReadPairSameVar(other, read2) and
1656-
other != read1 and
1657-
other != read2
1656+
(
1657+
read1 = read2 and
1658+
read1 = unique(AssignableRead other | PreSsa::adjacentReadPairSameVar(other, read2))
1659+
or
1660+
read1 =
1661+
unique(AssignableRead other |
1662+
PreSsa::adjacentReadPairSameVar(other, read2) and other != read2
1663+
)
16581664
)
16591665
}
16601666

@@ -1887,10 +1893,14 @@ module Internal {
18871893
Ssa::Definition def, ControlFlow::Node cfn1, ControlFlow::Node cfn2
18881894
) {
18891895
SsaImpl::adjacentReadPairSameVar(def, cfn1, cfn2) and
1890-
not exists(ControlFlow::Node other |
1891-
SsaImpl::adjacentReadPairSameVar(def, other, cfn2) and
1892-
other != cfn1 and
1893-
other != cfn2
1896+
(
1897+
cfn1 = cfn2 and
1898+
cfn1 = unique(ControlFlow::Node other | SsaImpl::adjacentReadPairSameVar(def, other, cfn2))
1899+
or
1900+
cfn1 =
1901+
unique(ControlFlow::Node other |
1902+
SsaImpl::adjacentReadPairSameVar(def, other, cfn2) and other != cfn2
1903+
)
18941904
)
18951905
}
18961906

csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll

Lines changed: 1 addition & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -293,18 +293,6 @@ private class Overflowable extends UnaryOperation {
293293
}
294294
}
295295

296-
private class CoreLib extends Assembly {
297-
CoreLib() { this = any(SystemExceptionClass c).getALocation() }
298-
}
299-
300-
/**
301-
* Holds if assembly `a` was definitely compiled with core library `core`.
302-
*/
303-
pragma[noinline]
304-
private predicate assemblyCompiledWithCoreLib(Assembly a, CoreLib core) {
305-
a.getAnAttribute().getType().getBaseClass*().(SystemAttributeClass).getALocation() = core
306-
}
307-
308296
/** A control flow element that is inside a `try` block. */
309297
private class TriedControlFlowElement extends ControlFlowElement {
310298
TryStmt try;
@@ -317,7 +305,7 @@ private class TriedControlFlowElement extends ControlFlowElement {
317305
/**
318306
* Gets an exception class that is potentially thrown by this element, if any.
319307
*/
320-
private Class getAThrownException0() {
308+
Class getAThrownException() {
321309
this instanceof Overflowable and
322310
result instanceof SystemOverflowExceptionClass
323311
or
@@ -376,41 +364,6 @@ private class TriedControlFlowElement extends ControlFlowElement {
376364
this instanceof DynamicExpr and
377365
result instanceof SystemExceptionClass
378366
}
379-
380-
private CoreLib getCoreLibFromACatchClause() {
381-
exists(SpecificCatchClause scc | scc = try.getACatchClause() |
382-
result = scc.getCaughtExceptionType().getBaseClass*().(SystemExceptionClass).getALocation()
383-
)
384-
}
385-
386-
private CoreLib getCoreLib() {
387-
result = this.getCoreLibFromACatchClause()
388-
or
389-
not exists(this.getCoreLibFromACatchClause()) and
390-
assemblyCompiledWithCoreLib(this.getAssembly(), result)
391-
}
392-
393-
pragma[noinline]
394-
private Class getAThrownExceptionFromPlausibleCoreLib(string name) {
395-
result = this.getAThrownException0() and
396-
name = result.getQualifiedName() and
397-
(
398-
not exists(this.getCoreLib())
399-
or
400-
this.getCoreLib() = result.getALocation()
401-
)
402-
}
403-
404-
Class getAThrownException() {
405-
exists(string name | result = this.getAThrownExceptionFromPlausibleCoreLib(name) |
406-
result =
407-
min(Class c |
408-
c = this.getAThrownExceptionFromPlausibleCoreLib(name)
409-
|
410-
c order by c.getLocation().(Assembly).getFullName()
411-
)
412-
)
413-
}
414367
}
415368

416369
pragma[nomagic]

csharp/ql/src/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class CfgScope extends Element, @top_level_exprorstmt_parent {
7777
}
7878

7979
module ControlFlowTree {
80-
private class Range_ = @callable or @control_flow_element;
80+
class Range_ = @callable or @control_flow_element;
8181

8282
class Range extends Element, Range_ {
8383
Range() { this = getAChild*(any(CfgScope scope)) }
@@ -88,9 +88,9 @@ module ControlFlowTree {
8888
result = p.(AssignOperation).getExpandedAssignment()
8989
}
9090

91-
private predicate id(Range x, Range y) { x = y }
91+
private predicate id(Range_ x, Range_ y) { x = y }
9292

93-
predicate idOf(Range x, int y) = equivalenceRelation(id/2)(x, y)
93+
predicate idOf(Range_ x, int y) = equivalenceRelation(id/2)(x, y)
9494
}
9595

9696
abstract private class ControlFlowTree extends ControlFlowTree::Range {

csharp/ql/src/semmle/code/csharp/controlflow/internal/NonReturning.qll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ private class ThrowingCall extends NonReturningCall {
3939
or
4040
this.(FailingAssertion).getAssertionFailure().isException(c.getExceptionClass())
4141
or
42-
exists(CIL::Method m, CIL::Type ex |
43-
this.getTarget().matchesHandle(m) and
42+
exists(Callable target, CIL::Method m, CIL::Type ex |
43+
target = this.getTarget() and
44+
not target.hasBody() and
45+
target.matchesHandle(m) and
4446
alwaysThrowsException(m, ex) and
4547
c.getExceptionClass().matchesHandle(ex) and
4648
not m.isVirtual()

csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,13 @@ abstract class SplitImpl extends Split {
209209
or
210210
exists(ControlFlowElement pred | this.appliesTo(pred) | this.hasSuccessor(pred, cfe, _))
211211
}
212+
213+
/** The `succ` relation restricted to predecessors `pred` that this split applies to. */
214+
pragma[noinline]
215+
final predicate appliesSucc(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
216+
this.appliesTo(pred) and
217+
succ(pred, succ, c)
218+
}
212219
}
213220

214221
module InitializerSplitting {
@@ -382,8 +389,7 @@ module InitializerSplitting {
382389
}
383390

384391
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
385-
this.appliesTo(pred) and
386-
succ(pred, succ, c) and
392+
this.appliesSucc(pred, succ, c) and
387393
succ =
388394
any(InitializedInstanceMember m |
389395
constructorInitializes(this.getConstructor(), m.getInitializer())
@@ -620,8 +626,7 @@ module AssertionSplitting {
620626
}
621627

622628
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
623-
this.appliesTo(pred) and
624-
succ(pred, succ, c) and
629+
this.appliesSucc(pred, succ, c) and
625630
succ = getAnAssertionDescendant(a)
626631
}
627632
}
@@ -858,8 +863,7 @@ module FinallySplitting {
858863
}
859864

860865
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
861-
this.appliesToPredecessor(pred) and
862-
succ(pred, succ, c) and
866+
this.appliesSucc(pred, succ, c) and
863867
succ =
864868
any(FinallyControlFlowElement fcfe |
865869
if fcfe.isEntryNode()
@@ -1037,7 +1041,7 @@ module ExceptionHandlerSplitting {
10371041

10381042
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
10391043
this.appliesToPredecessor(pred, c) and
1040-
succ(pred, succ, c) and
1044+
this.appliesSucc(pred, succ, c) and
10411045
not first(any(SpecificCatchClause scc).getBlock(), succ) and
10421046
not succ instanceof GeneralCatchClause and
10431047
not exists(TryStmt ts, SpecificCatchClause scc, int last |
@@ -1298,7 +1302,7 @@ module BooleanSplitting {
12981302
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
12991303
exists(PreBasicBlock bb, Completion c0 | this.appliesToBlock(bb, c0) |
13001304
pred = bb.getAnElement() and
1301-
succ(pred, succ, c) and
1305+
this.appliesSucc(pred, succ, c) and
13021306
(
13031307
pred = bb.getLastElement()
13041308
implies
@@ -1489,7 +1493,7 @@ module LoopSplitting {
14891493

14901494
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
14911495
this.appliesToPredecessor(pred, c) and
1492-
succ(pred, succ, c) and
1496+
this.appliesSucc(pred, succ, c) and
14931497
not loop.stop(pred, succ, c)
14941498
}
14951499
}

csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplSpecific.qll

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,37 @@ class ExitBasicBlock extends BasicBlock {
1515
ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) }
1616
}
1717

18-
pragma[noinline]
18+
/** Holds if `a` is assigned in non-constructor callable `c`. */
19+
pragma[nomagic]
20+
private predicate assignableDefinition(Assignable a, Callable c) {
21+
exists(AssignableDefinition def | def.getTarget() = a |
22+
c = def.getEnclosingCallable() and
23+
not c instanceof Constructor
24+
)
25+
}
26+
27+
/** Holds if `a` is accessed in callable `c`. */
28+
pragma[nomagic]
29+
private predicate assignableAccess(Assignable a, Callable c) {
30+
exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable())
31+
}
32+
33+
pragma[nomagic]
1934
private predicate assignableNoCapturing(Assignable a, Callable c) {
20-
exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable()) and
21-
forall(AssignableDefinition def | def.getTarget() = a |
22-
c = def.getEnclosingCallable()
35+
assignableAccess(a, c) and
36+
/*
37+
* The code below is equivalent to
38+
* ```ql
39+
* not exists(Callable other | assignableDefinition(a, other) | other != c)
40+
* ```
41+
* but it avoids a Cartesian product in the compiler generated antijoin
42+
* predicate.
43+
*/
44+
45+
(
46+
not assignableDefinition(a, _)
2347
or
24-
def.getEnclosingCallable() instanceof Constructor
48+
c = unique(Callable c0 | assignableDefinition(a, c0) | c0)
2549
)
2650
}
2751

@@ -41,7 +65,7 @@ class SourceVariable extends Assignable {
4165
(
4266
this instanceof LocalScopeVariable
4367
or
44-
this instanceof Field
68+
this = any(Field f | not f.isVolatile())
4569
or
4670
this = any(TrivialProperty tp | not tp.isOverridableOrImplementable())
4771
) and

csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ module Private {
4949
}
5050

5151
int getId(PhiInputEdgeBlock bb) {
52-
exists(CfgImpl::ControlFlowTree::Range t | CfgImpl::ControlFlowTree::idOf(t, result) |
52+
exists(CfgImpl::ControlFlowTree::Range_ t | CfgImpl::ControlFlowTree::idOf(t, result) |
5353
t = bb.getFirstNode().getElement()
5454
or
5555
t = bb.(CS::ControlFlow::BasicBlocks::EntryBlock).getCallable()

0 commit comments

Comments
 (0)