@@ -269,30 +269,41 @@ private module Cached {
269269 result .getAnAccess ( ) = upd .( UnaryAssignExpr ) .getExpr ( )
270270 }
271271
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+ }
287299
288- /** Holds if `n` must update the locally tracked variable `v`. */
289300 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+ )
296307 }
297308
298309 /*
@@ -333,8 +344,8 @@ private module Cached {
333344 /**
334345 * Holds if `fw` is an update of `f` in `c` that is relevant for SSA construction.
335346 */
336- cached
337- predicate relevantFieldUpdate ( Callable c , Field f , FieldWrite fw ) {
347+ pragma [ nomagic ]
348+ private predicate relevantFieldUpdate ( Callable c , Field f , FieldWrite fw ) {
338349 fw = f .getAnAccess ( ) and
339350 not init ( fw ) and
340351 fw .getEnclosingCallable ( ) = c and
@@ -483,34 +494,66 @@ private module Cached {
483494 * `FieldRead` of `f` is reachable from `call`.
484495 */
485496 pragma [ noopt]
486- cached
487- predicate updatesNamedField ( Call call , TrackedField f , Callable setter ) {
497+ private predicate updatesNamedField ( Call call , TrackedField f , Callable setter ) {
488498 exists ( TCallableNode src , TCallableNode sink , Field field |
489499 source ( call , f , field , src ) and
490500 sink ( setter , field , sink ) and
491501 ( src = sink or edgePlus ( src , sink ) )
492502 )
493503 }
494504
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+ */
496508 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+ }
503527 }
504528
505- /** Holds if `v` has an implicit definition at the entry, `b`, of the callable. */
506529 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
511556 )
512- or
513- v instanceof SsaSourceField and v .getEnclosingCallable ( ) .getBody ( ) = b
514557 }
515558
516559 /** Holds if `init` is a closure variable that captures the value of `capturedvar`. */
@@ -636,9 +679,21 @@ private module Cached {
636679 )
637680 }
638681 }
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+ }
639693}
640694
641695import Cached
696+ private import Internal
642697
643698/**
644699 * An SSA definition excluding those variables that use a trivial SSA construction.
@@ -682,6 +737,10 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
682737 )
683738 }
684739
740+ predicate allowFlowIntoUncertainDef ( UncertainWriteDefinition def ) {
741+ def instanceof SsaUncertainImplicitUpdate
742+ }
743+
685744 class Guard extends Guards:: Guard {
686745 predicate hasCfgNode ( BasicBlock bb , int i ) { this = bb .getNode ( i ) }
687746 }
0 commit comments