1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.ssa; 18 19 import java.util.ArrayList; 20 import java.util.BitSet; 21 import java.util.HashSet; 22 23 /** 24 * This class computes dominator and post-dominator information using the 25 * Lengauer-Tarjan method. 26 * 27 * See A Fast Algorithm for Finding Dominators in a Flowgraph 28 * T. Lengauer & R. Tarjan, ACM TOPLAS July 1979, pgs 121-141. 29 * 30 * This implementation runs in time O(n log n). The time bound 31 * could be changed to O(n * ack(n)) with a small change to the link and eval, 32 * and an addition of a child field to the DFS info. In reality, the constant 33 * overheads are high enough that the current method is faster in all but the 34 * strangest artificially constructed examples. 35 * 36 * The basic idea behind this algorithm is to perform a DFS walk, keeping track 37 * of various info about parents. We then use this info to calculate the 38 * dominators, using union-find structures to link together the DFS info, 39 * then finally evaluate the union-find results to get the dominators. 40 * This implementation is m log n because it does not perform union by 41 * rank to keep the union-find tree balanced. 42 */ 43 public final class Dominators { 44 /* postdom is true if we want post dominators */ 45 private final boolean postdom; 46 47 /* {@code non-null;} method being processed */ 48 private final SsaMethod meth; 49 50 /* Method's basic blocks. */ 51 private final ArrayList<SsaBasicBlock> blocks; 52 53 /** indexed by basic block index */ 54 private final DFSInfo[] info; 55 56 private final ArrayList<SsaBasicBlock> vertex; 57 58 /** {@code non-null;} the raw dominator info */ 59 private final DomFront.DomInfo domInfos[]; 60 61 /** 62 * Constructs an instance. 63 * 64 * @param meth {@code non-null;} method to process 65 * @param domInfos {@code non-null;} the raw dominator info 66 * @param postdom true for postdom information, false for normal dom info 67 */ Dominators(SsaMethod meth, DomFront.DomInfo[] domInfos, boolean postdom)68 private Dominators(SsaMethod meth, DomFront.DomInfo[] domInfos, 69 boolean postdom) { 70 this.meth = meth; 71 this.domInfos = domInfos; 72 this.postdom = postdom; 73 this.blocks = meth.getBlocks(); 74 this.info = new DFSInfo[blocks.size() + 2]; 75 this.vertex = new ArrayList<SsaBasicBlock>(); 76 } 77 78 /** 79 * Constructs a fully-initialized instance. (This method exists so as 80 * to avoid calling a large amount of code in the constructor.) 81 * 82 * @param meth {@code non-null;} method to process 83 * @param domInfos {@code non-null;} the raw dominator info 84 * @param postdom true for postdom information, false for normal dom info 85 */ make(SsaMethod meth, DomFront.DomInfo[] domInfos, boolean postdom)86 public static Dominators make(SsaMethod meth, DomFront.DomInfo[] domInfos, 87 boolean postdom) { 88 Dominators result = new Dominators(meth, domInfos, postdom); 89 90 result.run(); 91 return result; 92 } 93 getSuccs(SsaBasicBlock block)94 private BitSet getSuccs(SsaBasicBlock block) { 95 if (postdom) { 96 return block.getPredecessors(); 97 } else { 98 return block.getSuccessors(); 99 } 100 } 101 getPreds(SsaBasicBlock block)102 private BitSet getPreds(SsaBasicBlock block) { 103 if (postdom) { 104 return block.getSuccessors(); 105 } else { 106 return block.getPredecessors(); 107 } 108 } 109 110 /** 111 * Performs path compress on the DFS info. 112 * 113 * @param in Basic block whose DFS info we are path compressing. 114 */ compress(SsaBasicBlock in)115 private void compress(SsaBasicBlock in) { 116 DFSInfo bbInfo = info[in.getIndex()]; 117 DFSInfo ancestorbbInfo = info[bbInfo.ancestor.getIndex()]; 118 119 if (ancestorbbInfo.ancestor != null) { 120 ArrayList<SsaBasicBlock> worklist = new ArrayList<SsaBasicBlock>(); 121 HashSet<SsaBasicBlock> visited = new HashSet<SsaBasicBlock>(); 122 worklist.add(in); 123 124 while (!worklist.isEmpty()) { 125 int wsize = worklist.size(); 126 SsaBasicBlock v = worklist.get(wsize - 1); 127 DFSInfo vbbInfo = info[v.getIndex()]; 128 SsaBasicBlock vAncestor = vbbInfo.ancestor; 129 DFSInfo vabbInfo = info[vAncestor.getIndex()]; 130 131 // Make sure we process our ancestor before ourselves. 132 if (visited.add(vAncestor) && vabbInfo.ancestor != null) { 133 worklist.add(vAncestor); 134 continue; 135 } 136 worklist.remove(wsize - 1); 137 138 // Update based on ancestor info. 139 if (vabbInfo.ancestor == null) { 140 continue; 141 } 142 SsaBasicBlock vAncestorRep = vabbInfo.rep; 143 SsaBasicBlock vRep = vbbInfo.rep; 144 if (info[vAncestorRep.getIndex()].semidom 145 < info[vRep.getIndex()].semidom) { 146 vbbInfo.rep = vAncestorRep; 147 } 148 vbbInfo.ancestor = vabbInfo.ancestor; 149 } 150 } 151 } 152 eval(SsaBasicBlock v)153 private SsaBasicBlock eval(SsaBasicBlock v) { 154 DFSInfo bbInfo = info[v.getIndex()]; 155 156 if (bbInfo.ancestor == null) { 157 return v; 158 } 159 160 compress(v); 161 return bbInfo.rep; 162 } 163 164 /** 165 * Performs dominator/post-dominator calculation for the control 166 * flow graph. 167 * 168 * @param meth {@code non-null;} method to analyze 169 */ run()170 private void run() { 171 SsaBasicBlock root = postdom 172 ? meth.getExitBlock() : meth.getEntryBlock(); 173 174 if (root != null) { 175 vertex.add(root); 176 domInfos[root.getIndex()].idom = root.getIndex(); 177 } 178 179 /* 180 * First we perform a DFS numbering of the blocks, by 181 * numbering the dfs tree roots. 182 */ 183 184 DfsWalker walker = new DfsWalker(); 185 meth.forEachBlockDepthFirst(postdom, walker); 186 187 // the largest semidom number assigned 188 int dfsMax = vertex.size() - 1; 189 190 // Now calculate semidominators. 191 for (int i = dfsMax; i >= 2; --i) { 192 SsaBasicBlock w = vertex.get(i); 193 DFSInfo wInfo = info[w.getIndex()]; 194 195 BitSet preds = getPreds(w); 196 for (int j = preds.nextSetBit(0); 197 j >= 0; 198 j = preds.nextSetBit(j + 1)) { 199 SsaBasicBlock predBlock = blocks.get(j); 200 DFSInfo predInfo = info[predBlock.getIndex()]; 201 202 /* 203 * PredInfo may not exist in case the predecessor is 204 * not reachable. 205 */ 206 if (predInfo != null) { 207 int predSemidom = info[eval(predBlock).getIndex()].semidom; 208 if (predSemidom < wInfo.semidom) { 209 wInfo.semidom = predSemidom; 210 } 211 } 212 } 213 info[vertex.get(wInfo.semidom).getIndex()].bucket.add(w); 214 215 /* 216 * Normally we would call link here, but in our O(m log n) 217 * implementation this is equivalent to the following 218 * single line. 219 */ 220 wInfo.ancestor = wInfo.parent; 221 222 // Implicity define idom for each vertex. 223 ArrayList<SsaBasicBlock> wParentBucket; 224 wParentBucket = info[wInfo.parent.getIndex()].bucket; 225 226 while (!wParentBucket.isEmpty()) { 227 int lastItem = wParentBucket.size() - 1; 228 SsaBasicBlock last = wParentBucket.remove(lastItem); 229 SsaBasicBlock U = eval(last); 230 if (info[U.getIndex()].semidom 231 < info[last.getIndex()].semidom) { 232 domInfos[last.getIndex()].idom = U.getIndex(); 233 } else { 234 domInfos[last.getIndex()].idom = wInfo.parent.getIndex(); 235 } 236 } 237 } 238 239 // Now explicitly define the immediate dominator of each vertex 240 for (int i = 2; i <= dfsMax; ++i) { 241 SsaBasicBlock w = vertex.get(i); 242 if (domInfos[w.getIndex()].idom 243 != vertex.get(info[w.getIndex()].semidom).getIndex()) { 244 domInfos[w.getIndex()].idom 245 = domInfos[domInfos[w.getIndex()].idom].idom; 246 } 247 } 248 } 249 250 /** 251 * Callback for depth-first walk through control flow graph (either 252 * from the entry block or the exit block). Records the traversal order 253 * in the {@code info}list. 254 */ 255 private class DfsWalker implements SsaBasicBlock.Visitor { 256 private int dfsNum = 0; 257 visitBlock(SsaBasicBlock v, SsaBasicBlock parent)258 public void visitBlock(SsaBasicBlock v, SsaBasicBlock parent) { 259 DFSInfo bbInfo = new DFSInfo(); 260 bbInfo.semidom = ++dfsNum; 261 bbInfo.rep = v; 262 bbInfo.parent = parent; 263 vertex.add(v); 264 info[v.getIndex()] = bbInfo; 265 } 266 } 267 268 private static final class DFSInfo { 269 public int semidom; 270 public SsaBasicBlock parent; 271 272 /** 273 * rep(resentative) is known as "label" in the paper. It is the node 274 * that our block's DFS info has been unioned to. 275 */ 276 public SsaBasicBlock rep; 277 278 public SsaBasicBlock ancestor; 279 public ArrayList<SsaBasicBlock> bucket; 280 DFSInfo()281 public DFSInfo() { 282 bucket = new ArrayList<SsaBasicBlock>(); 283 } 284 } 285 } 286