mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
JS: Fix indentation
Only formatting changes
This commit is contained in:
@@ -113,254 +113,253 @@ BasicBlock immediatePostDominator(BasicBlock bb) = idominance(exitBB/1, predBB/2
|
||||
import Public
|
||||
|
||||
module Public {
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
*
|
||||
* At the database level, a basic block is represented by its first control flow node.
|
||||
*/
|
||||
class BasicBlock extends @cfg_node, NodeInStmtContainer {
|
||||
cached
|
||||
BasicBlock() { Stages::BasicBlocks::ref() and startsBB(this) }
|
||||
|
||||
/** Gets a basic block succeeding this one. */
|
||||
BasicBlock getASuccessor() { succBB(this, result) }
|
||||
|
||||
/** Gets a basic block preceding this one. */
|
||||
BasicBlock getAPredecessor() { result.getASuccessor() = this }
|
||||
|
||||
/** Gets a node in this block. */
|
||||
ControlFlowNode getANode() { result = this.getNode(_) }
|
||||
|
||||
/** Gets the node at the given position in this block. */
|
||||
ControlFlowNode getNode(int pos) { bbIndex(this, result, pos) }
|
||||
|
||||
/** Gets the first node in this block. */
|
||||
ControlFlowNode getFirstNode() { result = this }
|
||||
|
||||
/** Gets the last node in this block. */
|
||||
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
|
||||
|
||||
/** Gets the length of this block. */
|
||||
int length() { result = bbLength(this) }
|
||||
|
||||
/** Holds if this basic block uses variable `v` in its `i`th node `u`. */
|
||||
predicate useAt(int i, Variable v, VarUse u) { useAt(this, i, v, u) }
|
||||
|
||||
/** Holds if this basic block defines variable `v` in its `i`th node `d`. */
|
||||
predicate defAt(int i, Variable v, VarDef d) { defAt(this, i, v, d) }
|
||||
|
||||
/**
|
||||
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
|
||||
* witnessing the liveness.
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
*
|
||||
* In other words, `u` is a use of `v` that is reachable from the
|
||||
* entry node of this basic block without going through a redefinition
|
||||
* of `v`. The use `u` may either be in this basic block, or in another
|
||||
* basic block reachable from this one.
|
||||
* At the database level, a basic block is represented by its first control flow node.
|
||||
*/
|
||||
predicate isLiveAtEntry(Variable v, VarUse u) {
|
||||
// restrict `u` to be reachable from this basic block
|
||||
u = this.getASuccessor*().getANode() and
|
||||
(
|
||||
// shortcut: if `v` is never defined, then it must be live
|
||||
this.isDefinedInSameContainer(v)
|
||||
implies
|
||||
// otherwise, do full liveness computation
|
||||
this.isLiveAtEntryImpl(v, u)
|
||||
)
|
||||
}
|
||||
class BasicBlock extends @cfg_node, NodeInStmtContainer {
|
||||
cached
|
||||
BasicBlock() { Stages::BasicBlocks::ref() and startsBB(this) }
|
||||
|
||||
/**
|
||||
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
|
||||
* witnessing the liveness, where `v` is defined at least once in the enclosing
|
||||
* function or script.
|
||||
*/
|
||||
private predicate isLiveAtEntryImpl(Variable v, VarUse u) {
|
||||
this.isLocallyLiveAtEntry(v, u)
|
||||
or
|
||||
this.isDefinedInSameContainer(v) and
|
||||
not this.defAt(_, v, _) and
|
||||
this.getASuccessor().isLiveAtEntryImpl(v, u)
|
||||
}
|
||||
/** Gets a basic block succeeding this one. */
|
||||
BasicBlock getASuccessor() { succBB(this, result) }
|
||||
|
||||
/**
|
||||
* Holds if `v` is defined at least once in the function or script to which
|
||||
* this basic block belongs.
|
||||
*/
|
||||
private predicate isDefinedInSameContainer(Variable v) {
|
||||
exists(VarDef def | def.getAVariable() = v and def.getContainer() = this.getContainer())
|
||||
}
|
||||
/** Gets a basic block preceding this one. */
|
||||
BasicBlock getAPredecessor() { result.getASuccessor() = this }
|
||||
|
||||
/**
|
||||
* Holds if `v` is a variable that is live at entry to this basic block.
|
||||
*
|
||||
* Note that this is equivalent to `bb.isLiveAtEntry(v, _)`, but may
|
||||
* be more efficient on large databases.
|
||||
*/
|
||||
predicate isLiveAtEntry(Variable v) {
|
||||
this.isLocallyLiveAtEntry(v, _)
|
||||
or
|
||||
not this.defAt(_, v, _) and this.getASuccessor().isLiveAtEntry(v)
|
||||
}
|
||||
/** Gets a node in this block. */
|
||||
ControlFlowNode getANode() { result = this.getNode(_) }
|
||||
|
||||
/**
|
||||
* Holds if local variable `v` is live at entry to this basic block and
|
||||
* `u` is a use of `v` witnessing the liveness.
|
||||
*/
|
||||
predicate localIsLiveAtEntry(LocalVariable v, VarUse u) {
|
||||
this.isLocallyLiveAtEntry(v, u)
|
||||
or
|
||||
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v, u)
|
||||
}
|
||||
/** Gets the node at the given position in this block. */
|
||||
ControlFlowNode getNode(int pos) { bbIndex(this, result, pos) }
|
||||
|
||||
/**
|
||||
* Holds if local variable `v` is live at entry to this basic block.
|
||||
*/
|
||||
predicate localIsLiveAtEntry(LocalVariable v) {
|
||||
this.isLocallyLiveAtEntry(v, _)
|
||||
or
|
||||
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v)
|
||||
}
|
||||
/** Gets the first node in this block. */
|
||||
ControlFlowNode getFirstNode() { result = this }
|
||||
|
||||
/**
|
||||
* Holds if `d` is a definition of `v` that is reachable from the beginning of
|
||||
* this basic block without going through a redefinition of `v`.
|
||||
*/
|
||||
predicate localMayBeOverwritten(LocalVariable v, VarDef d) {
|
||||
this.isLocallyOverwritten(v, d)
|
||||
or
|
||||
not this.defAt(_, v, _) and this.getASuccessor().localMayBeOverwritten(v, d)
|
||||
}
|
||||
/** Gets the last node in this block. */
|
||||
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
|
||||
|
||||
/**
|
||||
* Gets the next index after `i` in this basic block at which `v` is
|
||||
* defined or used, provided that `d` is a definition of `v` at index `i`.
|
||||
* If there are no further uses or definitions of `v` after `i`, the
|
||||
* result is the length of this basic block.
|
||||
*/
|
||||
private int nextDefOrUseAfter(PurelyLocalVariable v, int i, VarDef d) {
|
||||
this.defAt(i, v, d) and
|
||||
result =
|
||||
min(int j |
|
||||
(this.defAt(j, v, _) or this.useAt(j, v, _) or j = this.length()) and
|
||||
j > i
|
||||
/** Gets the length of this block. */
|
||||
int length() { result = bbLength(this) }
|
||||
|
||||
/** Holds if this basic block uses variable `v` in its `i`th node `u`. */
|
||||
predicate useAt(int i, Variable v, VarUse u) { useAt(this, i, v, u) }
|
||||
|
||||
/** Holds if this basic block defines variable `v` in its `i`th node `d`. */
|
||||
predicate defAt(int i, Variable v, VarDef d) { defAt(this, i, v, d) }
|
||||
|
||||
/**
|
||||
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
|
||||
* witnessing the liveness.
|
||||
*
|
||||
* In other words, `u` is a use of `v` that is reachable from the
|
||||
* entry node of this basic block without going through a redefinition
|
||||
* of `v`. The use `u` may either be in this basic block, or in another
|
||||
* basic block reachable from this one.
|
||||
*/
|
||||
predicate isLiveAtEntry(Variable v, VarUse u) {
|
||||
// restrict `u` to be reachable from this basic block
|
||||
u = this.getASuccessor*().getANode() and
|
||||
(
|
||||
// shortcut: if `v` is never defined, then it must be live
|
||||
this.isDefinedInSameContainer(v)
|
||||
implies
|
||||
// otherwise, do full liveness computation
|
||||
this.isLiveAtEntryImpl(v, u)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `d` defines variable `v` at the `i`th node of this basic block, and
|
||||
* the definition is live, that is, the variable may be read after this
|
||||
* definition and before a re-definition.
|
||||
*/
|
||||
predicate localLiveDefAt(PurelyLocalVariable v, int i, VarDef d) {
|
||||
exists(int j | j = this.nextDefOrUseAfter(v, i, d) |
|
||||
this.useAt(j, v, _)
|
||||
/**
|
||||
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
|
||||
* witnessing the liveness, where `v` is defined at least once in the enclosing
|
||||
* function or script.
|
||||
*/
|
||||
private predicate isLiveAtEntryImpl(Variable v, VarUse u) {
|
||||
this.isLocallyLiveAtEntry(v, u)
|
||||
or
|
||||
j = this.length() and this.getASuccessor().localIsLiveAtEntry(v)
|
||||
)
|
||||
this.isDefinedInSameContainer(v) and
|
||||
not this.defAt(_, v, _) and
|
||||
this.getASuccessor().isLiveAtEntryImpl(v, u)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is defined at least once in the function or script to which
|
||||
* this basic block belongs.
|
||||
*/
|
||||
private predicate isDefinedInSameContainer(Variable v) {
|
||||
exists(VarDef def | def.getAVariable() = v and def.getContainer() = this.getContainer())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is a variable that is live at entry to this basic block.
|
||||
*
|
||||
* Note that this is equivalent to `bb.isLiveAtEntry(v, _)`, but may
|
||||
* be more efficient on large databases.
|
||||
*/
|
||||
predicate isLiveAtEntry(Variable v) {
|
||||
this.isLocallyLiveAtEntry(v, _)
|
||||
or
|
||||
not this.defAt(_, v, _) and this.getASuccessor().isLiveAtEntry(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if local variable `v` is live at entry to this basic block and
|
||||
* `u` is a use of `v` witnessing the liveness.
|
||||
*/
|
||||
predicate localIsLiveAtEntry(LocalVariable v, VarUse u) {
|
||||
this.isLocallyLiveAtEntry(v, u)
|
||||
or
|
||||
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v, u)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if local variable `v` is live at entry to this basic block.
|
||||
*/
|
||||
predicate localIsLiveAtEntry(LocalVariable v) {
|
||||
this.isLocallyLiveAtEntry(v, _)
|
||||
or
|
||||
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `d` is a definition of `v` that is reachable from the beginning of
|
||||
* this basic block without going through a redefinition of `v`.
|
||||
*/
|
||||
predicate localMayBeOverwritten(LocalVariable v, VarDef d) {
|
||||
this.isLocallyOverwritten(v, d)
|
||||
or
|
||||
not this.defAt(_, v, _) and this.getASuccessor().localMayBeOverwritten(v, d)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next index after `i` in this basic block at which `v` is
|
||||
* defined or used, provided that `d` is a definition of `v` at index `i`.
|
||||
* If there are no further uses or definitions of `v` after `i`, the
|
||||
* result is the length of this basic block.
|
||||
*/
|
||||
private int nextDefOrUseAfter(PurelyLocalVariable v, int i, VarDef d) {
|
||||
this.defAt(i, v, d) and
|
||||
result =
|
||||
min(int j |
|
||||
(this.defAt(j, v, _) or this.useAt(j, v, _) or j = this.length()) and
|
||||
j > i
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `d` defines variable `v` at the `i`th node of this basic block, and
|
||||
* the definition is live, that is, the variable may be read after this
|
||||
* definition and before a re-definition.
|
||||
*/
|
||||
predicate localLiveDefAt(PurelyLocalVariable v, int i, VarDef d) {
|
||||
exists(int j | j = this.nextDefOrUseAfter(v, i, d) |
|
||||
this.useAt(j, v, _)
|
||||
or
|
||||
j = this.length() and this.getASuccessor().localIsLiveAtEntry(v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `u` is a use of `v` in this basic block, and there are
|
||||
* no definitions of `v` before it.
|
||||
*/
|
||||
private predicate isLocallyLiveAtEntry(Variable v, VarUse u) {
|
||||
exists(int n | this.useAt(n, v, u) | not exists(int m | m < n | this.defAt(m, v, _)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `d` is a definition of `v` in this basic block, and there are
|
||||
* no other definitions of `v` before it.
|
||||
*/
|
||||
private predicate isLocallyOverwritten(Variable v, VarDef d) {
|
||||
exists(int n | this.defAt(n, v, d) | not exists(int m | m < n | this.defAt(m, v, _)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the basic block that immediately dominates this basic block.
|
||||
*/
|
||||
ReachableBasicBlock getImmediateDominator() { result = immediateDominator(this) }
|
||||
|
||||
/**
|
||||
* Holds if this if a basic block whose last node is an exit node.
|
||||
*/
|
||||
predicate isExitBlock() { exitBB(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `u` is a use of `v` in this basic block, and there are
|
||||
* no definitions of `v` before it.
|
||||
* An unreachable basic block, that is, a basic block
|
||||
* whose first node is unreachable.
|
||||
*/
|
||||
private predicate isLocallyLiveAtEntry(Variable v, VarUse u) {
|
||||
exists(int n | this.useAt(n, v, u) | not exists(int m | m < n | this.defAt(m, v, _)))
|
||||
class UnreachableBlock extends BasicBlock {
|
||||
UnreachableBlock() { this.getFirstNode().isUnreachable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `d` is a definition of `v` in this basic block, and there are
|
||||
* no other definitions of `v` before it.
|
||||
* An entry basic block, that is, a basic block
|
||||
* whose first node is the entry node of a statement container.
|
||||
*/
|
||||
private predicate isLocallyOverwritten(Variable v, VarDef d) {
|
||||
exists(int n | this.defAt(n, v, d) | not exists(int m | m < n | this.defAt(m, v, _)))
|
||||
class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { entryBB(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the basic block that immediately dominates this basic block.
|
||||
* A basic block that is reachable from an entry basic block.
|
||||
*/
|
||||
ReachableBasicBlock getImmediateDominator() { result = immediateDominator(this) }
|
||||
class ReachableBasicBlock extends BasicBlock {
|
||||
ReachableBasicBlock() { reachableBB(this) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly dominates `bb`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate strictlyDominates(ReachableBasicBlock bb) { this = immediateDominator+(bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block dominates `bb`.
|
||||
*
|
||||
* This predicate is reflexive: each reachable basic block dominates itself.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate dominates(ReachableBasicBlock bb) { this = immediateDominator*(bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly post-dominates `bb`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate strictlyPostDominates(ReachableBasicBlock bb) { this = immediatePostDominator+(bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block post-dominates `bb`.
|
||||
*
|
||||
* This predicate is reflexive: each reachable basic block post-dominates itself.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate postDominates(ReachableBasicBlock bb) { this = immediatePostDominator*(bb) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this if a basic block whose last node is an exit node.
|
||||
* A reachable basic block with more than one predecessor.
|
||||
*/
|
||||
predicate isExitBlock() { exitBB(this) }
|
||||
}
|
||||
class ReachableJoinBlock extends ReachableBasicBlock {
|
||||
ReachableJoinBlock() { this.getFirstNode().isJoin() }
|
||||
|
||||
/**
|
||||
* An unreachable basic block, that is, a basic block
|
||||
* whose first node is unreachable.
|
||||
*/
|
||||
class UnreachableBlock extends BasicBlock {
|
||||
UnreachableBlock() { this.getFirstNode().isUnreachable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry basic block, that is, a basic block
|
||||
* whose first node is the entry node of a statement container.
|
||||
*/
|
||||
class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { entryBB(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A basic block that is reachable from an entry basic block.
|
||||
*/
|
||||
class ReachableBasicBlock extends BasicBlock {
|
||||
ReachableBasicBlock() { reachableBB(this) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly dominates `bb`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate strictlyDominates(ReachableBasicBlock bb) { this = immediateDominator+(bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block dominates `bb`.
|
||||
*
|
||||
* This predicate is reflexive: each reachable basic block dominates itself.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate dominates(ReachableBasicBlock bb) { this = immediateDominator*(bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly post-dominates `bb`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate strictlyPostDominates(ReachableBasicBlock bb) { this = immediatePostDominator+(bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block post-dominates `bb`.
|
||||
*
|
||||
* This predicate is reflexive: each reachable basic block post-dominates itself.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate postDominates(ReachableBasicBlock bb) { this = immediatePostDominator*(bb) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A reachable basic block with more than one predecessor.
|
||||
*/
|
||||
class ReachableJoinBlock extends ReachableBasicBlock {
|
||||
ReachableJoinBlock() { this.getFirstNode().isJoin() }
|
||||
|
||||
/**
|
||||
* Holds if this basic block belongs to the dominance frontier of `b`, that is
|
||||
* `b` dominates a predecessor of this block, but not this block itself.
|
||||
*
|
||||
* Algorithm from Cooper et al., "A Simple, Fast Dominance Algorithm" (Figure 5),
|
||||
* who in turn attribute it to Ferrante et al., "The program dependence graph and
|
||||
* its use in optimization".
|
||||
*/
|
||||
predicate inDominanceFrontierOf(ReachableBasicBlock b) {
|
||||
b = this.getAPredecessor() and not b = this.getImmediateDominator()
|
||||
or
|
||||
exists(ReachableBasicBlock prev | this.inDominanceFrontierOf(prev) |
|
||||
b = prev.getImmediateDominator() and
|
||||
not b = this.getImmediateDominator()
|
||||
)
|
||||
/**
|
||||
* Holds if this basic block belongs to the dominance frontier of `b`, that is
|
||||
* `b` dominates a predecessor of this block, but not this block itself.
|
||||
*
|
||||
* Algorithm from Cooper et al., "A Simple, Fast Dominance Algorithm" (Figure 5),
|
||||
* who in turn attribute it to Ferrante et al., "The program dependence graph and
|
||||
* its use in optimization".
|
||||
*/
|
||||
predicate inDominanceFrontierOf(ReachableBasicBlock b) {
|
||||
b = this.getAPredecessor() and not b = this.getImmediateDominator()
|
||||
or
|
||||
exists(ReachableBasicBlock prev | this.inDominanceFrontierOf(prev) |
|
||||
b = prev.getImmediateDominator() and
|
||||
not b = this.getImmediateDominator()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user