Skip to content

Commit 211b42d

Browse files
committed
JS: Move BasicBlocks.qll -> internal/BasicBlocksInternal.qll
1 parent 9e60042 commit 211b42d

2 files changed

Lines changed: 369 additions & 368 deletions

File tree

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

0 commit comments

Comments
 (0)