Skip to content

Commit 2de892b

Browse files
committed
Python: Points-to performance improvements
1 parent a73cdf3 commit 2de892b

File tree

1 file changed

+64
-41
lines changed
  • python/ql/lib/semmle/python/pointsto

1 file changed

+64
-41
lines changed

python/ql/lib/semmle/python/pointsto/MRO.qll

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -114,39 +114,12 @@ class ClassList extends TClassList {
114114
this = Empty() and result = Empty()
115115
}
116116

117-
predicate legalMergeHead(ClassObjectInternal cls) {
118-
this.getTail().doesNotContain(cls)
119-
or
120-
this = Empty()
121-
}
122-
123117
predicate contains(ClassObjectInternal cls) {
124118
cls = this.getHead()
125119
or
126120
this.getTail().contains(cls)
127121
}
128122

129-
/** Use negative formulation to avoid negative recursion */
130-
predicate doesNotContain(ClassObjectInternal cls) {
131-
this.relevantForContains(cls) and
132-
cls != this.getHead() and
133-
this.getTail().doesNotContain(cls)
134-
or
135-
this = Empty()
136-
}
137-
138-
private predicate relevantForContains(ClassObjectInternal cls) {
139-
exists(ClassListList list |
140-
list.getItem(_).getHead() = cls and
141-
list.getItem(_) = this
142-
)
143-
or
144-
exists(ClassList l |
145-
l.relevantForContains(cls) and
146-
this = l.getTail()
147-
)
148-
}
149-
150123
ClassObjectInternal findDeclaringClass(string name) {
151124
exists(ClassDecl head | head = this.getHead().getClassDeclaration() |
152125
if head.declaresAttribute(name)
@@ -199,12 +172,18 @@ class ClassList extends TClassList {
199172
or
200173
this.duplicate(n) and result = this.deduplicate(n + 1)
201174
or
202-
exists(ClassObjectInternal cls |
203-
n = this.firstIndex(cls) and
204-
result = Cons(cls, this.deduplicate(n + 1))
175+
exists(ClassObjectInternal cls, ClassList tail |
176+
deduplicateCons(n, cls, tail) and
177+
result = Cons(cls, tail)
205178
)
206179
}
207180

181+
pragma[nomagic]
182+
private predicate deduplicateCons(int n, ClassObjectInternal cls, ClassList tail) {
183+
n = this.firstIndex(cls) and
184+
tail = this.deduplicate(n + 1)
185+
}
186+
208187
predicate isEmpty() { this = Empty() }
209188

210189
ClassList reverse() { reverse_step(this, Empty(), result) }
@@ -299,13 +278,23 @@ private class ClassListList extends TClassListList {
299278
removed_head = this.getItem(n).removeHead(cls) and
300279
removed_tail = EmptyList()
301280
or
281+
removed_head = this.removedClassPartsCons1(cls, removed_tail, n).removeHead(cls)
282+
}
283+
284+
pragma[noinline]
285+
predicate removedClassPartsCons0(ClassObjectInternal cls, ClassListList removed_tail, int n) {
302286
exists(ClassList prev_head, ClassListList prev_tail |
303287
this.removedClassParts(cls, prev_head, prev_tail, n + 1) and
304-
removed_head = this.getItem(n).removeHead(cls) and
305288
removed_tail = ConsList(prev_head, prev_tail)
306289
)
307290
}
308291

292+
pragma[noinline]
293+
ClassList removedClassPartsCons1(ClassObjectInternal cls, ClassListList removed_tail, int n) {
294+
removedClassPartsCons0(cls, removed_tail, n) and
295+
result = this.getItem(n)
296+
}
297+
309298
ClassListList remove(ClassObjectInternal cls) {
310299
exists(ClassList removed_head, ClassListList removed_tail |
311300
this.removedClassParts(cls, removed_head, removed_tail, 0) and
@@ -315,18 +304,34 @@ private class ClassListList extends TClassListList {
315304
this = EmptyList() and result = EmptyList()
316305
}
317306

318-
predicate legalMergeCandidate(ClassObjectInternal cls, int n) {
307+
pragma[nomagic]
308+
private predicate legalMergeCandidateNonEmpty(ClassObjectInternal cls, int n, ClassList cl, int j) {
309+
this.legalMergeCandidate(cls, n + 1) and
310+
cl = this.getItem(n) and
311+
j = cl.length()
312+
or
313+
legalMergeCandidateNonEmpty(cls, n, cl, j + 1) and
314+
j >= 1 and
315+
cls != cl.getItem(j)
316+
}
317+
318+
private predicate legalMergeCandidate(ClassObjectInternal cls, int n) {
319319
cls = this.getAHead() and n = this.length()
320320
or
321-
this.getItem(n).legalMergeHead(cls) and
322-
this.legalMergeCandidate(cls, n + 1)
321+
this.legalMergeCandidate(cls, n + 1) and
322+
this.getItem(n) = Empty()
323+
or
324+
legalMergeCandidateNonEmpty(cls, n, _, 1)
323325
}
324326

325327
predicate legalMergeCandidate(ClassObjectInternal cls) { this.legalMergeCandidate(cls, 0) }
326328

327329
predicate illegalMergeCandidate(ClassObjectInternal cls) {
328-
cls = this.getAHead() and
329-
this.getItem(_).getTail().contains(cls)
330+
exists(ClassList cl, int j |
331+
legalMergeCandidateNonEmpty(cls, _, cl, j + 1) and
332+
j >= 1 and
333+
cls = cl.getItem(j)
334+
)
330335
}
331336

332337
ClassObjectInternal bestMergeCandidate(int n) {
@@ -417,14 +422,25 @@ private predicate merge_step(
417422
remaining_list = original
418423
or
419424
/* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
420-
exists(ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList prev_list |
425+
exists(ClassObjectInternal head, ClassList prev_reverse_mro |
426+
merge_stepCons(head, prev_reverse_mro, remaining_list, original) and
427+
reversed_mro = Cons(head, prev_reverse_mro)
428+
)
429+
or
430+
merge_step(reversed_mro, ConsList(Empty(), remaining_list), original)
431+
}
432+
433+
pragma[nomagic]
434+
private predicate merge_stepCons(
435+
ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList remaining_list,
436+
ClassListList original
437+
) {
438+
/* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
439+
exists(ClassListList prev_list |
421440
merge_step(prev_reverse_mro, prev_list, original) and
422441
head = prev_list.bestMergeCandidate() and
423-
reversed_mro = Cons(head, prev_reverse_mro) and
424442
remaining_list = prev_list.remove(head)
425443
)
426-
or
427-
merge_step(reversed_mro, ConsList(Empty(), remaining_list), original)
428444
}
429445

430446
/* Helpers for `ClassList.reverse()` */
@@ -439,10 +455,17 @@ private predicate reverse_step(ClassList lst, ClassList remainder, ClassList rev
439455
or
440456
exists(ClassObjectInternal head, ClassList tail |
441457
reversed = Cons(head, tail) and
442-
reverse_step(lst, Cons(head, remainder), tail)
458+
reverse_stepCons(lst, remainder, head, tail)
443459
)
444460
}
445461

462+
pragma[nomagic]
463+
private predicate reverse_stepCons(
464+
ClassList lst, ClassList remainder, ClassObjectInternal head, ClassList tail
465+
) {
466+
reverse_step(lst, Cons(head, remainder), tail)
467+
}
468+
446469
module Mro {
447470
cached
448471
ClassList newStyleMro(ClassObjectInternal cls) {

0 commit comments

Comments
 (0)