@@ -77,6 +77,23 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
7777
7878import Cached
7979private cached module Cached {
80+ // The base case of `reachable` is factored out for performance. If it's
81+ // written in-line in `reachable`, the compiler inserts a `n instanceof
82+ // ControlFlowNode` check because the `not ... and not ...` case doesn't
83+ // otherwise bind `n`. The problem is that this check is inserted at the
84+ // outermost level of this predicate, so it covers all cases including the
85+ // recursive case. The optimizer doesn't eliminate the check even though it's
86+ // redundant, and having the check leads to needless extra computation and a
87+ // risk of bad join orders.
88+ private predicate reachableBaseCase ( ControlFlowNode n ) {
89+ exists ( Function f | f .getEntryPoint ( ) = n )
90+ or
91+ // Okay to use successors_extended directly here
92+ ( not successors_extended ( _, n ) and not successors_extended ( n , _) )
93+ or
94+ n instanceof Handler
95+ }
96+
8097 /**
8198 * Holds if the control-flow node `n` is reachable, meaning that either
8299 * it is an entry point, or there exists a path in the control-flow
@@ -88,14 +105,9 @@ private cached module Cached {
88105 cached
89106 predicate reachable ( ControlFlowNode n )
90107 {
91- exists ( Function f | f .getEntryPoint ( ) = n )
92- or
93- // Okay to use successors_extended directly here
94- ( not successors_extended ( _, n ) and not successors_extended ( n , _) )
108+ reachableBaseCase ( n )
95109 or
96110 reachable ( n .getAPredecessor ( ) )
97- or
98- n instanceof Handler
99111 }
100112
101113 /** Holds if `condition` always evaluates to a nonzero value. */
0 commit comments