|
3 | 3 | * liveness information for local variables.
|
4 | 4 | */
|
5 | 5 |
|
6 |
| -import javascript |
7 |
| -private import internal.StmtContainers |
8 |
| -private import semmle.javascript.internal.CachedStages |
9 |
| - |
10 |
| -/** |
11 |
| - * Holds if `nd` starts a new basic block. |
12 |
| - */ |
13 |
| -private predicate startsBB(ControlFlowNode nd) { |
14 |
| - not exists(nd.getAPredecessor()) and exists(nd.getASuccessor()) |
15 |
| - or |
16 |
| - nd.isJoin() |
17 |
| - or |
18 |
| - nd.getAPredecessor().isBranch() |
19 |
| -} |
20 |
| - |
21 |
| -/** |
22 |
| - * Holds if the first node of basic block `succ` is a control flow |
23 |
| - * successor of the last node of basic block `bb`. |
24 |
| - */ |
25 |
| -private predicate succBB(BasicBlock bb, BasicBlock succ) { succ = bb.getLastNode().getASuccessor() } |
26 |
| - |
27 |
| -/** |
28 |
| - * Holds if the first node of basic block `bb` is a control flow |
29 |
| - * successor of the last node of basic block `pre`. |
30 |
| - */ |
31 |
| -private predicate predBB(BasicBlock bb, BasicBlock pre) { succBB(pre, bb) } |
32 |
| - |
33 |
| -/** Holds if `bb` is an entry basic block. */ |
34 |
| -private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof ControlFlowEntryNode } |
35 |
| - |
36 |
| -/** Holds if `bb` is an exit basic block. */ |
37 |
| -private predicate exitBB(BasicBlock bb) { bb.getLastNode() instanceof ControlFlowExitNode } |
38 |
| - |
39 |
| -cached |
40 |
| -private module Internal { |
41 |
| - /** |
42 |
| - * Holds if `succ` is a control flow successor of `nd` within the same basic block. |
43 |
| - */ |
44 |
| - private predicate intraBBSucc(ControlFlowNode nd, ControlFlowNode succ) { |
45 |
| - succ = nd.getASuccessor() and |
46 |
| - not succ instanceof BasicBlock |
47 |
| - } |
48 |
| - |
49 |
| - /** |
50 |
| - * Holds if `nd` is the `i`th node in basic block `bb`. |
51 |
| - * |
52 |
| - * In other words, `i` is the shortest distance from a node `bb` |
53 |
| - * that starts a basic block to `nd` along the `intraBBSucc` relation. |
54 |
| - */ |
55 |
| - cached |
56 |
| - predicate bbIndex(BasicBlock bb, ControlFlowNode nd, int i) = |
57 |
| - shortestDistances(startsBB/1, intraBBSucc/2)(bb, nd, i) |
58 |
| - |
59 |
| - cached |
60 |
| - int bbLength(BasicBlock bb) { result = strictcount(ControlFlowNode nd | bbIndex(bb, nd, _)) } |
61 |
| - |
62 |
| - cached |
63 |
| - predicate useAt(BasicBlock bb, int i, Variable v, VarUse u) { |
64 |
| - Stages::BasicBlocks::ref() and |
65 |
| - v = u.getVariable() and |
66 |
| - bbIndex(bb, u, i) |
67 |
| - } |
68 |
| - |
69 |
| - cached |
70 |
| - predicate defAt(BasicBlock bb, int i, Variable v, VarDef d) { |
71 |
| - exists(VarRef lhs | |
72 |
| - lhs = d.getTarget().(BindingPattern).getABindingVarRef() and |
73 |
| - v = lhs.getVariable() |
74 |
| - | |
75 |
| - lhs = d.getTarget() and |
76 |
| - bbIndex(bb, d, i) |
77 |
| - or |
78 |
| - exists(PropertyPattern pp | |
79 |
| - lhs = pp.getValuePattern() and |
80 |
| - bbIndex(bb, pp, i) |
81 |
| - ) |
82 |
| - or |
83 |
| - exists(ObjectPattern op | |
84 |
| - lhs = op.getRest() and |
85 |
| - bbIndex(bb, lhs, i) |
86 |
| - ) |
87 |
| - or |
88 |
| - exists(ArrayPattern ap | |
89 |
| - lhs = ap.getAnElement() and |
90 |
| - bbIndex(bb, lhs, i) |
91 |
| - ) |
92 |
| - ) |
93 |
| - } |
94 |
| - |
95 |
| - cached |
96 |
| - predicate reachableBB(BasicBlock bb) { |
97 |
| - entryBB(bb) |
98 |
| - or |
99 |
| - exists(BasicBlock predBB | succBB(predBB, bb) | reachableBB(predBB)) |
100 |
| - } |
101 |
| -} |
102 |
| - |
103 |
| -private import Internal |
104 |
| - |
105 |
| -/** Holds if `dom` is an immediate dominator of `bb`. */ |
106 |
| -cached |
107 |
| -private predicate bbIDominates(BasicBlock dom, BasicBlock bb) = |
108 |
| - idominance(entryBB/1, succBB/2)(_, dom, bb) |
109 |
| - |
110 |
| -/** Holds if `dom` is an immediate post-dominator of `bb`. */ |
111 |
| -cached |
112 |
| -private predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) = |
113 |
| - idominance(exitBB/1, predBB/2)(_, dom, bb) |
114 |
| - |
115 |
| -/** |
116 |
| - * A basic block, that is, a maximal straight-line sequence of control flow nodes |
117 |
| - * without branches or joins. |
118 |
| - * |
119 |
| - * At the database level, a basic block is represented by its first control flow node. |
120 |
| - */ |
121 |
| -class BasicBlock extends @cfg_node, NodeInStmtContainer { |
122 |
| - cached |
123 |
| - BasicBlock() { Stages::BasicBlocks::ref() and startsBB(this) } |
124 |
| - |
125 |
| - /** Gets a basic block succeeding this one. */ |
126 |
| - BasicBlock getASuccessor() { succBB(this, result) } |
127 |
| - |
128 |
| - /** Gets a basic block preceding this one. */ |
129 |
| - BasicBlock getAPredecessor() { result.getASuccessor() = this } |
130 |
| - |
131 |
| - /** Gets a node in this block. */ |
132 |
| - ControlFlowNode getANode() { result = this.getNode(_) } |
133 |
| - |
134 |
| - /** Gets the node at the given position in this block. */ |
135 |
| - ControlFlowNode getNode(int pos) { bbIndex(this, result, pos) } |
136 |
| - |
137 |
| - /** Gets the first node in this block. */ |
138 |
| - ControlFlowNode getFirstNode() { result = this } |
139 |
| - |
140 |
| - /** Gets the last node in this block. */ |
141 |
| - ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) } |
142 |
| - |
143 |
| - /** Gets the length of this block. */ |
144 |
| - int length() { result = bbLength(this) } |
145 |
| - |
146 |
| - /** Holds if this basic block uses variable `v` in its `i`th node `u`. */ |
147 |
| - predicate useAt(int i, Variable v, VarUse u) { useAt(this, i, v, u) } |
148 |
| - |
149 |
| - /** Holds if this basic block defines variable `v` in its `i`th node `d`. */ |
150 |
| - predicate defAt(int i, Variable v, VarDef d) { defAt(this, i, v, d) } |
151 |
| - |
152 |
| - /** |
153 |
| - * Holds if `v` is live at entry to this basic block and `u` is a use of `v` |
154 |
| - * witnessing the liveness. |
155 |
| - * |
156 |
| - * In other words, `u` is a use of `v` that is reachable from the |
157 |
| - * entry node of this basic block without going through a redefinition |
158 |
| - * of `v`. The use `u` may either be in this basic block, or in another |
159 |
| - * basic block reachable from this one. |
160 |
| - */ |
161 |
| - predicate isLiveAtEntry(Variable v, VarUse u) { |
162 |
| - // restrict `u` to be reachable from this basic block |
163 |
| - u = this.getASuccessor*().getANode() and |
164 |
| - ( |
165 |
| - // shortcut: if `v` is never defined, then it must be live |
166 |
| - this.isDefinedInSameContainer(v) |
167 |
| - implies |
168 |
| - // otherwise, do full liveness computation |
169 |
| - this.isLiveAtEntryImpl(v, u) |
170 |
| - ) |
171 |
| - } |
172 |
| - |
173 |
| - /** |
174 |
| - * Holds if `v` is live at entry to this basic block and `u` is a use of `v` |
175 |
| - * witnessing the liveness, where `v` is defined at least once in the enclosing |
176 |
| - * function or script. |
177 |
| - */ |
178 |
| - private predicate isLiveAtEntryImpl(Variable v, VarUse u) { |
179 |
| - this.isLocallyLiveAtEntry(v, u) |
180 |
| - or |
181 |
| - this.isDefinedInSameContainer(v) and |
182 |
| - not this.defAt(_, v, _) and |
183 |
| - this.getASuccessor().isLiveAtEntryImpl(v, u) |
184 |
| - } |
185 |
| - |
186 |
| - /** |
187 |
| - * Holds if `v` is defined at least once in the function or script to which |
188 |
| - * this basic block belongs. |
189 |
| - */ |
190 |
| - private predicate isDefinedInSameContainer(Variable v) { |
191 |
| - exists(VarDef def | def.getAVariable() = v and def.getContainer() = this.getContainer()) |
192 |
| - } |
193 |
| - |
194 |
| - /** |
195 |
| - * Holds if `v` is a variable that is live at entry to this basic block. |
196 |
| - * |
197 |
| - * Note that this is equivalent to `bb.isLiveAtEntry(v, _)`, but may |
198 |
| - * be more efficient on large databases. |
199 |
| - */ |
200 |
| - predicate isLiveAtEntry(Variable v) { |
201 |
| - this.isLocallyLiveAtEntry(v, _) |
202 |
| - or |
203 |
| - not this.defAt(_, v, _) and this.getASuccessor().isLiveAtEntry(v) |
204 |
| - } |
205 |
| - |
206 |
| - /** |
207 |
| - * Holds if local variable `v` is live at entry to this basic block and |
208 |
| - * `u` is a use of `v` witnessing the liveness. |
209 |
| - */ |
210 |
| - predicate localIsLiveAtEntry(LocalVariable v, VarUse u) { |
211 |
| - this.isLocallyLiveAtEntry(v, u) |
212 |
| - or |
213 |
| - not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v, u) |
214 |
| - } |
215 |
| - |
216 |
| - /** |
217 |
| - * Holds if local variable `v` is live at entry to this basic block. |
218 |
| - */ |
219 |
| - predicate localIsLiveAtEntry(LocalVariable v) { |
220 |
| - this.isLocallyLiveAtEntry(v, _) |
221 |
| - or |
222 |
| - not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v) |
223 |
| - } |
224 |
| - |
225 |
| - /** |
226 |
| - * Holds if `d` is a definition of `v` that is reachable from the beginning of |
227 |
| - * this basic block without going through a redefinition of `v`. |
228 |
| - */ |
229 |
| - predicate localMayBeOverwritten(LocalVariable v, VarDef d) { |
230 |
| - this.isLocallyOverwritten(v, d) |
231 |
| - or |
232 |
| - not this.defAt(_, v, _) and this.getASuccessor().localMayBeOverwritten(v, d) |
233 |
| - } |
234 |
| - |
235 |
| - /** |
236 |
| - * Gets the next index after `i` in this basic block at which `v` is |
237 |
| - * defined or used, provided that `d` is a definition of `v` at index `i`. |
238 |
| - * If there are no further uses or definitions of `v` after `i`, the |
239 |
| - * result is the length of this basic block. |
240 |
| - */ |
241 |
| - private int nextDefOrUseAfter(PurelyLocalVariable v, int i, VarDef d) { |
242 |
| - this.defAt(i, v, d) and |
243 |
| - result = |
244 |
| - min(int j | |
245 |
| - (this.defAt(j, v, _) or this.useAt(j, v, _) or j = this.length()) and |
246 |
| - j > i |
247 |
| - ) |
248 |
| - } |
249 |
| - |
250 |
| - /** |
251 |
| - * Holds if `d` defines variable `v` at the `i`th node of this basic block, and |
252 |
| - * the definition is live, that is, the variable may be read after this |
253 |
| - * definition and before a re-definition. |
254 |
| - */ |
255 |
| - predicate localLiveDefAt(PurelyLocalVariable v, int i, VarDef d) { |
256 |
| - exists(int j | j = this.nextDefOrUseAfter(v, i, d) | |
257 |
| - this.useAt(j, v, _) |
258 |
| - or |
259 |
| - j = this.length() and this.getASuccessor().localIsLiveAtEntry(v) |
260 |
| - ) |
261 |
| - } |
262 |
| - |
263 |
| - /** |
264 |
| - * Holds if `u` is a use of `v` in this basic block, and there are |
265 |
| - * no definitions of `v` before it. |
266 |
| - */ |
267 |
| - private predicate isLocallyLiveAtEntry(Variable v, VarUse u) { |
268 |
| - exists(int n | this.useAt(n, v, u) | not exists(int m | m < n | this.defAt(m, v, _))) |
269 |
| - } |
270 |
| - |
271 |
| - /** |
272 |
| - * Holds if `d` is a definition of `v` in this basic block, and there are |
273 |
| - * no other definitions of `v` before it. |
274 |
| - */ |
275 |
| - private predicate isLocallyOverwritten(Variable v, VarDef d) { |
276 |
| - exists(int n | this.defAt(n, v, d) | not exists(int m | m < n | this.defAt(m, v, _))) |
277 |
| - } |
278 |
| - |
279 |
| - /** |
280 |
| - * Gets the basic block that immediately dominates this basic block. |
281 |
| - */ |
282 |
| - ReachableBasicBlock getImmediateDominator() { bbIDominates(result, this) } |
283 |
| -} |
284 |
| - |
285 |
| -/** |
286 |
| - * An unreachable basic block, that is, a basic block |
287 |
| - * whose first node is unreachable. |
288 |
| - */ |
289 |
| -class UnreachableBlock extends BasicBlock { |
290 |
| - UnreachableBlock() { this.getFirstNode().isUnreachable() } |
291 |
| -} |
292 |
| - |
293 |
| -/** |
294 |
| - * An entry basic block, that is, a basic block |
295 |
| - * whose first node is the entry node of a statement container. |
296 |
| - */ |
297 |
| -class EntryBasicBlock extends BasicBlock { |
298 |
| - EntryBasicBlock() { entryBB(this) } |
299 |
| -} |
300 |
| - |
301 |
| -/** |
302 |
| - * A basic block that is reachable from an entry basic block. |
303 |
| - */ |
304 |
| -class ReachableBasicBlock extends BasicBlock { |
305 |
| - ReachableBasicBlock() { reachableBB(this) } |
306 |
| - |
307 |
| - /** |
308 |
| - * Holds if this basic block strictly dominates `bb`. |
309 |
| - */ |
310 |
| - pragma[inline] |
311 |
| - predicate strictlyDominates(ReachableBasicBlock bb) { bbIDominates+(this, bb) } |
312 |
| - |
313 |
| - /** |
314 |
| - * Holds if this basic block dominates `bb`. |
315 |
| - * |
316 |
| - * This predicate is reflexive: each reachable basic block dominates itself. |
317 |
| - */ |
318 |
| - pragma[inline] |
319 |
| - predicate dominates(ReachableBasicBlock bb) { bbIDominates*(this, bb) } |
320 |
| - |
321 |
| - /** |
322 |
| - * Holds if this basic block strictly post-dominates `bb`. |
323 |
| - */ |
324 |
| - pragma[inline] |
325 |
| - predicate strictlyPostDominates(ReachableBasicBlock bb) { bbIPostDominates+(this, bb) } |
326 |
| - |
327 |
| - /** |
328 |
| - * Holds if this basic block post-dominates `bb`. |
329 |
| - * |
330 |
| - * This predicate is reflexive: each reachable basic block post-dominates itself. |
331 |
| - */ |
332 |
| - pragma[inline] |
333 |
| - predicate postDominates(ReachableBasicBlock bb) { bbIPostDominates*(this, bb) } |
334 |
| -} |
335 |
| - |
336 |
| -/** |
337 |
| - * A reachable basic block with more than one predecessor. |
338 |
| - */ |
339 |
| -class ReachableJoinBlock extends ReachableBasicBlock { |
340 |
| - ReachableJoinBlock() { this.getFirstNode().isJoin() } |
341 |
| - |
342 |
| - /** |
343 |
| - * Holds if this basic block belongs to the dominance frontier of `b`, that is |
344 |
| - * `b` dominates a predecessor of this block, but not this block itself. |
345 |
| - * |
346 |
| - * Algorithm from Cooper et al., "A Simple, Fast Dominance Algorithm" (Figure 5), |
347 |
| - * who in turn attribute it to Ferrante et al., "The program dependence graph and |
348 |
| - * its use in optimization". |
349 |
| - */ |
350 |
| - predicate inDominanceFrontierOf(ReachableBasicBlock b) { |
351 |
| - b = this.getAPredecessor() and not b = this.getImmediateDominator() |
352 |
| - or |
353 |
| - exists(ReachableBasicBlock prev | this.inDominanceFrontierOf(prev) | |
354 |
| - b = prev.getImmediateDominator() and |
355 |
| - not b = this.getImmediateDominator() |
356 |
| - ) |
357 |
| - } |
358 |
| -} |
| 6 | +import internal.BasicBlockInternal::Public |
0 commit comments