1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later, 9 * or the Apache License Version 2.0. 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 */ 16 17 package javassist.bytecode.analysis; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 22 import javassist.CtClass; 23 import javassist.CtMethod; 24 import javassist.bytecode.BadBytecode; 25 import javassist.bytecode.MethodInfo; 26 import javassist.bytecode.stackmap.BasicBlock; 27 28 /** 29 * Represents the control flow graph of a given method. 30 * 31 * <p>To obtain the control flow graph, do the following:</p> 32 * 33 * <pre>CtMethod m = ... 34 * ControlFlow cf = new ControlFlow(m); 35 * Block[] blocks = cf.basicBlocks(); 36 * </pre> 37 * 38 * <p><code>blocks</code> is an array of basic blocks in 39 * that method body.</p> 40 * 41 * @see javassist.CtMethod 42 * @see Block 43 * @see Frame 44 * @see Analyzer 45 * @author Shigeru Chiba 46 * @since 3.16 47 */ 48 public class ControlFlow { 49 private CtClass clazz; 50 private MethodInfo methodInfo; 51 private Block[] basicBlocks; 52 private Frame[] frames; 53 54 /** 55 * Constructs a control-flow analyzer for the given method. 56 */ ControlFlow(CtMethod method)57 public ControlFlow(CtMethod method) throws BadBytecode { 58 this(method.getDeclaringClass(), method.getMethodInfo2()); 59 } 60 61 /** 62 * Constructs a control-flow analyzer. 63 */ ControlFlow(CtClass ctclazz, MethodInfo minfo)64 public ControlFlow(CtClass ctclazz, MethodInfo minfo) throws BadBytecode { 65 clazz = ctclazz; 66 methodInfo = minfo; 67 frames = null; 68 basicBlocks = (Block[])new BasicBlock.Maker() { 69 @Override 70 protected BasicBlock makeBlock(int pos) { 71 return new Block(pos, methodInfo); 72 } 73 @Override 74 protected BasicBlock[] makeArray(int size) { 75 return new Block[size]; 76 } 77 }.make(minfo); 78 if (basicBlocks == null) 79 basicBlocks = new Block[0]; 80 int size = basicBlocks.length; 81 int[] counters = new int[size]; 82 for (int i = 0; i < size; i++) { 83 Block b = basicBlocks[i]; 84 b.index = i; 85 b.entrances = new Block[b.incomings()]; 86 counters[i] = 0; 87 } 88 89 for (int i = 0; i < size; i++) { 90 Block b = basicBlocks[i]; 91 for (int k = 0; k < b.exits(); k++) { 92 Block e = b.exit(k); 93 e.entrances[counters[e.index]++] = b; 94 } 95 96 ControlFlow.Catcher[] catchers = b.catchers(); 97 for (int k = 0; k < catchers.length; k++) { 98 Block catchBlock = catchers[k].node; 99 catchBlock.entrances[counters[catchBlock.index]++] = b; 100 } 101 } 102 } 103 104 /** 105 * Returns all the basic blocks in the method body. 106 * 107 * @return an array of basic blocks, the array has length 0 if 108 * the method doesn't have code. 109 */ basicBlocks()110 public Block[] basicBlocks() { 111 return basicBlocks; 112 } 113 114 /** 115 * Returns the types of the local variables and stack frame entries 116 * available at the given position. If the byte at the position is 117 * not the first byte of an instruction, then this method returns 118 * null. 119 * 120 * @param pos the position. 121 */ frameAt(int pos)122 public Frame frameAt(int pos) throws BadBytecode { 123 if (frames == null) 124 frames = new Analyzer().analyze(clazz, methodInfo); 125 126 return frames[pos]; 127 } 128 129 /** 130 * Constructs a dominator tree. This method returns an array of 131 * the tree nodes. The first element of the array is the root 132 * of the tree. 133 * 134 * <p> The order of the elements is the same as that 135 * of the elements in the <code>Block</code> array returned 136 * by the <code>basicBlocks</code> 137 * method. If a <code>Block</code> object is at the i-th position 138 * in the <code>Block</code> array, then 139 * the <code>Node</code> object referring to that 140 * <code>Block</code> object is at the i-th position in the 141 * array returned by this method. 142 * For every array element <code>node</code>, its index in the 143 * array is equivalent to <code>node.block().index()</code>. 144 * 145 * @return an array of the tree nodes, or null if the method doesn't have code. 146 * @see Node#block() 147 * @see Block#index() 148 */ dominatorTree()149 public Node[] dominatorTree() { 150 int size = basicBlocks.length; 151 if (size == 0) 152 return null; 153 154 Node[] nodes = new Node[size]; 155 boolean[] visited = new boolean[size]; 156 int[] distance = new int[size]; 157 for (int i = 0; i < size; i++) { 158 nodes[i] = new Node(basicBlocks[i]); 159 visited[i] = false; 160 } 161 162 Access access = new Access(nodes) { 163 @Override 164 BasicBlock[] exits(Node n) { return n.block.getExit(); } 165 @Override 166 BasicBlock[] entrances(Node n) { return n.block.entrances; } 167 }; 168 nodes[0].makeDepth1stTree(null, visited, 0, distance, access); 169 do { 170 for (int i = 0; i < size; i++) 171 visited[i] = false; 172 } while (nodes[0].makeDominatorTree(visited, distance, access)); 173 Node.setChildren(nodes); 174 return nodes; 175 } 176 177 /** 178 * Constructs a post dominator tree. This method returns an array of 179 * the tree nodes. Note that the tree has multiple roots. 180 * The parent of the root nodes is null. 181 * 182 * <p> The order of the elements is the same as that 183 * of the elements in the <code>Block</code> array returned 184 * by the <code>basicBlocks</code> 185 * method. If a <code>Block</code> object is at the i-th position 186 * in the <code>Block</code> array, then 187 * the <code>Node</code> object referring to that 188 * <code>Block</code> object is at the i-th position in the 189 * array returned by this method. 190 * For every array element <code>node</code>, its index in the 191 * array is equivalent to <code>node.block().index()</code>. 192 * 193 * @return an array of the tree nodes, or null if the method doesn't have code. 194 * @see Node#block() 195 * @see Block#index() 196 */ postDominatorTree()197 public Node[] postDominatorTree() { 198 int size = basicBlocks.length; 199 if (size == 0) 200 return null; 201 202 Node[] nodes = new Node[size]; 203 boolean[] visited = new boolean[size]; 204 int[] distance = new int[size]; 205 for (int i = 0; i < size; i++) { 206 nodes[i] = new Node(basicBlocks[i]); 207 visited[i] = false; 208 } 209 210 Access access = new Access(nodes) { 211 @Override 212 BasicBlock[] exits(Node n) { return n.block.entrances; } 213 @Override 214 BasicBlock[] entrances(Node n) { return n.block.getExit(); } 215 }; 216 217 int counter = 0; 218 for (int i = 0; i < size; i++) 219 if (nodes[i].block.exits() == 0) 220 counter = nodes[i].makeDepth1stTree(null, visited, counter, distance, access); 221 222 boolean changed; 223 do { 224 for (int i = 0; i < size; i++) 225 visited[i] = false; 226 227 changed = false; 228 for (int i = 0; i < size; i++) 229 if (nodes[i].block.exits() == 0) 230 if (nodes[i].makeDominatorTree(visited, distance, access)) 231 changed = true; 232 } while (changed); 233 234 Node.setChildren(nodes); 235 return nodes; 236 } 237 238 /** 239 * Basic block. 240 * It is a sequence of contiguous instructions that do not contain 241 * jump/branch instructions except the last one. 242 * Since Java6 or later does not allow <code>JSR</code>, 243 * we deal with <code>JSR</code> as a non-branch instruction. 244 */ 245 public static class Block extends BasicBlock { 246 /** 247 * A field that can be freely used for storing extra data. 248 * A client program of this control-flow analyzer can append 249 * an additional attribute to a <code>Block</code> object. 250 * The Javassist library never accesses this field. 251 */ 252 public Object clientData = null; 253 254 int index; 255 MethodInfo method; 256 Block[] entrances; 257 Block(int pos, MethodInfo minfo)258 Block(int pos, MethodInfo minfo) { 259 super(pos); 260 method = minfo; 261 } 262 263 @Override toString2(StringBuffer sbuf)264 protected void toString2(StringBuffer sbuf) { 265 super.toString2(sbuf); 266 sbuf.append(", incoming{"); 267 for (int i = 0; i < entrances.length; i++) 268 sbuf.append(entrances[i].position).append(", "); 269 270 sbuf.append("}"); 271 } 272 getExit()273 BasicBlock[] getExit() { return exit; } 274 275 /** 276 * Returns the position of this block in the array of 277 * basic blocks that the <code>basicBlocks</code> method 278 * returns. 279 * 280 * @see #basicBlocks() 281 */ index()282 public int index() { return index; } 283 284 /** 285 * Returns the position of the first instruction 286 * in this block. 287 */ position()288 public int position() { return position; } 289 290 /** 291 * Returns the length of this block. 292 */ length()293 public int length() { return length; } 294 295 /** 296 * Returns the number of the control paths entering this block. 297 */ incomings()298 public int incomings() { return incoming; } 299 300 /** 301 * Returns the block that the control may jump into this block from. 302 */ incoming(int n)303 public Block incoming(int n) { 304 return entrances[n]; 305 } 306 307 /** 308 * Return the number of the blocks that may be executed 309 * after this block. 310 */ exits()311 public int exits() { return exit == null ? 0 : exit.length; } 312 313 /** 314 * Returns the n-th block that may be executed after this 315 * block. 316 * 317 * @param n an index in the array of exit blocks. 318 */ exit(int n)319 public Block exit(int n) { return (Block)exit[n]; } 320 321 /** 322 * Returns catch clauses that will catch an exception thrown 323 * in this block. 324 */ catchers()325 public Catcher[] catchers() { 326 List<Catcher> catchers = new ArrayList<Catcher>(); 327 BasicBlock.Catch c = toCatch; 328 while (c != null) { 329 catchers.add(new Catcher(c)); 330 c = c.next; 331 } 332 333 return catchers.toArray(new Catcher[catchers.size()]); 334 } 335 } 336 337 static abstract class Access { 338 Node[] all; Access(Node[] nodes)339 Access(Node[] nodes) { all = nodes; } node(BasicBlock b)340 Node node(BasicBlock b) { return all[((Block)b).index]; } exits(Node n)341 abstract BasicBlock[] exits(Node n); entrances(Node n)342 abstract BasicBlock[] entrances(Node n); 343 } 344 345 /** 346 * A node of (post) dominator trees. 347 */ 348 public static class Node { 349 private Block block; 350 private Node parent; 351 private Node[] children; 352 Node(Block b)353 Node(Block b) { 354 block = b; 355 parent = null; 356 } 357 358 /** 359 * Returns a <code>String</code> representation. 360 */ 361 @Override toString()362 public String toString() { 363 StringBuffer sbuf = new StringBuffer(); 364 sbuf.append("Node[pos=").append(block().position()); 365 sbuf.append(", parent="); 366 sbuf.append(parent == null ? "*" : Integer.toString(parent.block().position())); 367 sbuf.append(", children{"); 368 for (int i = 0; i < children.length; i++) 369 sbuf.append(children[i].block().position()).append(", "); 370 371 sbuf.append("}]"); 372 return sbuf.toString(); 373 } 374 375 /** 376 * Returns the basic block indicated by this node. 377 */ block()378 public Block block() { return block; } 379 380 /** 381 * Returns the parent of this node. 382 */ parent()383 public Node parent() { return parent; } 384 385 /** 386 * Returns the number of the children of this node. 387 */ children()388 public int children() { return children.length; } 389 390 /** 391 * Returns the n-th child of this node. 392 * 393 * @param n an index in the array of children. 394 */ child(int n)395 public Node child(int n) { return children[n]; } 396 397 /* 398 * After executing this method, distance[] represents the post order of the tree nodes. 399 * It also represents distances from the root; a bigger number represents a shorter 400 * distance. parent is set to its parent in the depth first spanning tree. 401 */ makeDepth1stTree(Node caller, boolean[] visited, int counter, int[] distance, Access access)402 int makeDepth1stTree(Node caller, boolean[] visited, int counter, int[] distance, Access access) { 403 int index = block.index; 404 if (visited[index]) 405 return counter; 406 407 visited[index] = true; 408 parent = caller; 409 BasicBlock[] exits = access.exits(this); 410 if (exits != null) 411 for (int i = 0; i < exits.length; i++) { 412 Node n = access.node(exits[i]); 413 counter = n.makeDepth1stTree(this, visited, counter, distance, access); 414 } 415 416 distance[index] = counter++; 417 return counter; 418 } 419 makeDominatorTree(boolean[] visited, int[] distance, Access access)420 boolean makeDominatorTree(boolean[] visited, int[] distance, Access access) { 421 int index = block.index; 422 if (visited[index]) 423 return false; 424 425 visited[index] = true; 426 boolean changed = false; 427 BasicBlock[] exits = access.exits(this); 428 if (exits != null) 429 for (int i = 0; i < exits.length; i++) { 430 Node n = access.node(exits[i]); 431 if (n.makeDominatorTree(visited, distance, access)) 432 changed = true; 433 } 434 435 BasicBlock[] entrances = access.entrances(this); 436 if (entrances != null) 437 for (int i = 0; i < entrances.length; i++) { 438 if (parent != null) { 439 Node n = getAncestor(parent, access.node(entrances[i]), distance); 440 if (n != parent) { 441 parent = n; 442 changed = true; 443 } 444 } 445 } 446 447 return changed; 448 } 449 getAncestor(Node n1, Node n2, int[] distance)450 private static Node getAncestor(Node n1, Node n2, int[] distance) { 451 while (n1 != n2) { 452 if (distance[n1.block.index] < distance[n2.block.index]) 453 n1 = n1.parent; 454 else 455 n2 = n2.parent; 456 457 if (n1 == null || n2 == null) 458 return null; 459 } 460 461 return n1; 462 } 463 setChildren(Node[] all)464 private static void setChildren(Node[] all) { 465 int size = all.length; 466 int[] nchildren = new int[size]; 467 for (int i = 0; i < size; i++) 468 nchildren[i] = 0; 469 470 for (int i = 0; i < size; i++) { 471 Node p = all[i].parent; 472 if (p != null) 473 nchildren[p.block.index]++; 474 } 475 476 for (int i = 0; i < size; i++) 477 all[i].children = new Node[nchildren[i]]; 478 479 for (int i = 0; i < size; i++) 480 nchildren[i] = 0; 481 482 for (int i = 0; i < size; i++) { 483 Node n = all[i]; 484 Node p = n.parent; 485 if (p != null) 486 p.children[nchildren[p.block.index]++] = n; 487 } 488 } 489 } 490 491 /** 492 * Represents a catch clause. 493 */ 494 public static class Catcher { 495 private Block node; 496 private int typeIndex; 497 Catcher(BasicBlock.Catch c)498 Catcher(BasicBlock.Catch c) { 499 node = (Block)c.body; 500 typeIndex = c.typeIndex; 501 } 502 503 /** 504 * Returns the first block of the catch clause. 505 */ block()506 public Block block() { return node; } 507 508 /** 509 * Returns the name of the exception type that 510 * this catch clause catches. 511 */ type()512 public String type() { 513 if (typeIndex == 0) 514 return "java.lang.Throwable"; 515 else 516 return node.method.getConstPool().getClassInfo(typeIndex); 517 } 518 } 519 } 520