@@ -269,30 +269,41 @@ private module Cached {
269
269
result .getAnAccess ( ) = upd .( UnaryAssignExpr ) .getExpr ( )
270
270
}
271
271
272
- /**
273
- * Holds if `f` is a field that is interesting as a basis for SSA.
274
- *
275
- * - A field that is read twice is interesting as we want to know whether the
276
- * reads refer to the same value.
277
- * - A field that is both written and read is interesting as we want to know
278
- * whether the read might get the written value.
279
- * - A field that is read in a loop is interesting as we want to know whether
280
- * the value is the same in different iterations (that is, whether the SSA
281
- * definition can be placed outside the loop).
282
- * - A volatile field is never interesting, since all reads must reread from
283
- * memory and we are forced to assume that the value can change at any point.
284
- */
285
- cached
286
- predicate trackField ( SsaSourceField f ) { multiAccessed ( f ) and not f .isVolatile ( ) }
272
+ private module NotCached1 {
273
+ /**
274
+ * Holds if `f` is a field that is interesting as a basis for SSA.
275
+ *
276
+ * - A field that is read twice is interesting as we want to know whether the
277
+ * reads refer to the same value.
278
+ * - A field that is both written and read is interesting as we want to know
279
+ * whether the read might get the written value.
280
+ * - A field that is read in a loop is interesting as we want to know whether
281
+ * the value is the same in different iterations (that is, whether the SSA
282
+ * definition can be placed outside the loop).
283
+ * - A volatile field is never interesting, since all reads must reread from
284
+ * memory and we are forced to assume that the value can change at any point.
285
+ */
286
+ pragma [ nomagic]
287
+ predicate trackField ( SsaSourceField f ) { multiAccessed ( f ) and not f .isVolatile ( ) }
288
+
289
+ /** Holds if `n` must update the locally tracked variable `v`. */
290
+ pragma [ nomagic]
291
+ predicate certainVariableUpdate ( TrackedVar v , ControlFlowNode n , BasicBlock b , int i ) {
292
+ exists ( VariableUpdate a | a = n | getDestVar ( a ) = v ) and
293
+ b .getNode ( i ) = n and
294
+ hasDominanceInformation ( b )
295
+ or
296
+ certainVariableUpdate ( v .getQualifier ( ) , n , b , i )
297
+ }
298
+ }
287
299
288
- /** Holds if `n` must update the locally tracked variable `v`. */
289
300
cached
290
- predicate certainVariableUpdate ( TrackedVar v , ControlFlowNode n , BasicBlock b , int i ) {
291
- exists ( VariableUpdate a | a = n | getDestVar ( a ) = v ) and
292
- b . getNode ( i ) = n and
293
- hasDominanceInformation ( b )
294
- or
295
- certainVariableUpdate ( v . getQualifier ( ) , n , b , i )
301
+ predicate ssaExplicitUpdate ( SsaUpdate def , VariableUpdate upd ) {
302
+ exists ( SsaSourceVariable v , BasicBlock bb , int i |
303
+ def . definesAt ( v , bb , i ) and
304
+ certainVariableUpdate ( v , upd , bb , i ) and
305
+ getDestVar ( upd ) = def . getSourceVariable ( )
306
+ )
296
307
}
297
308
298
309
/*
@@ -333,8 +344,8 @@ private module Cached {
333
344
/**
334
345
* Holds if `fw` is an update of `f` in `c` that is relevant for SSA construction.
335
346
*/
336
- cached
337
- predicate relevantFieldUpdate ( Callable c , Field f , FieldWrite fw ) {
347
+ pragma [ nomagic ]
348
+ private predicate relevantFieldUpdate ( Callable c , Field f , FieldWrite fw ) {
338
349
fw = f .getAnAccess ( ) and
339
350
not init ( fw ) and
340
351
fw .getEnclosingCallable ( ) = c and
@@ -483,34 +494,66 @@ private module Cached {
483
494
* `FieldRead` of `f` is reachable from `call`.
484
495
*/
485
496
pragma [ noopt]
486
- cached
487
- predicate updatesNamedField ( Call call , TrackedField f , Callable setter ) {
497
+ private predicate updatesNamedField ( Call call , TrackedField f , Callable setter ) {
488
498
exists ( TCallableNode src , TCallableNode sink , Field field |
489
499
source ( call , f , field , src ) and
490
500
sink ( setter , field , sink ) and
491
501
( src = sink or edgePlus ( src , sink ) )
492
502
)
493
503
}
494
504
495
- /** Holds if `n` might update the locally tracked variable `v`. */
505
+ /**
506
+ * Gets a reachable `FieldWrite` that might represent this ssa update, if any.
507
+ */
496
508
cached
497
- predicate uncertainVariableUpdate ( TrackedVar v , ControlFlowNode n , BasicBlock b , int i ) {
498
- exists ( Call c | c = n | updatesNamedField ( c , v , _) ) and
499
- b .getNode ( i ) = n and
500
- hasDominanceInformation ( b )
501
- or
502
- uncertainVariableUpdate ( v .getQualifier ( ) , n , b , i )
509
+ FieldWrite getANonLocalUpdate ( SsaImplicitUpdate def ) {
510
+ exists ( SsaSourceField f , Callable setter |
511
+ f = def .getSourceVariable ( ) and
512
+ relevantFieldUpdate ( setter , f .getField ( ) , result ) and
513
+ updatesNamedField ( def .getCfgNode ( ) , f , setter )
514
+ )
515
+ }
516
+
517
+ private module NotCached2 {
518
+ /** Holds if `n` might update the locally tracked variable `v`. */
519
+ pragma [ nomagic]
520
+ predicate uncertainVariableUpdate ( TrackedVar v , ControlFlowNode n , BasicBlock b , int i ) {
521
+ exists ( Call c | c = n | updatesNamedField ( c , v , _) ) and
522
+ b .getNode ( i ) = n and
523
+ hasDominanceInformation ( b )
524
+ or
525
+ uncertainVariableUpdate ( v .getQualifier ( ) , n , b , i )
526
+ }
503
527
}
504
528
505
- /** Holds if `v` has an implicit definition at the entry, `b`, of the callable. */
506
529
cached
507
- predicate hasEntryDef ( TrackedVar v , BasicBlock b ) {
508
- exists ( LocalScopeVariable l , Callable c | v = TLocalVar ( c , l ) and c .getBody ( ) = b |
509
- l instanceof Parameter or
510
- l .getCallable ( ) != c
530
+ predicate ssaUncertainImplicitUpdate ( SsaImplicitUpdate def ) {
531
+ exists ( SsaSourceVariable v , BasicBlock bb , int i |
532
+ def .definesAt ( v , bb , i ) and
533
+ uncertainVariableUpdate ( v , _, bb , i )
534
+ )
535
+ }
536
+
537
+ private module NotCached3 {
538
+ /** Holds if `v` has an implicit definition at the entry, `b`, of the callable. */
539
+ pragma [ nomagic]
540
+ predicate hasEntryDef ( TrackedVar v , BasicBlock b ) {
541
+ exists ( LocalScopeVariable l , Callable c | v = TLocalVar ( c , l ) and c .getBody ( ) = b |
542
+ l instanceof Parameter or
543
+ l .getCallable ( ) != c
544
+ )
545
+ or
546
+ v instanceof SsaSourceField and v .getEnclosingCallable ( ) .getBody ( ) = b
547
+ }
548
+ }
549
+
550
+ cached
551
+ predicate ssaImplicitInit ( WriteDefinition def ) {
552
+ exists ( SsaSourceVariable v , BasicBlock bb , int i |
553
+ def .definesAt ( v , bb , i ) and
554
+ hasEntryDef ( v , bb ) and
555
+ i = 0
511
556
)
512
- or
513
- v instanceof SsaSourceField and v .getEnclosingCallable ( ) .getBody ( ) = b
514
557
}
515
558
516
559
/** Holds if `init` is a closure variable that captures the value of `capturedvar`. */
@@ -636,9 +679,21 @@ private module Cached {
636
679
)
637
680
}
638
681
}
682
+
683
+ /**
684
+ * Provides internal implementation predicates that are not cached and should not
685
+ * be used outside of this file.
686
+ */
687
+ cached // needed to avoid compilation error; has no actual effect
688
+ module Internal {
689
+ import NotCached1
690
+ import NotCached2
691
+ import NotCached3
692
+ }
639
693
}
640
694
641
695
import Cached
696
+ private import Internal
642
697
643
698
/**
644
699
* An SSA definition excluding those variables that use a trivial SSA construction.
@@ -682,6 +737,10 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
682
737
)
683
738
}
684
739
740
+ predicate allowFlowIntoUncertainDef ( UncertainWriteDefinition def ) {
741
+ def instanceof SsaUncertainImplicitUpdate
742
+ }
743
+
685
744
class Guard extends Guards:: Guard {
686
745
predicate hasCfgNode ( BasicBlock bb , int i ) { this = bb .getNode ( i ) }
687
746
}
0 commit comments