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 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  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. }
  84. }
  85. /**
  86. * Returns all the basic blocks in the method body.
  87. */
  88. public Block[] basicBlocks() {
  89. dominatorTree2();
  90. return basicBlocks;
  91. }
  92. /**
  93. * Returns the types of the local variables and stack frame entries
  94. * available at the given position. If the byte at the position is
  95. * not the first byte of an instruction, then this method returns
  96. * null.
  97. *
  98. * @param pos the position.
  99. */
  100. public Frame frameAt(int pos) throws BadBytecode {
  101. if (frames == null)
  102. frames = new Analyzer().analyze(clazz, methodInfo);
  103. return frames[pos];
  104. }
  105. /**
  106. * Constructs a dominator tree. This method returns an array of
  107. * the tree nodes. The first element of the array is the root
  108. * of the tree.
  109. *
  110. * <p> The order of the elements is the same as that
  111. * of the elements in the array returned by the <code>basicBlocks</code>
  112. * method.
  113. * For every array element <code>node</code>, its index in the
  114. * array is obtained by <code>node.block().index()</code>.
  115. *
  116. * @return an array of the tree nodes, or null if the method is abstract.
  117. * @see Node#block()
  118. * @see Block#index()
  119. */
  120. public Node[] dominatorTree() {
  121. int size = basicBlocks.length;
  122. if (size == 0)
  123. return null;
  124. Node[] nodes = new Node[size];
  125. boolean[] visited = new boolean[size];
  126. int[] distance = new int[size];
  127. for (int i = 0; i < size; i++) {
  128. nodes[i] = new Node(basicBlocks[i]);
  129. visited[i] = false;
  130. }
  131. Access access = new Access(nodes) {
  132. BasicBlock[] exits(Node n) { return n.block.getExit(); }
  133. BasicBlock[] entrances(Node n) { return n.block.entrances; }
  134. };
  135. nodes[0].makeDepth1stTree(null, visited, 0, distance, access);
  136. for (int i = 0; i < size; i++)
  137. visited[i] = false;
  138. while (nodes[0].makeDominatorTree(visited, distance, access))
  139. ;
  140. Node.setChildren(nodes);
  141. return nodes;
  142. }
  143. /**
  144. * Constructs a post dominator tree. This method returns an array of
  145. * the tree nodes. The parent of the root node is null.
  146. *
  147. * <p>For every array element <code>node</code>, its index in the
  148. * array is obtained by <code>node.block().index()</code>.
  149. *
  150. * @return an array of the tree nodes, or null if the method is abstract.
  151. * @see Node#block()
  152. * @see Block#index()
  153. */
  154. public Node[] postDominatorTree() {
  155. int size = basicBlocks.length;
  156. if (size == 0)
  157. return null;
  158. Node[] nodes = new Node[size];
  159. boolean[] visited = new boolean[size];
  160. int[] distance = new int[size];
  161. for (int i = 0; i < size; i++) {
  162. nodes[i] = new Node(basicBlocks[i]);
  163. visited[i] = false;
  164. }
  165. Access access = new Access(nodes) {
  166. BasicBlock[] exits(Node n) { return n.block.entrances; }
  167. BasicBlock[] entrances(Node n) { return n.block.getExit(); }
  168. };
  169. int counter = 0;
  170. for (int i = 0; i < size; i++)
  171. if (nodes[i].block.exits() == 0)
  172. counter = nodes[i].makeDepth1stTree(null, visited, counter, distance, access);
  173. for (int i = 0; i < size; i++)
  174. visited[i] = false;
  175. boolean changed;
  176. do {
  177. changed = false;
  178. for (int i = 0; i < size; i++)
  179. if (nodes[i].block.exits() == 0)
  180. if (nodes[i].makeDominatorTree(visited, distance, access))
  181. changed = true;
  182. } while (changed);
  183. Node.setChildren(nodes);
  184. return nodes;
  185. }
  186. private Block dominatorTree2() {
  187. int size = basicBlocks.length;
  188. if (size == 0)
  189. return null;
  190. if (basicBlocks[0].parent == null) {
  191. // a dominator tree has not been constructed.
  192. boolean[] visited = new boolean[size];
  193. int[] distance = new int[size];
  194. for (int i = 0; i < size; i++)
  195. visited[i] = false;
  196. basicBlocks[0].makeDepth1stTree(null, visited, 0, distance);
  197. for (int i = 0; i < size; i++)
  198. visited[i] = false;
  199. while (basicBlocks[0].makeDominatorTree(visited, distance))
  200. ;
  201. setChildren(size);
  202. }
  203. return basicBlocks[0];
  204. }
  205. private void setChildren(int size) {
  206. int[] nchildren = new int[size];
  207. for (int i = 0; i < size; i++)
  208. nchildren[i] = 0;
  209. for (int i = 0; i < size; i++) {
  210. Block p = basicBlocks[i].parent;
  211. if (p != null)
  212. nchildren[p.index]++;
  213. }
  214. for (int i = 0; i < size; i++)
  215. basicBlocks[i].children = new Block[nchildren[i]];
  216. for (int i = 0; i < size; i++)
  217. nchildren[i] = 0;
  218. for (int i = 0; i < size; i++) {
  219. Block b = basicBlocks[i];
  220. Block p = b.parent;
  221. if (p != null)
  222. p.children[nchildren[p.index]++] = b;
  223. }
  224. }
  225. /**
  226. * Basic block.
  227. * It is a sequence of contiguous instructions that do not contain
  228. * jump/branch instructions except the last one.
  229. * Since Java6 or later does not allow <code>JSR</code>,
  230. * we deal with <code>JSR</code> as a non-branch instruction.
  231. */
  232. public static class Block extends BasicBlock {
  233. /**
  234. * A field that can be freely used for storing extra data.
  235. * A client program of this control-flow analyzer can append
  236. * an additional attribute to a <code>Block</code> object.
  237. * The Javassist library never accesses this field.
  238. */
  239. public Object clientData = null;
  240. int index;
  241. MethodInfo method;
  242. Block[] entrances;
  243. Block parent; // for a dominator tree
  244. Block[] children; // for a dominator tree
  245. Block(int pos, MethodInfo minfo) {
  246. super(pos);
  247. parent = null;
  248. method = minfo;
  249. }
  250. protected void toString2(StringBuffer sbuf) {
  251. super.toString2(sbuf);
  252. sbuf.append(", incomping{");
  253. for (int i = 0; i < entrances.length; i++)
  254. sbuf.append(entrances[i].position).append(", ");
  255. sbuf.append("}");
  256. sbuf.append("{parent=");
  257. sbuf.append(parent == null ? "*" : parent.position());
  258. sbuf.append(", children{");
  259. for (int i = 0; i < children.length; i++)
  260. sbuf.append(children[i].position()).append(", ");
  261. sbuf.append("}}");
  262. }
  263. BasicBlock[] getExit() { return exit; }
  264. /**
  265. * Returns the position of this block in the array of
  266. * basic blocks that the <code>basicBlocks</code> method
  267. * returns.
  268. *
  269. * @see #basicBlocks()
  270. */
  271. public int index() { return index; }
  272. /**
  273. * Returns the position of the first instruction
  274. * in this block.
  275. */
  276. public int position() { return position; }
  277. /**
  278. * Returns the length of this block.
  279. * @return
  280. */
  281. public int length() { return length; }
  282. /**
  283. * Returns the number of the control paths entering this block.
  284. */
  285. public int incomings() { return incoming; }
  286. /**
  287. * Returns the blocks that the control may jump into this block from.
  288. */
  289. public Block incoming(int n) {
  290. return entrances[n];
  291. }
  292. /**
  293. * Return the number of the blocks that may be executed
  294. * after this block.
  295. */
  296. public int exits() { return exit == null ? 0 : exit.length; }
  297. /**
  298. * Returns the n-th block that may be executed after this
  299. * block.
  300. *
  301. * @param n an index in the array of exit blocks.
  302. */
  303. public Block exit(int n) { return (Block)exit[n]; }
  304. /**
  305. * Returns the parent of this block in the dominator
  306. * tree.
  307. */
  308. public Block parent() { return parent; }
  309. /**
  310. * Returns the number of the children of this block
  311. * in the dominator tree.
  312. */
  313. public int children() { return children.length; }
  314. /**
  315. * Returns the n-th child of this block in the
  316. * dominator tree.
  317. *
  318. * @param n an index in the array of children.
  319. */
  320. public Block child(int n) { return children[n]; }
  321. /**
  322. * Returns catch clauses that will catch an exception thrown
  323. * in this block.
  324. */
  325. public Catcher[] catchers() {
  326. ArrayList catchers = new ArrayList();
  327. BasicBlock.Catch c = toCatch;
  328. while (c != null) {
  329. catchers.add(new Catcher(c));
  330. c = c.next;
  331. }
  332. return (Catcher[])catchers.toArray(new Catcher[catchers.size()]);
  333. }
  334. /*
  335. * After executing this method, distance[] represents the post order of the tree nodes.
  336. * It also represents distances from the root; a bigger number represents a shorter
  337. * distance. parent is set to its parent in the depth first spanning tree.
  338. */
  339. int makeDepth1stTree(Block caller, boolean[] visited, int counter, int[] distance) {
  340. if (visited[index])
  341. return counter;
  342. visited[index] = true;
  343. parent = caller;
  344. if (exit == null) {
  345. distance[index] = counter++;
  346. return counter;
  347. }
  348. else
  349. for (int i = 0; i < exit.length; i++) {
  350. Block b = (Block)exit[i];
  351. counter = b.makeDepth1stTree(this, visited, counter, distance);
  352. }
  353. distance[index] = counter++;
  354. return counter;
  355. }
  356. boolean makeDominatorTree(boolean[] visited, int[] distance) {
  357. if (visited[index])
  358. return false;
  359. visited[index] = true;
  360. boolean changed = false;
  361. if (exit != null)
  362. for (int i = 0; i < exit.length; i++) {
  363. Block b = (Block)exit[i];
  364. if (b.makeDominatorTree(visited, distance))
  365. changed = true;
  366. }
  367. for (int i = 0; i < entrances.length; i++) {
  368. if (parent != null) {
  369. Block a = getAncestor(parent, entrances[i], distance);
  370. if (a != parent) {
  371. parent = a;
  372. changed = true;
  373. }
  374. }
  375. }
  376. return changed;
  377. }
  378. private Block getAncestor(Block b1, Block b2, int[] distance) {
  379. while (b1 != b2)
  380. if (distance[b1.index] < distance[b2.index])
  381. b1 = b1.parent;
  382. else
  383. b2 = b2.parent;
  384. return b1;
  385. }
  386. }
  387. static abstract class Access {
  388. Node[] all;
  389. Access(Node[] nodes) { all = nodes; }
  390. Node node(BasicBlock b) { return all[((Block)b).index]; }
  391. abstract BasicBlock[] exits(Node n);
  392. abstract BasicBlock[] entrances(Node n);
  393. }
  394. /**
  395. * A node of (post) dominator trees.
  396. */
  397. public static class Node {
  398. private Block block;
  399. private Node parent;
  400. private Node[] children;
  401. Node(Block b) {
  402. block = b;
  403. parent = null;
  404. }
  405. /**
  406. * Returns a <code>String</code> representation.
  407. */
  408. public String toString() {
  409. StringBuffer sbuf = new StringBuffer();
  410. sbuf.append("Node[pos=").append(block().position());
  411. sbuf.append(", parent=");
  412. sbuf.append(parent == null ? "*" : parent.block().position());
  413. sbuf.append(", children{");
  414. for (int i = 0; i < children.length; i++)
  415. sbuf.append(children[i].block().position()).append(", ");
  416. sbuf.append("}]");
  417. return sbuf.toString();
  418. }
  419. /**
  420. * Returns the basic block indicated by this node.
  421. */
  422. public Block block() { return block; }
  423. /**
  424. * Returns the parent of this node.
  425. */
  426. public Node parent() { return parent; }
  427. /**
  428. * Returns the number of the children of this node.
  429. */
  430. public int children() { return children.length; }
  431. /**
  432. * Returns the n-th child of this node.
  433. *
  434. * @param n an index in the array of children.
  435. */
  436. public Node child(int n) { return children[n]; }
  437. /*
  438. * After executing this method, distance[] represents the post order of the tree nodes.
  439. * It also represents distances from the root; a bigger number represents a shorter
  440. * distance. parent is set to its parent in the depth first spanning tree.
  441. */
  442. int makeDepth1stTree(Node caller, boolean[] visited, int counter, int[] distance, Access access) {
  443. int index = block.index;
  444. if (visited[index])
  445. return counter;
  446. visited[index] = true;
  447. parent = caller;
  448. BasicBlock[] exits = access.exits(this);
  449. if (exits != null)
  450. for (int i = 0; i < exits.length; i++) {
  451. Node n = access.node(exits[i]);
  452. counter = n.makeDepth1stTree(this, visited, counter, distance, access);
  453. }
  454. distance[index] = counter++;
  455. return counter;
  456. }
  457. boolean makeDominatorTree(boolean[] visited, int[] distance, Access access) {
  458. int index = block.index;
  459. if (visited[index])
  460. return false;
  461. visited[index] = true;
  462. boolean changed = false;
  463. BasicBlock[] exits = access.exits(this);
  464. if (exits != null)
  465. for (int i = 0; i < exits.length; i++) {
  466. Node n = access.node(exits[i]);
  467. if (n.makeDominatorTree(visited, distance, access))
  468. changed = true;
  469. }
  470. BasicBlock[] entrances = access.entrances(this);
  471. if (entrances != null)
  472. for (int i = 0; i < entrances.length; i++) {
  473. if (parent != null) {
  474. Node n = getAncestor(parent, access.node(entrances[i]), distance);
  475. if (n != parent) {
  476. parent = n;
  477. changed = true;
  478. }
  479. }
  480. }
  481. return changed;
  482. }
  483. private static Node getAncestor(Node n1, Node n2, int[] distance) {
  484. while (n1 != n2) {
  485. if (distance[n1.block.index] < distance[n2.block.index])
  486. n1 = n1.parent;
  487. else
  488. n2 = n2.parent;
  489. if (n1 == null || n2 == null)
  490. return null;
  491. }
  492. return n1;
  493. }
  494. private static void setChildren(Node[] all) {
  495. int size = all.length;
  496. int[] nchildren = new int[size];
  497. for (int i = 0; i < size; i++)
  498. nchildren[i] = 0;
  499. for (int i = 0; i < size; i++) {
  500. Node p = all[i].parent;
  501. if (p != null)
  502. nchildren[p.block.index]++;
  503. }
  504. for (int i = 0; i < size; i++)
  505. all[i].children = new Node[nchildren[i]];
  506. for (int i = 0; i < size; i++)
  507. nchildren[i] = 0;
  508. for (int i = 0; i < size; i++) {
  509. Node n = all[i];
  510. Node p = n.parent;
  511. if (p != null)
  512. p.children[nchildren[p.block.index]++] = n;
  513. }
  514. }
  515. }
  516. /**
  517. * Represents a catch clause.
  518. */
  519. public static class Catcher {
  520. private Block node;
  521. private int typeIndex;
  522. Catcher(BasicBlock.Catch c) {
  523. node = (Block)c.body;
  524. typeIndex = c.typeIndex;
  525. }
  526. /**
  527. * Returns the first block of the catch clause.
  528. */
  529. public Block block() { return node; }
  530. /**
  531. * Returns the name of the exception type that
  532. * this catch clause catches.
  533. */
  534. public String type() {
  535. if (typeIndex == 0)
  536. return "java.lang.Throwable";
  537. else
  538. return node.method.getConstPool().getClassInfo(typeIndex);
  539. }
  540. }
  541. }