com.android.dx.ssa.Dominators Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder Show documentation
Show all versions of builder Show documentation
Library to build Android applications.
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.ssa;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
/**
* This class computes dominator and post-dominator information using the
* Lengauer-Tarjan method.
*
* See A Fast Algorithm for Finding Dominators in a Flowgraph
* T. Lengauer & R. Tarjan, ACM TOPLAS July 1979, pgs 121-141.
*
* This implementation runs in time O(n log n). The time bound
* could be changed to O(n * ack(n)) with a small change to the link and eval,
* and an addition of a child field to the DFS info. In reality, the constant
* overheads are high enough that the current method is faster in all but the
* strangest artificially constructed examples.
*
* The basic idea behind this algorithm is to perform a DFS walk, keeping track
* of various info about parents. We then use this info to calculate the
* dominators, using union-find structures to link together the DFS info,
* then finally evaluate the union-find results to get the dominators.
* This implementation is m log n because it does not perform union by
* rank to keep the union-find tree balanced.
*/
public final class Dominators {
/* postdom is true if we want post dominators */
private final boolean postdom;
/* {@code non-null;} method being processed */
private final SsaMethod meth;
/* Method's basic blocks. */
private final ArrayList blocks;
/** indexed by basic block index */
private final DFSInfo[] info;
private final ArrayList vertex;
/** {@code non-null;} the raw dominator info */
private final DomFront.DomInfo domInfos[];
/**
* Constructs an instance.
*
* @param meth {@code non-null;} method to process
* @param domInfos {@code non-null;} the raw dominator info
* @param postdom true for postdom information, false for normal dom info
*/
private Dominators(SsaMethod meth, DomFront.DomInfo[] domInfos,
boolean postdom) {
this.meth = meth;
this.domInfos = domInfos;
this.postdom = postdom;
this.blocks = meth.getBlocks();
this.info = new DFSInfo[blocks.size() + 2];
this.vertex = new ArrayList();
}
/**
* Constructs a fully-initialized instance. (This method exists so as
* to avoid calling a large amount of code in the constructor.)
*
* @param meth {@code non-null;} method to process
* @param domInfos {@code non-null;} the raw dominator info
* @param postdom true for postdom information, false for normal dom info
*/
public static Dominators make(SsaMethod meth, DomFront.DomInfo[] domInfos,
boolean postdom) {
Dominators result = new Dominators(meth, domInfos, postdom);
result.run();
return result;
}
private BitSet getSuccs(SsaBasicBlock block) {
if (postdom) {
return block.getPredecessors();
} else {
return block.getSuccessors();
}
}
private BitSet getPreds(SsaBasicBlock block) {
if (postdom) {
return block.getSuccessors();
} else {
return block.getPredecessors();
}
}
/**
* Performs path compress on the DFS info.
*
* @param in Basic block whose DFS info we are path compressing.
*/
private void compress(SsaBasicBlock in) {
DFSInfo bbInfo = info[in.getIndex()];
DFSInfo ancestorbbInfo = info[bbInfo.ancestor.getIndex()];
if (ancestorbbInfo.ancestor != null) {
ArrayList worklist = new ArrayList();
HashSet visited = new HashSet();
worklist.add(in);
while (!worklist.isEmpty()) {
int wsize = worklist.size();
SsaBasicBlock v = worklist.get(wsize - 1);
DFSInfo vbbInfo = info[v.getIndex()];
SsaBasicBlock vAncestor = vbbInfo.ancestor;
DFSInfo vabbInfo = info[vAncestor.getIndex()];
// Make sure we process our ancestor before ourselves.
if (visited.add(vAncestor) && vabbInfo.ancestor != null) {
worklist.add(vAncestor);
continue;
}
worklist.remove(wsize - 1);
// Update based on ancestor info.
if (vabbInfo.ancestor == null) {
continue;
}
SsaBasicBlock vAncestorRep = vabbInfo.rep;
SsaBasicBlock vRep = vbbInfo.rep;
if (info[vAncestorRep.getIndex()].semidom
< info[vRep.getIndex()].semidom) {
vbbInfo.rep = vAncestorRep;
}
vbbInfo.ancestor = vabbInfo.ancestor;
}
}
}
private SsaBasicBlock eval(SsaBasicBlock v) {
DFSInfo bbInfo = info[v.getIndex()];
if (bbInfo.ancestor == null) {
return v;
}
compress(v);
return bbInfo.rep;
}
/**
* Performs dominator/post-dominator calculation for the control
* flow graph.
*/
private void run() {
SsaBasicBlock root = postdom
? meth.getExitBlock() : meth.getEntryBlock();
if (root != null) {
vertex.add(root);
domInfos[root.getIndex()].idom = root.getIndex();
}
/*
* First we perform a DFS numbering of the blocks, by
* numbering the dfs tree roots.
*/
DfsWalker walker = new DfsWalker();
meth.forEachBlockDepthFirst(postdom, walker);
// the largest semidom number assigned
int dfsMax = vertex.size() - 1;
// Now calculate semidominators.
for (int i = dfsMax; i >= 2; --i) {
SsaBasicBlock w = vertex.get(i);
DFSInfo wInfo = info[w.getIndex()];
BitSet preds = getPreds(w);
for (int j = preds.nextSetBit(0);
j >= 0;
j = preds.nextSetBit(j + 1)) {
SsaBasicBlock predBlock = blocks.get(j);
DFSInfo predInfo = info[predBlock.getIndex()];
/*
* PredInfo may not exist in case the predecessor is
* not reachable.
*/
if (predInfo != null) {
int predSemidom = info[eval(predBlock).getIndex()].semidom;
if (predSemidom < wInfo.semidom) {
wInfo.semidom = predSemidom;
}
}
}
info[vertex.get(wInfo.semidom).getIndex()].bucket.add(w);
/*
* Normally we would call link here, but in our O(m log n)
* implementation this is equivalent to the following
* single line.
*/
wInfo.ancestor = wInfo.parent;
// Implicity define idom for each vertex.
ArrayList wParentBucket;
wParentBucket = info[wInfo.parent.getIndex()].bucket;
while (!wParentBucket.isEmpty()) {
int lastItem = wParentBucket.size() - 1;
SsaBasicBlock last = wParentBucket.remove(lastItem);
SsaBasicBlock U = eval(last);
if (info[U.getIndex()].semidom
< info[last.getIndex()].semidom) {
domInfos[last.getIndex()].idom = U.getIndex();
} else {
domInfos[last.getIndex()].idom = wInfo.parent.getIndex();
}
}
}
// Now explicitly define the immediate dominator of each vertex
for (int i = 2; i <= dfsMax; ++i) {
SsaBasicBlock w = vertex.get(i);
if (domInfos[w.getIndex()].idom
!= vertex.get(info[w.getIndex()].semidom).getIndex()) {
domInfos[w.getIndex()].idom
= domInfos[domInfos[w.getIndex()].idom].idom;
}
}
}
/**
* Callback for depth-first walk through control flow graph (either
* from the entry block or the exit block). Records the traversal order
* in the {@code info}list.
*/
private class DfsWalker implements SsaBasicBlock.Visitor {
private int dfsNum = 0;
public void visitBlock(SsaBasicBlock v, SsaBasicBlock parent) {
DFSInfo bbInfo = new DFSInfo();
bbInfo.semidom = ++dfsNum;
bbInfo.rep = v;
bbInfo.parent = parent;
vertex.add(v);
info[v.getIndex()] = bbInfo;
}
}
private static final class DFSInfo {
public int semidom;
public SsaBasicBlock parent;
/**
* rep(resentative) is known as "label" in the paper. It is the node
* that our block's DFS info has been unioned to.
*/
public SsaBasicBlock rep;
public SsaBasicBlock ancestor;
public ArrayList bucket;
public DFSInfo() {
bucket = new ArrayList();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy