You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ControlFlow.java 16KB

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